Storage

Depolama, konuşma geçmişinin nerede yaşadığını, ne kadar geçmişin yüklendiğini ve oturumların ne kadar güvenilir bir şekilde sürdürülebileceğini denetler.

Yerleşik depolama modları

Agent Framework iki normal depolama modunu destekler:

Çalışma Modu Ne depolanır Tipik kullanım
Yerel oturum durumu AgentSession.state tam sohbet geçmişi (örneğin InMemoryHistoryProvider aracılığıyla) Sunucu tarafı konuşma kalıcılığı gerektirmeyen hizmetler
Hizmet tarafından yönetilen depolama Hizmetteki konuşma durumu; AgentSession.service_session_id ona işaret eder Yerel kalıcı konuşma desteğine sahip hizmetler

Bellek içi sohbet geçmişi depolama

Sağlayıcı sunucu tarafı sohbet geçmişi gerektirmediğinde, Agent Framework geçmişi oturumda yerel olarak tutar ve her çalıştırmada ilgili iletiler gönderir.

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)

Bellek içi geçmiş boyutunu küçültme

Geçmiş model sınırları için çok büyükse bir azaltıcı uygulayın.

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)
        })
    });

Uyarı

Azaltıcı yapılandırması bellek içi geçmiş sağlayıcıları için geçerlidir. Hizmet tarafından yönetilen geçmiş için azaltma davranışı sağlayıcıya/hizmete özgüdür.

Hizmet tarafından yönetilen depolama

Hizmet konuşma geçmişini yönettiğinde, oturum bir uzak konuşma tanımlayıcısı depolar.

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)

Hizmet çağrısı başına yerel geçmiş kalıcılığı

Bir araç çağırma işlemi, tek bir agent.run() tamamlanmadan önce birden fazla model çağrısı gerçekleştirebilir. Varsayılan olarak, yerel geçmiş sağlayıcıları tam çalıştırma sonrasında bir kez kalıcı olarak saklanır. Yerel geçmişin, hizmet tarafından yönetilen konuşmaları daha yakından yansıtmasını istiyorsanız, require_per_service_call_history_persistence=True ayarını yaparak geçmiş sağlayıcılarının her model çağrısının etrafında çalışmasını sağlayabilirsiniz.

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,
)

Önemli

Bu modu yalnızca çerçeveyle yönetilen yerel geçmiş için kullanın. Çalışma zaten hizmet tarafından yönetilen bir konuşmaya bağlıysa (örneğin session.service_session_id veya options={"conversation_id": ...} aracılığıyla), Agent Framework, iki kalıcılık modelini karıştırmak yerine bir hata oluşturur.

Bu mod, özellikle bir araç çağrısından hemen sonra ara yazılımın sonlandırılabildiği durumlarda kullanışlıdır: model çağrısı başına veri saklama, yerel geçmişi, hizmet tarafından yönetilen bir konuşmanın tutacağı şekilde uyumlu tutar.

Üçüncü taraf/Özel depolama düzeni

Veritabanı/Redis/blob destekli geçmiş için özel bir geçmiş sağlayıcısı uygulayın.

Temel kılavuz:

  • İletileri oturum kapsamı bir anahtar altında depolayın.
  • Döndürülen geçmişi model bağlam sınırları içinde tutun.
  • Sağlayıcıya özgü tanımlayıcıları oturum durumuna kaydedin.

Temel sınıf, geçmiş sağlayıcıları için Microsoft.Agents.AI.ChatHistoryProvider'dir. Geçmiş sağlayıcıları aracı işlem hattına katılır, aracı giriş iletilerine katkıda bulunabilir veya bu iletileri geçersiz kılabilir ve yeni iletileri depolayabilir. ChatHistoryProvider kendi özel geçmiş sağlayıcınızı uygulamak için geçersiz kılınabilecek çeşitli sanal yöntemlere sahiptir. Daha fazla bilgi için, neyin geçersiz kılınacağını anlamak amacıyla aşağıdaki farklı uygulama seçeneklerine bakın.

ChatHistoryProvider Durum

Bir ChatHistoryProvider örnek bir aracıya eklenir ve tüm oturumlar için aynı örnek kullanılır. Bu, sağlayıcı örneğinde ChatHistoryProvider oturuma özgü bir durum depolamaması gerektiği anlamına gelir. bir ChatHistoryProvider alandaki veritabanı istemcisine başvuru içerebilir, ancak bir alandaki sohbet geçmişi için veritabanı anahtarına sahip olmamalıdır.

