Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Penyimpanan menentukan di mana riwayat percakapan disimpan, berapa banyak data riwayat yang dimuat, dan seberapa andal sesi dapat dimulai kembali.
Mode penyimpanan bawaan
Agent Framework mendukung dua mode penyimpanan reguler:
| Pengaturan | Apa yang disimpan | Penggunaan umum |
|---|---|---|
| Status sesi lokal | Riwayat obrolan lengkap di AgentSession.state (misalnya melalui InMemoryHistoryProvider) |
Layanan yang tidak memerlukan persistensi percakapan sisi server |
| Penyimpanan yang dikelola layanan | Status percakapan dalam layanan; AgentSession.service_session_id menunjuk ke dalamnya |
Layanan dengan dukungan percakapan persisten bawaan |
Penyimpanan riwayat obrolan dalam memori
Saat penyedia tidak memerlukan riwayat obrolan sisi server, Agent Framework menyimpan riwayat secara lokal dalam sesi dan mengirim pesan yang relevan pada setiap proses.
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)
Mengurangi ukuran riwayat dalam memori
Jika riwayat tumbuh terlalu besar untuk batas model, terapkan pengurang.
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)
})
});
Nota
Konfigurasi reducer berlaku untuk penyedia riwayat dalam memori. Untuk riwayat yang dikelola oleh layanan, perilaku pengurangan tergantung pada penyedia atau layanan.
Penyimpanan yang dikelola layanan
Saat layanan mengelola riwayat percakapan, sesi menyimpan pengidentifikasi percakapan jarak jauh.
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)
Persistensi riwayat lokal per panggilan layanan
Eksekusi panggilan alat dapat melakukan beberapa panggilan model sebelum satu agent.run() kali selesai. Secara bawaan, penyedia riwayat lokal terus disimpan sekali setelah menjalankan secara penuh. Jika Anda ingin riwayat lokal mencerminkan percakapan yang dikelola layanan lebih dekat, atur require_per_service_call_history_persistence=True agar penyedia riwayat menjalankan setiap panggilan model sebagai gantinya.
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,
)
Penting
Gunakan mode ini hanya untuk riwayat lokal yang dikelola kerangka kerja. Jika eksekusi sudah terikat ke percakapan yang dikelola layanan (misalnya melalui session.service_session_id atau options={"conversation_id": ...}), Kerangka Kerja Agen menimbulkan kesalahan alih-alih mencampur dua model persistensi.
Mode ini sangat berguna ketika middleware dapat segera berakhir setelah panggilan alat: melanjutkan status setiap panggilan model menjaga catatan lokal tetap selaras dengan catatan yang akan disimpan oleh percakapan yang dikelola layanan.
Pola penyimpanan pihak ketiga/Kustom
Untuk riwayat database/Redis/blob-backed, terapkan penyedia riwayat kustom.
Panduan utama:
- Simpan pesan di bawah kunci yang terlingkup sesi.
- Pertahankan riwayat yang dikembalikan dalam batas konteks model.
- Pertahankan pengidentifikasi khusus penyedia dalam status sesi.
Kelas dasar untuk penyedia riwayat adalah Microsoft.Agents.AI.ChatHistoryProvider.
Penyedia riwayat berpartisipasi dalam alur agen, memiliki kemampuan untuk berkontribusi atau mengambil alih pesan input agen dan dapat menyimpan pesan baru.
ChatHistoryProvider memiliki berbagai metode virtual yang dapat ditimpa untuk mengimplementasikan penyedia riwayat kustom Anda sendiri.
Lihat berbagai opsi implementasi di bawah ini untuk informasi selengkapnya tentang apa yang perlu diganti.
ChatHistoryProvider Status
ChatHistoryProvider Instans diikatkan ke agen, dan instans yang sama akan digunakan untuk semua sesi.
Ini berarti bahwa ChatHistoryProvider tidak boleh menyimpan status spesifik sesi apa pun dalam instans penyedia.
ChatHistoryProvider mungkin memiliki referensi ke klien database dalam bidang, tetapi seharusnya tidak memiliki kunci database untuk riwayat obrolan dalam bidang.
Sebaliknya ChatHistoryProvider dapat menyimpan nilai spesifik sesi apa pun, seperti kunci database, pesan, atau hal lain yang relevan dalam AgentSession itu sendiri. Semua metode virtual diteruskan sebagai referensi ke ChatHistoryProvider dan AIAgent saat ini.
Untuk mengaktifkan penyimpanan status yang di ketik dengan mudah di AgentSessionkelas utilitas disediakan:
// 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);
Implementasi sederhana ChatHistoryProvider
Implementasi paling ChatHistoryProvider sederhana biasanya akan mengambil alih dua metode:
- ChatHistoryProvider.ProvideChatHistoryAsync - Muat riwayat obrolan yang relevan dan kembalikan pesan yang dimuat.
- ChatHistoryProvider.StoreChatHistoryAsync - Pesan permintaan dan respons toko, yang semuanya harus baru.
Berikut adalah contoh sederhana ChatHistoryProvider yang menyimpan riwayat obrolan langsung dalam status sesi.
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; } = [];
}
}
Implementasi tingkat lanjut ChatHistoryProvider
Implementasi yang lebih canggih dapat memilih untuk mengambil alih metode berikut:
- ChatHistoryProvider.InvokingCoreAsync - Dipanggil sebelum agen mengaktifkan LLM dan memungkinkan modifikasi daftar pesan permintaan.
- ChatHistoryProvider.InvokedCoreAsync - Dipanggil setelah agen melakukan pemanggilan ke LLM dan memungkinkan akses terhadap semua pesan permintaan dan respons.
ChatHistoryProvider menyediakan implementasi dasar untuk InvokingCoreAsync dan InvokedCoreAsync.
Implementasi InvokingCoreAsync dasar melakukan hal berikut:
- Memanggil
ProvideChatHistoryAsyncuntuk mendapatkan pesan yang harus digunakan sebagai riwayat obrolan untuk sesi - menjalankan filter
FuncprovideOutputMessageFilteropsional pada pesan yang dikembalikan olehProvideChatHistoryAsync. FilterFuncini dapat disediakan melaluiChatHistoryProviderkonstruktor. - menggabungkan pesan-pesan yang telah difilter, yang dikembalikan oleh
ProvideChatHistoryAsync, dengan pesan-pesan yang diteruskan ke dalam agen oleh pemanggil, untuk menghasilkan pesan permintaan agen. Riwayat obrolan ditambahkan di awal pesan masuk agen. - stempel semua pesan yang difilter yang dikembalikan oleh
ProvideChatHistoryAsyncdengan informasi sumber, menunjukkan bahwa pesan ini berasal dari riwayat obrolan.
Basis InvokedCoreAsync melakukan hal berikut:
- memeriksa apakah eksekusi gagal dan jika demikian, kembali tanpa melakukan pemrosesan lebih lanjut.
- memfilter pesan permintaan agen untuk mengecualikan pesan yang dihasilkan oleh
ChatHistoryProvider, karena kami hanya ingin menyimpan pesan baru dan bukan pesan yang diproduksi olehChatHistoryProviderdi tempat pertama. Perhatikan bahwa filter ini dapat digantikan melalui parameterstoreInputMessageFilterpada konstruktorChatHistoryProvider. - meneruskan pesan permintaan yang difilter dan semua pesan respons ke
StoreChatHistoryAsyncuntuk penyimpanan.
Dimungkinkan untuk mengganti metode ini untuk mengimplementasikan ChatHistoryProvider, namun ini membutuhkan pelaksana untuk mengimplementasikan fungsi dasar tersebut sendiri sesuai kebutuhan.
Berikut adalah contoh implementasi seperti itu.
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; } = [];
}
}
- Di Python, hanya satu penyedia riwayat yang harus menggunakan
load_messages=True.
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)
Mempertahankan sesi selama memulai ulang
Pertahankan teks lengkap AgentSession, tidak hanya pesan.
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)
Penting
Perlakukan AgentSession sebagai objek status buram dan pulihkan dengan konfigurasi agen/penyedia yang sama yang membuatnya.
Petunjuk / Saran
Gunakan penyedia riwayat audit/eval tambahan (load_messages=False, store_context_messages=True) untuk menangkap konteks yang diperkaya ditambah input/output tanpa memengaruhi pemuatan riwayat utama.