Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
L’historique des conversations et la mémoire de l’agent sont des fonctionnalités cruciales qui permettent aux agents de maintenir le contexte entre les conversations, de mémoriser les préférences utilisateur et de fournir des expériences personnalisées. Agent Framework fournit plusieurs fonctionnalités pour répondre à différents cas d’usage, du stockage de messages de conversation en mémoire simple aux bases de données persistantes et aux services de mémoire spécialisés.
Historique des conversations
Différentes options de stockage de l’historique des conversations sont prises en charge par Agent Framework. Les options disponibles varient selon le type d’agent et les services sous-jacents utilisés pour générer l’agent.
Voici les deux principaux scénarios pris en charge :
-
Stockage en mémoire : l’agent est basé sur un service qui ne prend pas en charge le stockage en service de l’historique des conversations (par exemple, OpenAI Chat Completion). Agent Framework stocke par défaut l’historique complet des conversations en mémoire dans l’objet
AgentThread, mais les développeurs peuvent fournir une implémentation personnaliséeChatMessageStorepour stocker l’historique des conversations dans un magasin tiers si nécessaire. -
Stockage en service : l’agent repose sur un service qui nécessite un stockage en service de l’historique des conversations (par exemple, les agents persistants Azure AI Foundry). Agent Framework stocke l’ID de l’historique des conversations distantes dans l’objet
AgentThreadet aucune autre option de stockage de l’historique des conversations n’est prise en charge.
Stockage de l’historique des conversations en mémoire
Lorsque vous utilisez un service qui ne prend pas en charge le stockage in-service de l’historique des conversations, Agent Framework stocke par défaut l’historique des conversations en mémoire dans l’objet AgentThread . Dans ce cas, l’historique de conversation complet stocké dans l’objet thread, ainsi que les nouveaux messages, sera fourni au service sous-jacent sur chaque exécution de l’agent. Cela permet une expérience conversationnelle naturelle avec l’agent, où l’appelant fournit uniquement le nouveau message utilisateur, et l’agent retourne uniquement de nouvelles réponses, mais l’agent a accès à l’historique complet des conversations et l’utilisera lors de la génération de sa réponse.
Lorsque vous utilisez OpenAI Chat Completion comme service sous-jacent pour les agents, le code suivant entraîne l’exécution de l’objet thread contenant l’historique des conversations de l’agent.
AIAgent agent = new OpenAIClient("<your_api_key>")
.GetChatClient(modelName)
.CreateAIAgent(JokerInstructions, JokerName);
AgentThread thread = agent.GetNewThread();
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", thread));
Lorsque les messages sont stockés en mémoire, il est possible de récupérer la liste des messages du thread et de manipuler les messages directement si nécessaire.
IList<ChatMessage>? messages = thread.GetService<IList<ChatMessage>>();
Note
La récupération des messages à partir de l’objet AgentThread fonctionne uniquement si le stockage en mémoire est utilisé.
Réduction de l’historique des conversations avec stockage In-Memory
Le composant intégré InMemoryChatMessageStore utilisé par défaut lorsque le service sous-jacent ne prend pas en charge le stockage en service, peut être configuré avec un réducteur pour gérer la taille de l’historique des conversations.
Cela permet d’éviter de dépasser les limites de taille de contexte du service sous-jacent.
L’implémentation InMemoryChatMessageStore facultative Microsoft.Extensions.AI.IChatReducer peut réduire la taille de l’historique des conversations.
Il vous permet également de configurer l’événement pendant lequel le réducteur est appelé, soit après l’ajout d’un message à l’historique des conversations, soit avant que l’historique des conversations ne soit retourné pour l’appel suivant.
Pour configurer le InMemoryChatMessageStore réducteur avec un réducteur, vous pouvez fournir une fabrique pour construire un nouveau InMemoryChatMessageStore pour chaque nouveau AgentThread et le transmettre à un réducteur de votre choix. Vous InMemoryChatMessageStore pouvez également passer un événement de déclencheur facultatif qui peut être défini sur l’un ou l’autre InMemoryChatMessageStore.ChatReducerTriggerEvent.AfterMessageAddedInMemoryChatMessageStore.ChatReducerTriggerEvent.BeforeMessagesRetrieval.
AIAgent agent = new OpenAIClient("<your_api_key>")
.GetChatClient(modelName)
.CreateAIAgent(new ChatClientAgentOptions
{
Name = JokerName,
Instructions = JokerInstructions,
ChatMessageStoreFactory = ctx => new InMemoryChatMessageStore(
new MessageCountingChatReducer(2),
ctx.SerializedState,
ctx.JsonSerializerOptions,
InMemoryChatMessageStore.ChatReducerTriggerEvent.AfterMessageAdded)
});
Note
Cette fonctionnalité n’est prise en charge que lors de l’utilisation du InMemoryChatMessageStore. Lorsqu’un service dispose d’un stockage d’historique des conversations en service, il incombe au service lui-même de gérer la taille de l’historique des conversations. De même, lors de l’utilisation du stockage tiers (voir ci-dessous), il est jusqu’à la solution de stockage tierce pour gérer la taille de l’historique des conversations. Si vous fournissez un ChatMessageStoreFactory magasin de messages, mais que vous utilisez un service avec un stockage d’historique de conversation intégré, la fabrique ne sera pas utilisée.
Stockage de l’historique des conversations du service d’inférence
Lorsque vous utilisez un service qui nécessite un stockage en service de l’historique des conversations, Agent Framework stocke l’ID de l’historique des conversations distantes dans l’objet AgentThread .
Par exemple, lors de l’utilisation des réponses OpenAI avec store=true comme service sous-jacent pour les agents, le code suivant génère l’objet thread contenant le dernier ID de réponse retourné par le service.
AIAgent agent = new OpenAIClient("<your_api_key>")
.GetOpenAIResponseClient(modelName)
.CreateAIAgent(JokerInstructions, JokerName);
AgentThread thread = agent.GetNewThread();
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", thread));
Note
Certains services, par exemple, Les réponses OpenAI prennent en charge le stockage in-service de l’historique des conversations (store=true) ou fournissent l’historique de conversation complet sur chaque appel (store=false). Par conséquent, selon le mode dans lequel le service est utilisé, Agent Framework stocke par défaut l’historique de conversation complet en mémoire ou stocke une référence d’ID à l’historique de conversation stocké par le service.
Stockage de l’historique des conversations tiers
Lorsque vous utilisez un service qui ne prend pas en charge le stockage in-service de l’historique des conversations, Agent Framework permet aux développeurs de remplacer le stockage en mémoire par défaut de l’historique des conversations par le stockage de l’historique des conversations tiers. Le développeur doit fournir une sous-classe de la classe abstraite ChatMessageStore de base.
La ChatMessageStore classe définit l’interface permettant de stocker et de récupérer des messages de conversation. Les développeurs doivent implémenter les méthodes et AddMessagesAsync les GetMessagesAsync méthodes permettant d’ajouter des messages au magasin distant au fur et à mesure qu’ils sont générés et récupérer des messages du magasin distant avant d’appeler le service sous-jacent.
L’agent utilise tous les messages retournés lors du GetMessagesAsync traitement d’une requête utilisateur. Il incombe à l’implémenteur de ChatMessageStore s’assurer que la taille de l’historique des conversations ne dépasse pas la fenêtre de contexte du service sous-jacent.
Lors de l’implémentation d’un fichier personnalisé ChatMessageStore qui stocke l’historique des conversations dans un magasin distant, l’historique des conversations de ce thread doit être stocké sous une clé unique à ce thread. L’implémentation ChatMessageStore doit générer cette clé et la conserver dans son état.
ChatMessageStore a une Serialize méthode qui peut être substituée pour sérialiser son état lorsque le thread est sérialisé. Il ChatMessageStore doit également fournir un constructeur qui prend une JsonElement entrée comme entrée pour prendre en charge la désérialisation de son état.
Pour fournir un personnalisé ChatMessageStore à un ChatClientAgent, vous pouvez utiliser l’option lors de la ChatMessageStoreFactory création de l’agent.
Voici un exemple montrant comment passer l’implémentation personnalisée d’une ChatMessageStore implémentation basée sur l’achèvement de ChatClientAgent conversation Azure OpenAI.
AIAgent agent = new AzureOpenAIClient(
new Uri(endpoint),
new AzureCliCredential())
.GetChatClient(deploymentName)
.CreateAIAgent(new ChatClientAgentOptions
{
Name = JokerName,
Instructions = JokerInstructions,
ChatMessageStoreFactory = ctx =>
{
// Create a new chat message store for this agent that stores the messages in a custom store.
// Each thread must get its own copy of the CustomMessageStore, since the store
// also contains the id that the thread is stored under.
return new CustomMessageStore(vectorStore, ctx.SerializedState, ctx.JsonSerializerOptions);
}
});
Conseil / Astuce
Pour obtenir un exemple détaillé sur la création d’un magasin de messages personnalisé, consultez le didacticiel stockage de l’historique des conversations dans le didacticiel sur le stockage tiers .
Mémoire à long terme
Agent Framework permet aux développeurs de fournir des composants personnalisés qui peuvent extraire des souvenirs ou fournir des souvenirs à un agent.
Pour implémenter un tel composant de mémoire, le développeur doit sous-classer la AIContextProvider classe de base abstraite. Cette classe a deux méthodes principales et InvokingAsyncInvokedAsync. En cas de substitution, InvokedAsync permet aux développeurs d’inspecter tous les messages fournis par les utilisateurs ou générés par l’agent.
InvokingAsync permet aux développeurs d’injecter un contexte supplémentaire pour une exécution d’agent spécifique. Des instructions système, des messages supplémentaires et des fonctions supplémentaires peuvent être fournis.
Conseil / Astuce
Pour obtenir un exemple détaillé sur la création d’un composant de mémoire personnalisé, consultez le didacticiel Ajout de mémoire à un agent .
Sérialisation AgentThread
Il est important de pouvoir conserver un AgentThread objet entre les appels d’agent. Cela permet des situations où un utilisateur peut poser une question à l’agent et prendre beaucoup de temps pour poser des questions de suivi. Cela permet à l’état AgentThread de survivre aux redémarrages du service ou de l’application.
Même si l’historique des conversations est stocké dans un magasin distant, l’objet AgentThread contient toujours un ID référençant l’historique des conversations distantes. La perte de l’état AgentThread entraîne donc également la perte de l’ID de l’historique des conversations distantes.
Ainsi AgentThread que tous les objets attachés à celui-ci, tous fournissent donc la SerializeAsync méthode pour sérialiser leur état. Il AIAgent fournit également une DeserializeThread méthode qui recrée un thread à partir de l’état sérialisé. La DeserializeThread méthode recrée le thread avec l’agent ChatMessageStore et AIContextProvider le configure sur l’agent.
// Serialize the thread state to a JsonElement, so it can be stored for later use.
JsonElement serializedThreadState = thread.Serialize();
// Re-create the thread from the JsonElement.
AgentThread resumedThread = AIAgent.DeserializeThread(serializedThreadState);
Note
AgentThread les objets peuvent contenir plus que l’historique des conversations, par exemple, les fournisseurs de contexte peuvent également stocker l’état dans l’objet thread. Par conséquent, il est important de toujours sérialiser, stocker et désérialiser l’ensemble de l’objet AgentThread pour s’assurer que tout l’état est conservé.
Important
Traitez AgentThread toujours les objets comme des objets opaques, sauf si vous êtes très sûr des éléments internes. Le contenu peut varier non seulement par type d’agent, mais également par type de service et par configuration.
Avertissement
La désérialisation d’un thread avec un agent différent de celui qui l’a créé à l’origine, ou avec un agent ayant une configuration différente de celle de l’agent d’origine, peut entraîner des erreurs ou un comportement inattendu.
Types de mémoire
Agent Framework prend en charge plusieurs types de mémoire pour prendre en charge différents cas d’usage, notamment la gestion de l’historique des conversations dans le cadre de la mémoire à court terme et la fourniture de points d’extension pour l’extraction, le stockage et l’injection de mémoires à long terme dans des agents.
stockage In-Memory (valeur par défaut)
La forme la plus simple de mémoire où l’historique des conversations est stocké en mémoire pendant le runtime de l’application. Il s’agit du comportement par défaut et ne nécessite aucune configuration supplémentaire.
from agent_framework import ChatAgent
from agent_framework.openai import OpenAIChatClient
# Default behavior - uses in-memory storage
agent = ChatAgent(
chat_client=OpenAIChatClient(),
instructions="You are a helpful assistant."
)
# Conversation history is maintained in memory for this thread
thread = agent.get_new_thread()
response = await agent.run("Hello, my name is Alice", thread=thread)
Magasins de messages persistants
Pour les applications qui doivent conserver l’historique des conversations entre les sessions, l’infrastructure fournit des ChatMessageStore implémentations :
ChatMessageStore intégré
Implémentation en mémoire par défaut qui peut être sérialisée :
from agent_framework import ChatMessageStore
# Create a custom message store
def create_message_store():
return ChatMessageStore()
agent = ChatAgent(
chat_client=OpenAIChatClient(),
instructions="You are a helpful assistant.",
chat_message_store_factory=create_message_store
)
Magasin de messages Redis
Pour les applications de production nécessitant un stockage persistant :
from agent_framework.redis import RedisChatMessageStore
def create_redis_store():
return RedisChatMessageStore(
redis_url="redis://localhost:6379",
thread_id="user_session_123",
max_messages=100 # Keep last 100 messages
)
agent = ChatAgent(
chat_client=OpenAIChatClient(),
instructions="You are a helpful assistant.",
chat_message_store_factory=create_redis_store
)
Magasin de messages personnalisé
Vous pouvez implémenter votre propre back-end de stockage en implémentant les ChatMessageStoreProtocolpoints suivants :
from agent_framework import ChatMessage, ChatMessageStoreProtocol
from typing import Any
from collections.abc import Sequence
class DatabaseMessageStore(ChatMessageStoreProtocol):
def __init__(self, connection_string: str):
self.connection_string = connection_string
self._messages: list[ChatMessage] = []
async def add_messages(self, messages: Sequence[ChatMessage]) -> None:
"""Add messages to database."""
# Implement database insertion logic
self._messages.extend(messages)
async def list_messages(self) -> list[ChatMessage]:
"""Retrieve messages from database."""
# Implement database query logic
return self._messages
async def serialize(self, **kwargs: Any) -> Any:
"""Serialize store state for persistence."""
return {"connection_string": self.connection_string}
async def update_from_state(self, serialized_store_state: Any, **kwargs: Any) -> None:
"""Update store from serialized state."""
if serialized_store_state:
self.connection_string = serialized_store_state["connection_string"]
Conseil / Astuce
Pour obtenir un exemple détaillé sur la création d’un magasin de messages personnalisé, consultez le didacticiel stockage de l’historique des conversations dans le didacticiel sur le stockage tiers .
Fournisseurs de contexte (mémoire dynamique)
Les fournisseurs de contexte permettent des modèles de mémoire sophistiqués en injectant le contexte approprié avant chaque appel d’agent :
Fournisseur de contexte de base
from agent_framework import ContextProvider, Context, ChatMessage
from collections.abc import MutableSequence
from typing import Any
class UserPreferencesMemory(ContextProvider):
def __init__(self):
self.preferences = {}
async def invoking(self, messages: ChatMessage | MutableSequence[ChatMessage], **kwargs: Any) -> Context:
"""Provide user preferences before each invocation."""
if self.preferences:
preferences_text = ", ".join([f"{k}: {v}" for k, v in self.preferences.items()])
instructions = f"User preferences: {preferences_text}"
return Context(instructions=instructions)
return Context()
async def invoked(
self,
request_messages: ChatMessage | Sequence[ChatMessage],
response_messages: ChatMessage | Sequence[ChatMessage] | None = None,
invoke_exception: Exception | None = None,
**kwargs: Any,
) -> None:
"""Extract and store user preferences from the conversation."""
# Implement preference extraction logic
pass
Conseil / Astuce
Pour obtenir un exemple détaillé sur la création d’un composant de mémoire personnalisé, consultez le didacticiel Ajout de mémoire à un agent .
Services de mémoire externe
L’infrastructure prend en charge l’intégration à des services de mémoire spécialisés comme Mem0 :
from agent_framework.mem0 import Mem0Provider
# Using Mem0 for advanced memory capabilities
memory_provider = Mem0Provider(
api_key="your-mem0-api-key",
user_id="user_123",
application_id="my_app"
)
agent = ChatAgent(
chat_client=OpenAIChatClient(),
instructions="You are a helpful assistant with memory.",
context_providers=memory_provider
)
Sérialisation et persistance des threads
Le framework prend en charge la sérialisation des états de thread entiers pour la persistance entre les redémarrages d’application :
import json
# Create agent and thread
agent = ChatAgent(chat_client=OpenAIChatClient())
thread = agent.get_new_thread()
# Have conversation
await agent.run("Hello, my name is Alice", thread=thread)
# Serialize thread state
serialized_thread = await thread.serialize()
# Save to file/database
with open("thread_state.json", "w") as f:
json.dump(serialized_thread, f)
# Later, restore the thread
with open("thread_state.json", "r") as f:
thread_data = json.load(f)
restored_thread = await agent.deserialize_thread(thread_data)
# Continue conversation with full context
await agent.run("What's my name?", thread=restored_thread)