Chatthistorik
Chatthistorikobjektet används för att underhålla en post med meddelanden i en chattsession. Den används för att lagra meddelanden från olika författare, till exempel användare, assistenter, verktyg eller systemet. Som den primära mekanismen för att skicka och ta emot meddelanden är chatthistorikobjektet viktigt för att upprätthålla kontext och kontinuitet i en konversation.
Skapa ett chatthistorikobjekt
Ett chatthistorikobjekt är en lista under huven, vilket gör det enkelt att skapa och lägga till meddelanden i.
using Microsoft.SemanticKernel.ChatCompletion;
// Create a chat history object
ChatHistory chatHistory = [];
chatHistory.AddSystemMessage("You are a helpful assistant.");
chatHistory.AddUserMessage("What's available to order?");
chatHistory.AddAssistantMessage("We have pizza, pasta, and salad available to order. What would you like to order?");
chatHistory.AddUserMessage("I'd like to have the first option, please.");
# Create a chat history object
chat_history = ChatHistory()
chat_history.add_system_message("You are a helpful assistant.")
chat_history.add_user_message("What's available to order?")
chat_history.add_assistant_message("We have pizza, pasta, and salad available to order. What would you like to order?")
chat_history.add_user_message("I'd like to have the first option, please.")
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
// Create a chat history object
ChatHistory chatHistory = new ChatHistory();
chatHistory.addSystemMessage("You are a helpful assistant.");
chatHistory.addUserMessage("What's available to order?");
chatHistory.addAssistantMessage("We have pizza, pasta, and salad available to order. What would you like to order?");
chatHistory.addUserMessage("I'd like to have the first option, please.");
Lägga till mer omfattande meddelanden i en chatthistorik
Det enklaste sättet att lägga till meddelanden i ett chatthistorikobjekt är att använda metoderna ovan. Du kan dock också lägga till meddelanden manuellt genom att skapa ett nytt ChatMessage
objekt. På så sätt kan du ange ytterligare information, till exempel namn och bildinnehåll.
using Microsoft.SemanticKernel.ChatCompletion;
// Add system message
chatHistory.Add(
new() {
Role = AuthorRole.System,
Content = "You are a helpful assistant"
}
);
// Add user message with an image
chatHistory.Add(
new() {
Role = AuthorRole.User,
AuthorName = "Laimonis Dumins",
Items = [
new TextContent { Text = "What available on this menu" },
new ImageContent { Uri = new Uri("https://example.com/menu.jpg") }
]
}
);
// Add assistant message
chatHistory.Add(
new() {
Role = AuthorRole.Assistant,
AuthorName = "Restaurant Assistant",
Content = "We have pizza, pasta, and salad available to order. What would you like to order?"
}
);
// Add additional message from a different user
chatHistory.Add(
new() {
Role = AuthorRole.User,
AuthorName = "Ema Vargova",
Content = "I'd like to have the first option, please."
}
);
from semantic_kernel.contents.chat_history import ChatHistory
from semantic_kernel.contents import ChatMessageContent, TextContent, ImageContent
from semantic_kernel.contents.utils.author_role import AuthorRole
# Add system message
chat_history.add_message(
ChatMessage(
role=AuthorRole.System,
content="You are a helpful assistant"
)
)
# Add user message with an image
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.USER,
name="Laimonis Dumins",
items=[
TextContent(text="What available on this menu"),
ImageContent(uri="https://example.com/menu.jpg")
]
)
)
# Add assistant message
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.ASSISTANT,
name="Restaurant Assistant",
content="We have pizza, pasta, and salad available to order. What would you like to order?"
)
)
# Add additional message from a different user
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.USER,
name="Ema Vargova",
content="I'd like to have the first option, please."
)
)
import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageImageContent;
import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageTextContent;
// Add system message
chatHistory.addSystemMessage(
"You are a helpful assistant"
);
// Add user message with an image
chatHistory.addUserMessage(
"What available on this menu"
);
chatHistory.addMessage(
ChatMessageImageContent.builder()
.withImageUrl("https://example.com/menu.jpg")
.build()
);
// Add assistant message
chatHistory.addAssistantMessage(
"We have pizza, pasta, and salad available to order. What would you like to order?"
);
// Add additional message from a different user
chatHistory.addUserMessage(
"I'd like to have the first option, please."
);
Simulera funktionsanrop
Förutom användar-, assistent- och systemroller kan du även lägga till meddelanden från verktygsrollen för att simulera funktionsanrop. Detta är användbart för att lära AI:n hur man använder plugin-program och för att ge ytterligare kontext till konversationen.
Om du till exempel vill mata in information om den aktuella användaren i chatthistoriken utan att användaren behöver ange informationen eller låta LLM slösa tid på att be om den, kan du använda verktygsrollen för att tillhandahålla informationen direkt.
Nedan visas ett exempel på hur vi kan ge assistenten användarallergier genom att simulera ett funktionsanrop till plugin-programmet User
.
Dricks
Simulerade funktionsanrop är särskilt användbara för att ge information om de aktuella användarna. Dagens LLM:er har tränats att vara särskilt känsliga för användarinformation. Även om du anger användarinformation i ett systemmeddelande kan LLM fortfarande välja att ignorera det. Om du anger det via ett användarmeddelande eller ett verktygsmeddelande är det mer troligt att LLM använder det.
// Add a simulated function call from the assistant
chatHistory.Add(
new() {
Role = AuthorRole.Assistant,
Items = [
new FunctionCallContent(
functionName: "get_user_allergies",
pluginName: "User",
id: "0001",
arguments: new () { {"username", "laimonisdumins"} }
),
new FunctionCallContent(
functionName: "get_user_allergies",
pluginName: "User",
id: "0002",
arguments: new () { {"username", "emavargova"} }
)
]
}
);
// Add a simulated function results from the tool role
chatHistory.Add(
new() {
Role = AuthorRole.Tool,
Items = [
new FunctionResultContent(
functionName: "get_user_allergies",
pluginName: "User",
id: "0001",
result: "{ \"allergies\": [\"peanuts\", \"gluten\"] }"
)
]
}
);
chatHistory.Add(
new() {
Role = AuthorRole.Tool,
Items = [
new FunctionResultContent(
functionName: "get_user_allergies",
pluginName: "User",
id: "0002",
result: "{ \"allergies\": [\"dairy\", \"soy\"] }"
)
]
}
);
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
# Add a simulated function call from the assistant
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.ASSISTANT,
items=[
FunctionCallContent(
name="get_user_allergies-User",
id="0001",
arguments=str({"username": "laimonisdumins"})
),
FunctionCallContent(
name="get_user_allergies-User",
id="0002",
arguments=str({"username": "emavargova"})
)
]
)
)
# Add a simulated function results from the tool role
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.TOOL,
items=[
FunctionResultContent(
name="get_user_allergies-User",
id="0001",
result="{ \"allergies\": [\"peanuts\", \"gluten\"] }"
)
]
)
)
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.TOOL,
items=[
FunctionResultContent(
name="get_user_allergies-User",
id="0002",
result="{ \"allergies\": [\"dairy\", \"gluten\"] }"
)
]
)
)
This functionality is not supported in the current version of Semantic Kernel for Java.
Viktigt!
När du simulerar verktygsresultat måste du alltid ange det id
funktionsanrop som resultatet motsvarar. Det här är viktigt för AI:n att förstå resultatets kontext. Vissa LLM:er, till exempel OpenAI, utlöser ett fel om de id
saknas eller om de id
inte motsvarar ett funktionsanrop.
Inspektera ett chatthistorikobjekt
När du skickar ett chatthistorikobjekt till en tjänst för att slutföra chatten med automatiskt funktionsanrop aktiverat, ändras chatthistorikobjektet så att det innehåller funktionsanrop och resultat. På så sätt kan du undvika att behöva lägga till dessa meddelanden manuellt i chatthistorikobjektet och du kan även inspektera chatthistorikobjektet för att se funktionsanrop och resultat.
Du måste dock fortfarande lägga till de sista meddelandena i chatthistorikobjektet. Nedan visas ett exempel på hur du kan inspektera chatthistorikobjektet för att se funktionsanrop och resultat.
using Microsoft.SemanticKernel.ChatCompletion;
ChatHistory chatHistory = [
new() {
Role = AuthorRole.User,
Content = "Please order me a pizza"
}
];
// Get the current length of the chat history object
int currentChatHistoryLength = chatHistory.Count;
// Get the chat message content
ChatMessageContent results = await chatCompletionService.GetChatMessageContentAsync(
chatHistory,
kernel: kernel
);
// Get the new messages added to the chat history object
for (int i = currentChatHistoryLength; i < chatHistory.Count; i++)
{
Console.WriteLine(chatHistory[i]);
}
// Print the final message
Console.WriteLine(results);
// Add the final message to the chat history object
chatHistory.Add(results);
from semantic_kernel.contents import ChatMessageContent
chat_history = ChatHistory([
ChatMessageContent(
role=AuthorRole.USER,
content="Please order me a pizza"
)
])
# Get the current length of the chat history object
current_chat_history_length = len(chat_history)
# Get the chat message content
results = await chat_completion.get_chat_message_content(
chat_history=history,
settings=execution_settings,
kernel=kernel,
)
# Get the new messages added to the chat history object
for i in range(current_chat_history_length, len(chat_history)):
print(chat_history[i])
# Print the final message
print(results)
# Add the final message to the chat history object
chat_history.add_message(results)
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
ChatHistory chatHistory = new ChatHistory();
chatHistory.addUserMessage("Please order me a pizza");
// Get the chat message content
List<ChatMessageContent> results = chatCompletionService.getChatMessageContentsAsync(
chatHistory,
kernel,
null
).block();
results.forEach(result -> System.out.println(result.getContent());
// Get the new messages added to the chat history object. By default,
// the ChatCompletionService returns new messages only.
chatHistory.addAll(results);
Minskning av chatthistorik
Att hantera chatthistorik är viktigt för att upprätthålla sammanhangsmedvetna konversationer samtidigt som du säkerställer effektiva prestanda. När en konversation fortskrider kan historikobjektet växa bortom gränserna för en modells kontextfönster, vilket påverkar svarskvaliteten och saktar ned bearbetningen. En strukturerad metod för att minska chatthistoriken säkerställer att den mest relevanta informationen förblir tillgänglig utan onödiga omkostnader.
Varför minska chatthistoriken?
- Prestandaoptimering: Stora chatthistoriker ökar bearbetningstiden. Att minska deras storlek hjälper till att upprätthålla snabba och effektiva interaktioner.
- Hantering av kontextfönster: Språkmodeller har ett fast kontextfönster. När historiken överskrider den här gränsen går äldre meddelanden förlorade. Genom att hantera chatthistoriken ser du till att den viktigaste kontexten förblir tillgänglig.
- Minneseffektivitet: I resursbegränsade miljöer, till exempel mobila program eller inbäddade system, kan obundna chatthistorik leda till överdriven minnesanvändning och långsamma prestanda.
- Sekretess och säkerhet: Om du behåller onödig konversationshistorik ökar risken för att känslig information exponeras. En strukturerad minskningsprocess minimerar datakvarhållningen samtidigt som relevant kontext bibehålls.
Strategier för att minska chatthistoriken
Flera metoder kan användas för att hålla chatthistoriken hanterbar samtidigt som viktig information bevaras:
- Trunkering: De äldsta meddelandena tas bort när historiken överskrider en fördefinierad gräns, vilket säkerställer att endast de senaste interaktionerna behålls.
- Sammanfattning: Äldre meddelanden komprimeras till en sammanfattning, vilket bevarar viktig information samtidigt som antalet lagrade meddelanden minskas.
- Tokenbaserad: Tokenbaserad minskning säkerställer att chatthistoriken ligger inom en modells tokengräns genom att mäta totalt antal token och ta bort eller sammanfatta äldre meddelanden när gränsen överskrids.
En reducer för chatthistorik automatiserar dessa strategier genom att utvärdera historikens storlek och minska den baserat på konfigurerbara parametrar som målantal (önskat antal meddelanden att behålla) och tröskelvärdesantal (den punkt då minskningen utlöses). Genom att integrera dessa minskningstekniker kan chattprogram förbli dynamiska och presterande utan att äventyra konversationskontexten.
I .NET-versionen av Semantic Kernel definieras chathistorikreduceringsabstraktionen av IChatHistoryReducer
-gränssnittet.
namespace Microsoft.SemanticKernel.ChatCompletion;
[Experimental("SKEXP0001")]
public interface IChatHistoryReducer
{
Task<IEnumerable<ChatMessageContent>?> ReduceAsync(IReadOnlyList<ChatMessageContent> chatHistory, CancellationToken cancellationToken = default);
}
Det här gränssnittet tillåter anpassade implementeringar för minskning av chatthistorik.
Semantisk kernel tillhandahåller dessutom inbyggda reducers:
-
ChatHistoryTruncationReducer
– trunkerar chatthistoriken till en angiven storlek och tar bort de borttagna meddelandena. Minskningen utlöses när chatthistorikens längd överskrider gränsen. -
ChatHistorySummarizationReducer
– trunkerar chatthistoriken, sammanfattar de borttagna meddelandena och lägger till sammanfattningen i chatthistoriken som ett enda meddelande.
Båda reducerarna bevarar alltid systemmeddelanden för att behålla den viktiga kontexten för modellen.
I följande exempel visas hur du endast behåller de två sista användarmeddelandena samtidigt som konversationsflödet bibehålls:
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
var chatService = new OpenAIChatCompletionService(
modelId: "<model-id>",
apiKey: "<api-key>");
var reducer = new ChatHistoryTruncationReducer(targetCount: 2); // Keep system message and last user message
var chatHistory = new ChatHistory("You are a librarian and expert on books about cities");
string[] userMessages = [
"Recommend a list of books about Seattle",
"Recommend a list of books about Dublin",
"Recommend a list of books about Amsterdam",
"Recommend a list of books about Paris",
"Recommend a list of books about London"
];
int totalTokenCount = 0;
foreach (var userMessage in userMessages)
{
chatHistory.AddUserMessage(userMessage);
Console.WriteLine($"\n>>> User:\n{userMessage}");
var reducedMessages = await reducer.ReduceAsync(chatHistory);
if (reducedMessages is not null)
{
chatHistory = new ChatHistory(reducedMessages);
}
var response = await chatService.GetChatMessageContentAsync(chatHistory);
chatHistory.AddAssistantMessage(response.Content!);
Console.WriteLine($"\n>>> Assistant:\n{response.Content!}");
if (response.InnerContent is OpenAI.Chat.ChatCompletion chatCompletion)
{
totalTokenCount += chatCompletion.Usage?.TotalTokenCount ?? 0;
}
}
Console.WriteLine($"Total Token Count: {totalTokenCount}");
I det här avsnittet går vi igenom implementeringsinformationen för minskning av chatthistorik i Python. Metoden innebär att skapa en ChatHistoryReducer som integreras sömlöst med ChatHistory-objektet, så att det kan användas och skickas där en chatthistorik krävs.
- Integrering: I Python är
ChatHistoryReducer
utformat för att vara en underklass tillChatHistory
-objektet. Med det här arvet kan reducern vara utbytbar med standardinstanser av chatthistorik. - Minskningslogik: Användare kan anropa metoden
reduce
i chatthistorikobjektet. Reducern utvärderar om det aktuella antalet meddelanden överskridertarget_count
plusthreshold_count
(om det anges). I så fall reduceras historiken tilltarget_count
antingen genom trunkering eller sammanfattning. - Konfiguration: Minskningsbeteendet kan konfigureras via parametrar som
target_count
(önskat antal meddelanden att behålla) och threshold_count (antalet meddelanden som utlöser minskningsprocessen).
De semantiska Kernel Python-historikreduceringarna som stöds är ChatHistorySummarizationReducer
och ChatHistoryTruncationReducer
. Som en del av reducerkonfigurationen kan auto_reduce
aktiveras för att automatiskt tillämpa historikminskning när den används med add_message_async
, vilket säkerställer att chatthistoriken ligger inom de konfigurerade gränserna.
I följande exempel visas hur du använder ChatHistoryTruncationReducer för att endast behålla de två sista meddelandena samtidigt som konversationsflödet bibehålls.
import asyncio
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatHistoryTruncationReducer
from semantic_kernel.kernel import Kernel
async def main():
kernel = Kernel()
kernel.add_service(AzureChatCompletion())
# Keep the last two messages
truncation_reducer = ChatHistoryTruncationReducer(
target_count=2,
)
truncation_reducer.add_system_message("You are a helpful chatbot.")
is_reduced = False
while True:
user_input = input("User:> ")
if user_input.lower() == "exit":
print("\n\nExiting chat...")
break
is_reduced = await truncation_reducer.reduce()
if is_reduced:
print(f"@ History reduced to {len(truncation_reducer.messages)} messages.")
response = await kernel.invoke_prompt(
prompt="{{$chat_history}}{{$user_input}}", user_input=user_input, chat_history=truncation_reducer
)
if response:
print(f"Assistant:> {response}")
truncation_reducer.add_user_message(str(user_input))
truncation_reducer.add_message(response.value[0])
if is_reduced:
for msg in truncation_reducer.messages:
print(f"{msg.role} - {msg.content}\n")
print("\n")
if __name__ == "__main__":
asyncio.run(main())
Minskning av chatthistorik är för närvarande inte tillgänglig i Java.
Nästa steg
Nu när du vet hur du skapar och hanterar ett chatthistorikobjekt kan du lära dig mer om funktionsanrop i avsnittet Funktionssamtal .