Historique des conversations
L’objet d’historique des conversations est utilisé pour conserver un enregistrement des messages dans une session de conversation. Il est utilisé pour stocker des messages provenant de différents auteurs, tels que les utilisateurs, les assistants, les outils ou le système. En tant que mécanisme principal pour l’envoi et la réception de messages, l’objet d’historique des conversations est essentiel pour maintenir le contexte et la continuité dans une conversation.
Création d’un objet d’historique de conversation
Un objet d’historique des conversations est une liste sous le capot, ce qui facilite la création et l’ajout de messages.
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.");
Ajout de messages plus riches à un historique de conversation
Le moyen le plus simple d’ajouter des messages à un objet d’historique de conversation consiste à utiliser les méthodes ci-dessus. Toutefois, vous pouvez également ajouter manuellement des messages en créant un ChatMessage
objet. Cela vous permet de fournir des informations supplémentaires, telles que des noms et du contenu d’images.
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."
);
Simulation d’appels de fonction
Outre les rôles utilisateur, Assistant et système, vous pouvez également ajouter des messages à partir du rôle outil pour simuler des appels de fonction. Cela est utile pour enseigner à l’IA comment utiliser des plug-ins et fournir un contexte supplémentaire à la conversation.
Par exemple, pour injecter des informations sur l’utilisateur actuel dans l’historique des conversations sans demander à l’utilisateur de fournir les informations ou de perdre du temps pour lui demander, vous pouvez utiliser le rôle d’outil pour fournir les informations directement.
Voici un exemple de la façon dont nous sommes en mesure de fournir des allergies utilisateur à l’assistant en simulant un appel de fonction au User
plug-in.
Conseil
Les appels de fonction simulés sont particulièrement utiles pour fournir des détails sur le ou les utilisateurs actuels. Les llMs d’aujourd’hui ont été formés pour être particulièrement sensibles aux informations utilisateur. Même si vous fournissez des détails utilisateur dans un message système, le LLM peut toujours choisir de l’ignorer. Si vous le fournissez via un message utilisateur ou un message d’outil, le LLM est plus susceptible de l’utiliser.
// 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.
Important
Lors de la simulation des résultats de l’outil, vous devez toujours fournir l’appel id
de fonction auquel correspond le résultat. Il est important pour l’IA de comprendre le contexte du résultat. Certaines machines virtuelles LL, comme OpenAI, lèvent une erreur si la id
valeur est manquante ou si celle-ci id
ne correspond pas à un appel de fonction.
Inspection d’un objet d’historique de conversation
Chaque fois que vous passez un objet d’historique de conversation à un service d’achèvement de conversation avec l’appel automatique de fonction activé, l’objet d’historique des conversations est manipulé afin qu’il inclut les appels de fonction et les résultats. Cela vous permet d’éviter d’avoir à ajouter manuellement ces messages à l’objet d’historique des conversations et vous permet également d’inspecter l’objet d’historique des conversations pour voir les appels de fonction et les résultats.
Toutefois, vous devez toujours ajouter les messages finaux à l’objet d’historique des conversations. Vous trouverez ci-dessous un exemple de la façon dont vous pouvez inspecter l’objet d’historique des conversations pour afficher les appels de fonction et les résultats.
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);
Réduction de l’historique des conversations
La gestion de l’historique des conversations est essentielle pour maintenir des conversations prenant en charge le contexte tout en garantissant des performances efficaces. À mesure qu’une conversation progresse, l’objet d’historique peut dépasser les limites de la fenêtre de contexte d’un modèle, ce qui affecte la qualité de la réponse et le ralentissement du traitement. Une approche structurée pour réduire l’historique des conversations garantit que les informations les plus pertinentes restent disponibles sans surcharge inutile.
Pourquoi réduire l’historique des conversations ?
- Optimisation des performances : les historiques de conversation volumineux augmentent le temps de traitement. La réduction de leur taille permet de maintenir des interactions rapides et efficaces.
- Gestion des fenêtres de contexte : les modèles de langage ont une fenêtre contextuelle fixe. Lorsque l’historique dépasse cette limite, les messages plus anciens sont perdus. La gestion de l’historique des conversations garantit que le contexte le plus important reste accessible.
- Efficacité de la mémoire : dans les environnements à contrainte de ressources tels que les applications mobiles ou les systèmes incorporés, l’historique des conversations sans limite peut entraîner une utilisation excessive de la mémoire et des performances lentes.
- Confidentialité et sécurité : la conservation de l’historique des conversations inutiles augmente le risque d’exposer des informations sensibles. Un processus de réduction structurée réduit la conservation des données tout en conservant le contexte approprié.
Stratégies de réduction de l’historique des conversations
Plusieurs approches peuvent être utilisées pour maintenir l’historique des conversations gérable tout en préservant les informations essentielles :
- Troncation : les messages les plus anciens sont supprimés lorsque l’historique dépasse une limite prédéfinie, ce qui garantit que seules les interactions récentes sont conservées.
- Résumé : les anciens messages sont condensés en résumé, préservant les détails clés tout en réduisant le nombre de messages stockés.
- Basé sur un jeton : la réduction basée sur les jetons garantit que l’historique des conversations reste dans la limite de jetons d’un modèle en mesurant le nombre total de jetons et en supprimant ou en récapitulant les anciens messages lorsque la limite est dépassée.
Un réducteur d’historique de conversation automatise ces stratégies en évaluant la taille de l’historique et en la réduisant en fonction de paramètres configurables tels que le nombre cible (le nombre souhaité de messages à conserver) et le nombre de seuils (le point auquel la réduction est déclenchée). En intégrant ces techniques de réduction, les applications de conversation peuvent rester réactives et performantes sans compromettre le contexte conversationnel.
Dans la version .NET du noyau sémantique, l’abstraction réducteur de l’historique des conversations est définie par l’interface IChatHistoryReducer
:
namespace Microsoft.SemanticKernel.ChatCompletion;
[Experimental("SKEXP0001")]
public interface IChatHistoryReducer
{
Task<IEnumerable<ChatMessageContent>?> ReduceAsync(IReadOnlyList<ChatMessageContent> chatHistory, CancellationToken cancellationToken = default);
}
Cette interface permet des implémentations personnalisées pour la réduction de l’historique des conversations.
En outre, le noyau sémantique fournit des réducteurs intégrés :
-
ChatHistoryTruncationReducer
: tronque l’historique des conversations à une taille spécifiée et ignore les messages supprimés. La réduction est déclenchée lorsque la longueur de l’historique des conversations dépasse la limite. -
ChatHistorySummarizationReducer
: tronque l’historique des conversations, récapitule les messages supprimés et ajoute le résumé dans l’historique des conversations en tant que message unique.
Les deux réducteurs conservent toujours les messages système pour conserver le contexte essentiel du modèle.
L’exemple suivant montre comment conserver uniquement les deux derniers messages utilisateur tout en conservant le flux de conversation :
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}");
Vous trouverez d’autres exemples dans le référentiel du noyau sémantique .
Dans cette section, nous abordons les détails de l’implémentation de la réduction de l’historique des conversations dans Python. L’approche implique la création d’un ChatHistoryReducer qui s’intègre en toute transparence à l’objet ChatHistory, ce qui lui permet d’être utilisé et passé partout où un historique de conversation est requis.
- Intégration : En Python, le
ChatHistoryReducer
est conçu pour être une sous-classe de l’objetChatHistory
. Cet héritage permet au réducteur d’être interchangeable avec les instances d'historique de discussions standard. - Logique de réduction : les utilisateurs peuvent appeler la méthode
reduce
sur l’objet d’historique des conversations. Le réducteur évalue si le nombre de messages actuel dépassetarget_count
plusthreshold_count
(si défini). Si c'est le cas, l'historique est réduit àtarget_count
par troncation ou résumé. - Configuration : le comportement de réduction est configurable via des paramètres tels que
target_count
(le nombre souhaité de messages à conserver) et threshold_count (le nombre de messages qui déclenche le processus de réduction).
Les réducteurs historiques de Python pour le noyau sémantique pris en charge sont ChatHistorySummarizationReducer
et ChatHistoryTruncationReducer
. Dans le cadre de la configuration du réducteur, auto_reduce
peut être activé pour appliquer automatiquement la réduction de l’historique lorsqu’elle est utilisée avec add_message_async
, ce qui garantit que l’historique des conversations reste dans les limites configurées.
L’exemple suivant montre comment utiliser ChatHistoryTruncationReducer pour conserver uniquement les deux derniers messages tout en conservant le flux de conversation.
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())
La réduction de l’historique des conversations n’est actuellement pas disponible en Java.
Étapes suivantes
Maintenant que vous savez comment créer et gérer un objet d’historique des conversations, vous pouvez en savoir plus sur l’appel de fonction dans la rubrique d’appel de fonction.