Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
La cronologia e la memoria delle chat degli agenti sono funzionalità cruciali che consentono agli agenti di mantenere il contesto nelle conversazioni, ricordare le preferenze utente e offrire esperienze personalizzate. Agent Framework offre più funzionalità per soddisfare casi d'uso diversi, dalla semplice risorsa di archiviazione dei messaggi di chat in memoria ai database persistenti e ai servizi di memoria specializzati.
Cronologia chat
Varie opzioni di archiviazione della cronologia delle chat sono supportate da Agent Framework. Le opzioni disponibili variano in base al tipo di agente e ai servizi sottostanti usati per compilare l'agente.
Ecco i due scenari principali supportati:
-
Archiviazione in memoria: Agent è basato su un servizio che non supporta l'archiviazione in servizio della cronologia delle chat (ad esempio, completamento della chat OpenAI). Agent Framework archivierà per impostazione predefinita la cronologia completa delle chat in memoria nell'oggetto
AgentThread, ma gli sviluppatori possono fornire un'implementazione personalizzataChatMessageStoreper archiviare la cronologia delle chat in un archivio di terze parti, se necessario. -
Archiviazione nel servizio: l'agente è basato su un servizio che richiede l'archiviazione in servizio della cronologia delle chat ,ad esempio gli agenti persistenti di Azure AI Foundry. Agent Framework archivierà l'ID della cronologia delle chat remote nell'oggetto
AgentThreade non sono supportate altre opzioni di archiviazione della cronologia delle chat.
Archiviazione della cronologia delle chat in memoria
Quando si usa un servizio che non supporta l'archiviazione nella cronologia delle chat nel servizio, Agent Framework archivia la cronologia delle chat in memoria nell'oggetto AgentThread . In questo caso, la cronologia di chat completa archiviata nell'oggetto thread, più eventuali nuovi messaggi, verrà fornita al servizio sottostante in ogni esecuzione dell'agente. Ciò consente un'esperienza di conversazione naturale con l'agente, in cui il chiamante fornisce solo il nuovo messaggio utente e l'agente restituisce solo nuove risposte, ma l'agente ha accesso alla cronologia completa della conversazione e lo userà durante la generazione della risposta.
Quando si usa OpenAI Chat Completion come servizio sottostante per gli agenti, il codice seguente genererà l'oggetto thread contenente la cronologia delle chat dall'esecuzione dell'agente.
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));
Dove i messaggi vengono archiviati in memoria, è possibile recuperare l'elenco di messaggi dal thread e modificare direttamente i messaggi, se necessario.
IList<ChatMessage>? messages = thread.GetService<IList<ChatMessage>>();
Annotazioni
Il recupero dei messaggi dall'oggetto AgentThread in questo modo funzionerà solo se viene usata l'archiviazione in memoria.
Riduzione della cronologia chat con archiviazione In-Memory
InMemoryChatMessageStore Il valore predefinito usato per impostazione predefinita quando il servizio sottostante non supporta l'archiviazione nel servizio, può essere configurato con un riduttore per gestire le dimensioni della cronologia delle chat.
Ciò è utile per evitare di superare i limiti di dimensioni del contesto del servizio sottostante.
InMemoryChatMessageStore può accettare un'implementazione facoltativa Microsoft.Extensions.AI.IChatReducer per ridurre le dimensioni della cronologia delle chat.
Consente anche di configurare l'evento durante il quale viene richiamato il reducer, dopo l'aggiunta di un messaggio alla cronologia delle chat o prima della restituzione della cronologia delle chat per la chiamata successiva.
Per configurare con un riduttoreInMemoryChatMessageStore, è possibile fornire una factory per costruire un nuovo per ogni nuovo InMemoryChatMessageStoreAgentThread e passarlo un riduttore di propria scelta.
InMemoryChatMessageStore Può anche essere passato un evento trigger facoltativo che può essere impostato su InMemoryChatMessageStore.ChatReducerTriggerEvent.AfterMessageAdded o InMemoryChatMessageStore.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)
});
Annotazioni
Questa funzionalità è supportata solo quando si usa .InMemoryChatMessageStore Quando un servizio dispone di archiviazione cronologia chat nel servizio, spetta al servizio stesso gestire le dimensioni della cronologia delle chat. Analogamente, quando si usa l'archiviazione di terze parti (vedere di seguito), è fino alla soluzione di archiviazione di terze parti per gestire le dimensioni della cronologia delle chat. Se si specifica un ChatMessageStoreFactory per un archivio messaggi ma si usa un servizio con l'archiviazione della cronologia delle chat predefinite, la factory non verrà usata.
Archiviazione della cronologia chat del servizio di inferenza
Quando si usa un servizio che richiede l'archiviazione in servizio della cronologia delle chat, Agent Framework archivierà l'ID della cronologia chat remota nell'oggetto AgentThread .
Ad esempio, quando si usano risposte OpenAI con store=true come servizio sottostante per gli agenti, il codice seguente genererà l'oggetto thread contenente l'ultimo ID risposta restituito dal servizio.
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));
Annotazioni
Alcuni servizi, ad esempio Le risposte OpenAI supportano l'archiviazione in servizio della cronologia delle chat (store=true) o la cronologia completa delle chat in ogni chiamata (store=false). Pertanto, a seconda della modalità in cui viene usato il servizio, Agent Framework archivierà per impostazione predefinita la cronologia completa della chat in memoria o archivia un riferimento ID alla cronologia delle chat archiviate del servizio.
Archiviazione della cronologia delle chat di terze parti
Quando si usa un servizio che non supporta l'archiviazione nella cronologia delle chat nel servizio, Agent Framework consente agli sviluppatori di sostituire l'archiviazione in memoria predefinita della cronologia delle chat con l'archiviazione della cronologia di chat di terze parti. Lo sviluppatore deve fornire una sottoclasse della classe astratta ChatMessageStore di base.
La ChatMessageStore classe definisce l'interfaccia per l'archiviazione e il recupero dei messaggi di chat. Gli sviluppatori devono implementare i AddMessagesAsync metodi e GetMessagesAsync per aggiungere messaggi all'archivio remoto man mano che vengono generati e recuperare i messaggi dall'archivio remoto prima di richiamare il servizio sottostante.
L'agente userà tutti i messaggi restituiti da GetMessagesAsync durante l'elaborazione di una query utente. Spetta all'implementatore di ChatMessageStore garantire che le dimensioni della cronologia delle chat non superino la finestra di contesto del servizio sottostante.
Quando si implementa un oggetto personalizzato che archivia la cronologia ChatMessageStore delle chat in un archivio remoto, la cronologia delle chat per tale thread deve essere archiviata in una chiave univoca per tale thread. L'implementazione ChatMessageStore deve generare questa chiave e mantenerla nello stato.
ChatMessageStore dispone di un Serialize metodo che può essere sottoposto a override per serializzare il relativo stato quando il thread viene serializzato. deve ChatMessageStore inoltre fornire un costruttore che accetta come JsonElement input per supportare la deserializzazione dello stato.
Per fornire un oggetto personalizzato ChatMessageStore a un ChatClientAgentoggetto , è possibile usare l'opzione durante la ChatMessageStoreFactory creazione dell'agente.
Di seguito è riportato un esempio che illustra come passare l'implementazione personalizzata di ChatMessageStore a un ChatClientAgent oggetto basato sul completamento della chat OpenAI di Azure.
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);
}
});
Suggerimento
Per un esempio dettagliato su come creare un archivio messaggi personalizzato, vedere l'esercitazione Archiviazione della cronologia chat in Archiviazione di terze parti .
Memoria a lungo termine
Agent Framework consente agli sviluppatori di fornire componenti personalizzati che possono estrarre memorie o fornire memorie a un agente.
Per implementare tale componente di memoria, lo sviluppatore deve sottoclassare la AIContextProvider classe base astratta. Questa classe ha due metodi principali, InvokingAsync e InvokedAsync. In caso di override, InvokedAsync consente agli sviluppatori di controllare tutti i messaggi forniti dagli utenti o generati dall'agente.
InvokingAsync consente agli sviluppatori di inserire un contesto aggiuntivo per un'esecuzione specifica dell'agente. È possibile fornire istruzioni di sistema, messaggi aggiuntivi e funzioni aggiuntive.
Suggerimento
Per un esempio dettagliato su come creare un componente di memoria personalizzato, vedere l'esercitazione Aggiunta di memoria a un agente .
Serializzazione di AgentThread
È importante essere in grado di salvare in modo permanente un AgentThread oggetto tra le chiamate dell'agente. Ciò consente alle situazioni in cui un utente può porre una domanda all'agente e richiedere molto tempo per porre domande di completamento. In questo modo lo AgentThread stato può sopravvivere ai riavvii del servizio o dell'app.
Anche se la cronologia delle chat viene archiviata in un archivio remoto, l'oggetto AgentThread contiene ancora un ID che fa riferimento alla cronologia delle chat remote. La perdita dello AgentThread stato comporterà quindi anche la perdita dell'ID della cronologia di chat remota.
AgentThread E tutti gli oggetti collegati, forniscono quindi il metodo per serializzare il SerializeAsync relativo stato. Fornisce AIAgent inoltre un DeserializeThread metodo che ricrea un thread dallo stato serializzato. Il DeserializeThread metodo ricrea il thread con ChatMessageStore e AIContextProvider configurato nell'agente.
// 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);
Annotazioni
AgentThread gli oggetti possono contenere più della semplice cronologia delle chat, ad esempio i provider di contesto possono anche archiviare lo stato nell'oggetto thread. Pertanto, è importante serializzare sempre, archiviare e deserializzare l'intero AgentThread oggetto per garantire che tutto lo stato venga mantenuto.
Importante
Considera AgentThread sempre gli oggetti come oggetti opachi, a meno che non sei molto sicuro degli elementi interni. Il contenuto può variare non solo in base al tipo di agente, ma anche al tipo di servizio e alla configurazione.
Avvertimento
La deserializzazione di un thread con un agente diverso da quello che l'ha originariamente creata o con un agente con una configurazione diversa rispetto all'agente originale, può causare errori o comportamenti imprevisti.
Tipi di memoria
Agent Framework supporta diversi tipi di memoria per supportare diversi casi d'uso, tra cui la gestione della cronologia delle chat come parte della memoria a breve termine e la fornitura di punti di estensione per l'estrazione, l'archiviazione e l'inserimento di memorie a lungo termine negli agenti.
archiviazione In-Memory (impostazione predefinita)
La forma più semplice di memoria in cui la cronologia delle conversazioni viene archiviata in memoria durante il runtime dell'applicazione. Si tratta del comportamento predefinito e non richiede alcuna configurazione aggiuntiva.
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)
Archivi messaggi permanenti
Per le applicazioni che devono rendere persistente la cronologia delle conversazioni tra le sessioni, il framework fornisce ChatMessageStore implementazioni:
ChatMessageStore predefinito
Implementazione predefinita in memoria che può essere serializzata:
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
)
Archivio messaggi Redis
Per le applicazioni di produzione che richiedono l'archiviazione permanente:
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
)
Archivio messaggi personalizzato
È possibile implementare un back-end di archiviazione personalizzato implementando :ChatMessageStoreProtocol
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"]
Suggerimento
Per un esempio dettagliato su come creare un archivio messaggi personalizzato, vedere l'esercitazione Archiviazione della cronologia chat in Archiviazione di terze parti .
Provider di contesto (memoria dinamica)
I provider di contesto consentono modelli di memoria sofisticati inserendo il contesto pertinente prima di ogni chiamata dell'agente:
Provider di contesto di 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
Suggerimento
Per un esempio dettagliato su come creare un componente di memoria personalizzato, vedere l'esercitazione Aggiunta di memoria a un agente .
Servizi di memoria esterna
Il framework supporta l'integrazione con servizi di memoria specializzati come 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
)
Serializzazione e persistenza dei thread
Il framework supporta la serializzazione di interi stati del thread per la persistenza tra i riavvii dell'applicazione:
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)