Bunun yerine, ChatHistoryProvider veritabanı anahtarları, iletiler veya kendi içinde ilgili başka herhangi bir şey gibi oturuma AgentSession özgü değerleri depolayabilir. ChatHistoryProvider üzerindeki sanal yöntemlerin tümüne, geçerli AIAgent ve AgentSession için bir başvuru geçirilir.

Belirtilmiş türdeki durumu AgentSession içinde kolayca depolamak için bir yardımcı sınıf sağlanır.

// 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);

Basit ChatHistoryProvider uygulama

En basit ChatHistoryProvider uygulama genellikle iki yöntemi geçersiz kılar:

  • ChatHistoryProvider.ProvideChatHistoryAsync - İlgili sohbet geçmişini yükleyin ve yüklenen iletileri döndürin.
  • ChatHistoryProvider.StoreChatHistoryAsync - İstek ve yanıt iletilerini depolayın; bunların tümü yeni olmalıdır.

Burada, sohbet geçmişini doğrudan oturum durumunda depolayan basit ChatHistoryProvider bir örnek verilmiştir.

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; } = [];
    }
}

Gelişmiş ChatHistoryProvider uygulama

Daha gelişmiş bir uygulama aşağıdaki yöntemleri geçersiz kılmayı seçebilir:

  • ChatHistoryProvider.InvokingCoreAsync - Aracı LLM'yi çağırmadan önce çağrılır ve istek ileti listesinin değiştirilmesine izin verir.
  • ChatHistoryProvider.InvokedCoreAsync - Aracı LLM'yi çağırdıktan ve tüm istek ve yanıt iletilerine erişime izin verdikten sonra çağrılır.

ChatHistoryProvider, InvokingCoreAsync ve InvokedCoreAsync temel uygulamalarını sağlar.

InvokingCoreAsync Temel uygulama aşağıdakileri yapar:

  • çalıştırma için sohbet geçmişi olarak kullanılması gereken iletileri almak için ProvideChatHistoryAsync çağrılır
  • İletiler Func tarafından döndürüldüğünde, isteğe bağlı bir filtre provideOutputMessageFilterProvideChatHistoryAsync uygulanır. Bu filtre Func oluşturucu aracılığıyla ChatHistoryProvider sağlanabilir.
  • Bu işlem, ProvideChatHistoryAsync tarafından döndürülen filtrelenmiş iletileri, çağıran tarafından aracıya iletilen iletilerle birleştirerek aracı istek iletilerini oluşturur. Sohbet geçmişi aracı giriş iletilerine eklenir.
  • tarafından döndürülen ProvideChatHistoryAsync tüm filtrelenmiş iletileri kaynak bilgileriyle damgalar ve bu iletilerin sohbet geçmişinden geldiğini belirtir.

Temel InvokedCoreAsync aşağıdakileri yapar:

  • çalıştırmanın başarısız olup olmadığını denetler ve başarısız olursa, daha fazla işlem yapmadan döndürür.
  • aracı istek iletilerini, ilk etapta ChatHistoryProvider tarafından üretilenleri değil, yalnızca yeni iletileri depolamak istediğimizden, ChatHistoryProvider tarafından üretilen iletileri hariç tutacak şekilde filtreler. Bu filtrenin oluşturucudaki storeInputMessageFilterChatHistoryProvider parametresi aracılığıyla geçersiz kılınabileceğini unutmayın.
  • Filtrelenmiş istek iletilerini ve tüm yanıt iletilerini depolama için StoreChatHistoryAsync öğesine geçirir.

Bir ChatHistoryProvider uygulamak için bu yöntemleri geçersiz kılmak mümkündür, ancak bunun için uygulayanın temel işlevselliği uygun bir şekilde gerçekleştirmesi gerekir. Burada böyle bir uygulama örneği verilmiştir.

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; } = [];
    }
}
  • Python'da yalnızca bir geçmiş sağlayıcısı kullanmalıdır 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)

Yeniden başlatmalar arasında oturumların devamlılığı

Tam AgentSession öğesini, yalnızca ileti metni değil, kalıcı hale getirin.

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)

Önemli

AgentSession bir opak durum nesnesi olarak ele alın ve onu oluşturan aracı/sağlayıcı yapılandırmasıyla geri yükleyin.

Tip

Birincil geçmiş yüklemesini etkilemeden zenginleştirilmiş bağlam ve giriş/çıkış yakalamak için ek bir denetim/değerlendirme geçmişi sağlayıcısı (load_messages=False, store_context_messages=True) kullanın.

Sonraki Adımlar