Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Úložiště určuje, kde se nachází historie konverzací, kolik historie se načte a jak spolehlivě se dají relace obnovit.
Integrované režimy úložiště
Agent Framework podporuje dva běžné režimy úložiště:
| Režim | Co je uloženo | Typické použití |
|---|---|---|
| Místní stav relace | Úplná historie chatu v AgentSession.state (například prostřednictvím InMemoryHistoryProvider) |
Služby, které nevyžadují trvalost konverzací na straně serveru |
| Úložiště spravované službou | Stav konverzace ve službě; AgentSession.service_session_id odkazuje na ni |
Služby s nativní podporou trvalých konverzací |
Úložiště historie chatu v paměti
Pokud poskytovatel nevyžaduje historii chatu na straně serveru, agent Framework uchovává historii místně v relaci a odesílá relevantní zprávy při každém spuštění.
AIAgent agent = new OpenAIClient("<your_api_key>")
.GetChatClient(modelName)
.AsAIAgent(instructions: "You are a helpful assistant.", name: "Assistant");
AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session));
// When in-memory chat history storage is used, it's possible to access the chat history
// that is stored in the session via the provider attached to the agent.
var provider = agent.GetService<InMemoryChatHistoryProvider>();
List<ChatMessage>? messages = provider?.GetMessages(session);
from agent_framework import InMemoryHistoryProvider
from agent_framework.openai import OpenAIChatClient
agent = OpenAIChatClient().as_agent(
name="StorageAgent",
instructions="You are a helpful assistant.",
context_providers=[InMemoryHistoryProvider("memory", load_messages=True)],
)
session = agent.create_session()
await agent.run("Remember that I like Italian food.", session=session)
Zmenšení velikosti historie v paměti
Pokud se historie pro limity modelů příliš rozrůstá, použijte redukční faktor.
AIAgent agent = new OpenAIClient("<your_api_key>")
.GetChatClient(modelName)
.AsAIAgent(new ChatClientAgentOptions
{
Name = "Assistant",
ChatOptions = new() { Instructions = "You are a helpful assistant." },
ChatHistoryProvider = new InMemoryChatHistoryProvider(new InMemoryChatHistoryProviderOptions
{
ChatReducer = new MessageCountingChatReducer(20)
})
});
Poznámka:
Konfigurace redukčního nástroje se vztahuje na zprostředkovatele historie v paměti. V případě historie spravované služby je chování redukce specifické pro poskytovatele nebo službu.
Úložiště spravované službou
Když služba spravuje historii konverzací, relace uloží identifikátor vzdálené konverzace.
AIAgent agent = new OpenAIClient("<your_api_key>")
.GetOpenAIResponseClient(modelName)
.AsAIAgent(instructions: "You are a helpful assistant.", name: "Assistant");
AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session));
// In this case, since we know we are working with a ChatClientAgent, we can cast
// the AgentSession to a ChatClientAgentSession to retrieve the remote conversation
// identifier.
ChatClientAgentSession typedSession = (ChatClientAgentSession)session;
Console.WriteLine(typedSession.ConversationId);
# Rehydrate when the service already has the conversation state.
session = agent.get_session(service_session_id="<service-conversation-id>")
response = await agent.run("Continue this conversation.", session=session)
Ukládání historie pro jednotlivá volání služby
Spuštění volání nástrojů může provádět více volání modelu před dokončením jednoho agent.run(). Ve výchozím nastavení zprostředkovatelé místní historie se uloží jednou po úplném spuštění. Pokud chcete, aby místní historie lépe zrcadlila konverzace spravované službou, nastavte require_per_service_call_history_persistence=True , aby poskytovatelé historie místo toho běželi kolem jednotlivých volání modelu.
from agent_framework import Agent, InMemoryHistoryProvider
from agent_framework.openai import OpenAIChatClient
agent = Agent(
client=OpenAIChatClient(),
name="StorageAgent",
instructions="You are a helpful assistant.",
context_providers=[InMemoryHistoryProvider("memory", load_messages=True)],
require_per_service_call_history_persistence=True,
)
Důležité
Tento režim použijte pouze pro místní historii spravovanou rámcem. Pokud je spuštění již vázáno na konverzaci spravovanou službou (například prostřednictvím session.service_session_id nebo options={"conversation_id": ...}), agent Framework vyvolá chybu místo kombinování těchto dvou modelů trvalosti.
Tento režim je zvlášť užitečný, když se middleware může ukončit okamžitě po volání nástroje: při zachování na jedno volání modelu udržuje místní historii v souladu s tím, jak by ji vedla spravovaná služba.
Model úložiště třetích stran nebo vlastní úložiště
Pro databázi, Redis nebo historii založené na objektech blob implementujte vlastního poskytovatele historie.
Klíčové pokyny:
- Ukládat zprávy pod klíčem s rozsahovou platností relace.
- Uchovávejte vrácenou historii v rámci omezení kontextu modelu.
- Zachovají identifikátory specifické pro zprostředkovatele ve stavu relace.
Základní třída pro poskytovatele historie je Microsoft.Agents.AI.ChatHistoryProvider.
Poskytovatelé historie se účastní kanálu agenta, mají možnost přispívat do vstupních zpráv agenta nebo je přepsat a můžou ukládat nové zprávy.
ChatHistoryProvider má různé virtuální metody, které je možné přepsat k implementaci vlastního poskytovatele historie.
Další informace o tom, co je potřeba přepsat, jsou uvedeny v možnostech implementace níže.
ChatHistoryProvider Stav
Instance ChatHistoryProvider je přiřazena agentovi a stejná instance by se používala pro všechny relace.
To znamená, že ChatHistoryProvider v instanci poskytovatele by se neměl ukládat žádný konkrétní stav relace.
Může ChatHistoryProvider mít odkaz na databázového klienta v poli, ale neměl by mít v poli klíč databáze pro historii chatu.
Místo toho může ChatHistoryProvider ukládat jakékoli hodnoty specifické pro relaci, jako jsou databázové klíče, zprávy nebo cokoli jiného, co je relevantní samo o sobě v AgentSession. Všem virtuálním metodám ChatHistoryProvider se předává odkaz na aktuální AIAgent a AgentSession.
Chcete-li snadno ukládat stav s určeným typem v AgentSession, je k dispozici pomocná třída:
// First define a type containing the properties to store in state
internal class MyCustomState
{
public string? DbKey { get; set; }
}
// Create the helper
var sessionStateHelper = new ProviderSessionState<MyCustomState>(
// stateInitializer is called when there is no state in the session for this ChatHistoryProvider yet
stateInitializer: currentSession => new MyCustomState() { DbKey = Guid.NewGuid().ToString() },
// The key under which to store state in the session for this provider. Make sure it does not clash with the keys of other providers.
stateKey: this.GetType().Name,
// An optional jsonSerializerOptions to control the serialization/deserialization of the custom state object
jsonSerializerOptions: myJsonSerializerOptions);
// Using the helper you can read state:
MyCustomState state = sessionStateHelper.GetOrInitializeState(session);
Console.WriteLine(state.DbKey);
// And write state:
sessionStateHelper.SaveState(session, state);
Jednoduchá ChatHistoryProvider implementace
Nejjednodušší ChatHistoryProvider implementace by obvykle přepsala dvě metody:
- ChatHistoryProvider.ProvideChatHistoryAsync – Načtěte relevantní historii chatu a vraťte načtené zprávy.
- ChatHistoryProvider.StoreChatHistoryAsync – zprávy žádosti o uložení a odpovědi, z nichž všechny by měly být nové.
Tady je příklad jednoduchého ChatHistoryProvider uložení historie chatu přímo do stavu relace.
public sealed class SimpleInMemoryChatHistoryProvider : ChatHistoryProvider
{
private readonly ProviderSessionState<State> _sessionState;
public SimpleInMemoryChatHistoryProvider(
Func<AgentSession?, State>? stateInitializer = null,
string? stateKey = null)
{
this._sessionState = new ProviderSessionState<State>(
stateInitializer ?? (_ => new State()),
stateKey ?? this.GetType().Name);
}
public override string StateKey => this._sessionState.StateKey;
protected override ValueTask<IEnumerable<ChatMessage>> ProvideChatHistoryAsync(InvokingContext context, CancellationToken cancellationToken = default) =>
// return all messages in the session state
new(this._sessionState.GetOrInitializeState(context.Session).Messages);
protected override ValueTask StoreChatHistoryAsync(InvokedContext context, CancellationToken cancellationToken = default)
{
var state = this._sessionState.GetOrInitializeState(context.Session);
// Add both request and response messages to the session state.
var allNewMessages = context.RequestMessages.Concat(context.ResponseMessages ?? []);
state.Messages.AddRange(allNewMessages);
this._sessionState.SaveState(context.Session, state);
return default;
}
public sealed class State
{
[JsonPropertyName("messages")]
public List<ChatMessage> Messages { get; set; } = [];
}
}
Pokročilá ChatHistoryProvider implementace
Pokročilejší implementace by se mohla rozhodnout přepsat následující metody:
- ChatHistoryProvider.InvokingCoreAsync – Volá se před tím, než agent vyvolá LLM, a umožňuje úpravu seznamu zpráv žádosti.
- ChatHistoryProvider.InvokedCoreAsync – je vyvoláno poté, co agent spustí LLM a umožní přístup ke všem zprávám o požadavcích a odpovědích.
ChatHistoryProvider poskytuje základní implementace InvokingCoreAsync a InvokedCoreAsync.
Základní InvokingCoreAsync implementace provede následující:
- volání
ProvideChatHistoryAsyncpro získání zpráv, které by se měly použít jako historie chatu pro spuštění - spustí volitelný filtr
FuncprovideOutputMessageFilterzpráv vrácených uživatelemProvideChatHistoryAsync. Tento filtrFunclze zadat prostřednictvím konstruktoruChatHistoryProvider. - sloučí filtrované zprávy, vrácené pomocí
ProvideChatHistoryAsync, se zprávami předávanými volajícím do agenta k vytvoření žádostí agenta. Historie chatu je připojena před vstupní zprávy agenta. - označí všechny filtrované zprávy vrácené
ProvideChatHistoryAsynczdrojovými informacemi, které označují, že tyto zprávy pocházejí z historie chatu.
Základ InvokedCoreAsync dělá následující:
- zkontroluje, jestli spuštění selhalo, a pokud ano, vrátí se bez dalšího zpracování.
- filtruje požadavky agenta na zprávy tak, aby byly vyloučeny ty, které byly vytvořeny aplikací
ChatHistoryProvider, protože chceme ukládat pouze nové zprávy, nikoli ty, které vytvořilChatHistoryProviderpůvodně. Všimněte si, že tento filtr lze přepsat pomocístoreInputMessageFilterparametru v konstruktoruChatHistoryProvider. - předá filtrované požadované zprávy a všechny zprávy odpovědi do
StoreChatHistoryAsyncúložiště.
Tyto metody je možné přepsat k implementaci ChatHistoryProvider, ale to vyžaduje, aby implementátor sám přiměřeně zajistil základní funkčnost.
Tady je příklad takové implementace.
public sealed class AdvancedInMemoryChatHistoryProvider : ChatHistoryProvider
{
private readonly ProviderSessionState<State> _sessionState;
public AdvancedInMemoryChatHistoryProvider(
Func<AgentSession?, State>? stateInitializer = null,
string? stateKey = null)
{
this._sessionState = new ProviderSessionState<State>(
stateInitializer ?? (_ => new State()),
stateKey ?? this.GetType().Name);
}
public override string StateKey => this._sessionState.StateKey;
protected override ValueTask<IEnumerable<ChatMessage>> InvokingCoreAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
// Retrieve the chat history from the session state.
var chatHistory = this._sessionState.GetOrInitializeState(context.Session).Messages;
// Stamp the messages with this class as the source, so that they can be filtered out later if needed when storing the agent input/output.
var stampedChatHistory = chatHistory.Select(message => message.WithAgentRequestMessageSource(AgentRequestMessageSourceType.ChatHistory, this.GetType().FullName!));
// Merge the original input with the chat history to produce a combined agent input.
return new(stampedChatHistory.Concat(context.RequestMessages));
}
protected override ValueTask InvokedCoreAsync(InvokedContext context, CancellationToken cancellationToken = default)
{
if (context.InvokeException is not null)
{
return default;
}
// Since we are receiving all messages that were contributed earlier, including those from chat history, we need to filter out the messages that came from chat history
// so that we don't store message we already have in storage.
var filteredRequestMessages = context.RequestMessages.Where(m => m.GetAgentRequestMessageSourceType() != AgentRequestMessageSourceType.ChatHistory);
var state = this._sessionState.GetOrInitializeState(context.Session);
// Add both request and response messages to the state.
var allNewMessages = filteredRequestMessages.Concat(context.ResponseMessages ?? []);
state.Messages.AddRange(allNewMessages);
this._sessionState.SaveState(context.Session, state);
return default;
}
public sealed class State
{
[JsonPropertyName("messages")]
public List<ChatMessage> Messages { get; set; } = [];
}
}
- V Pythonu by měl používat
load_messages=Truepouze jeden poskytovatel historie .
from agent_framework.openai import OpenAIChatClient
history = DatabaseHistoryProvider(db_client)
agent = OpenAIChatClient().as_agent(
name="StorageAgent",
instructions="You are a helpful assistant.",
context_providers=[history],
)
session = agent.create_session()
await agent.run("Store this conversation.", session=session)
Zachování relací během restartů
Zachovejte celý AgentSession, nejen text zprávy.
JsonElement serialized = agent.SerializeSession(session);
// Store serialized payload in durable storage.
AgentSession resumed = await agent.DeserializeSessionAsync(serialized);
serialized = session.to_dict()
# Store serialized payload in durable storage.
resumed = AgentSession.from_dict(serialized)
Důležité
Zacházejte s AgentSession jako s neprůhledným stavovým objektem a obnovte ho se stejnou konfigurací agenta a poskytovatele, která ho vytvořila.
Návod
Použijte dalšího zprostředkovatele historie auditu/evaluace (load_messages=False, store_context_messages=True) k zachycení rozšířeného kontextu a vstupu/výstupu, aniž by to ovlivnilo načítání primární historie.