Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Os fornecedores de contexto correm em torno de cada invocação para adicionar contexto antes da execução e processar os dados após a execução.
Padrão incorporado
Configure fornecedores utilizando opções do construtor ao criar um agente.
AIContextProvider é o ponto de extensão incorporado para enriquecimento de memória/contexto.
AIAgent agent = new OpenAIClient("<your_api_key>")
.GetChatClient(modelName)
.AsAIAgent(new ChatClientAgentOptions()
{
ChatOptions = new() { Instructions = "You are a helpful assistant." },
AIContextProviders = [
new MyCustomMemoryProvider()
],
});
AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("Remember my name is Alice.", session));
Sugestão
Para uma lista de implementações pré-construídas AIContextProvider , veja Integrações
O padrão habitual é configurar os provedores através de context_providers=[...] ao criar um agente.
InMemoryHistoryProvider é o fornecedor de histórico incorporado utilizado para memória conversacional local.
from agent_framework import InMemoryHistoryProvider
from agent_framework.openai import OpenAIChatClient
agent = OpenAIChatClient().as_agent(
name="MemoryBot",
instructions="You are a helpful assistant.",
context_providers=[InMemoryHistoryProvider("memory", load_messages=True)],
)
session = agent.create_session()
await agent.run("Remember that I prefer vegetarian food.", session=session)
RawAgent pode adicionar InMemoryHistoryProvider("memory") automaticamente em casos específicos, mas adicioná-lo explicitamente quando quiser um comportamento local determinístico na memória.
Fornecedor de contexto personalizado
Usa fornecedores de contexto personalizados quando precisares de injetar instruções/mensagens/ferramentas dinâmicas ou extrair estado após as execuções.
A classe base para os fornecedores de contexto é Microsoft.Agents.AI.AIContextProvider.
Os fornecedores de contexto participam no pipeline do agente, têm a capacidade de contribuir ou substituir mensagens de entrada do agente e podem extrair informações de novas mensagens.
AIContextProvider tem vários métodos virtuais que podem ser ultrapassados para implementar o seu próprio fornecedor de contexto personalizado.
Para mais informações sobre o que deve substituir, consulte as diferentes opções de implementação abaixo.
AIContextProvider Estado
Uma AIContextProvider instância está associada a um agente e a mesma instância seria usada para todas as sessões.
Isto significa que o AIContextProvider não deve armazenar nenhum estado específico da sessão na instância do fornecedor.
O AIContextProvider pode ter uma referência a um cliente do serviço de memória num campo, mas não deve ter um id para o conjunto específico de memórias num campo.
Em vez disso, o AIContextProvider pode armazenar quaisquer valores específicos da sessão, como IDs de memória, mensagens ou qualquer outra coisa relevante no AgentSession. Os métodos virtuais em AIContextProvider recebem todos uma referência ao atual AIAgent e AgentSession.
Para permitir o armazenamento fácil do estado tipado no AgentSession, é fornecida uma classe utilitária:
// First define a type containing the properties to store in state
internal class MyCustomState
{
public string? MemoryId { get; set; }
}
// Create the helper
var sessionStateHelper = new ProviderSessionState<MyCustomState>(
// stateInitializer is called when there is no state in the session for this AIContextProvider yet
stateInitializer: currentSession => new MyCustomState() { MemoryId = 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.MemoryId);
// And write state:
sessionStateHelper.SaveState(session, state);
Implementação simples AIContextProvider
A implementação AIContextProvider mais simples normalmente sobrepõe dois métodos:
- AIContextProvider.ProvideAIContextAsync - Carregar dados relevantes e devolver instruções, mensagens ou ferramentas adicionais.
- AIContextProvider.StoreAIContextAsync - Extrair quaisquer dados relevantes de novas mensagens e armazenar.
Aqui está um exemplo de um simples AIContextProvider que se integra com um serviço de memória.
internal sealed class SimpleServiceMemoryProvider : AIContextProvider
{
private readonly ProviderSessionState<State> _sessionState;
private readonly ServiceClient _client;
public SimpleServiceMemoryProvider(ServiceClient client, Func<AgentSession?, State>? stateInitializer = null)
: base(null, null)
{
this._sessionState = new ProviderSessionState<State>(
stateInitializer ?? (_ => new State()),
this.GetType().Name);
this._client = client;
}
public override string StateKey => this._sessionState.StateKey;
protected override ValueTask<AIContext> ProvideAIContextAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
var state = this._sessionState.GetOrInitializeState(context.Session);
if (state.MemoriesId == null)
{
// No stored memories yet.
return new ValueTask<AIContext>(new AIContext());
}
// Find memories that match the current user input.
var memories = this._client.LoadMemories(state.MemoriesId, string.Join("\n", context.AIContext.Messages?.Select(x => x.Text) ?? []));
// Return a new message that contains the text from any memories that were found.
return new ValueTask<AIContext>(new AIContext
{
Messages = [new ChatMessage(ChatRole.User, "Here are some memories to help answer the user question: " + string.Join("\n", memories.Select(x => x.Text)))]
});
}
protected override async ValueTask StoreAIContextAsync(InvokedContext context, CancellationToken cancellationToken = default)
{
var state = this._sessionState.GetOrInitializeState(context.Session);
// Create a memory container in the service for this session
// and save the returned id in the session.
state.MemoriesId ??= this._client.CreateMemoryContainer();
this._sessionState.SaveState(context.Session, state);
// Use the service to extract memories from the user input and agent response.
await this._client.StoreMemoriesAsync(state.MemoriesId, context.RequestMessages.Concat(context.ResponseMessages ?? []), cancellationToken);
}
public class State
{
public string? MemoriesId { get; set; }
}
}
Implementação avançada AIContextProvider
Uma implementação mais avançada poderia optar por sobrepor os seguintes métodos:
- AIContextProvider.InvokingCoreAsync - Chamado antes do agente invocar o LLM e permitir a modificação da lista de mensagens de pedido, ferramentas e instruções.
- AIContextProvider.InvokedCoreAsync - Chamado depois de o agente ter invocado o LLM e permite o acesso a todas as mensagens de pedido e resposta.
AIContextProvider fornece implementações base de InvokingCoreAsync e InvokedCoreAsync.
A InvokingCoreAsync implementação base faz o seguinte:
- Filtra a lista de mensagens de entrada apenas para mensagens passadas ao agente pelo chamador. Note que este filtro pode ser sobreposto pelo parâmetro
provideInputMessageFilterno construtorAIContextProvider. - chamadas
ProvideAIContextAsynccom as mensagens de pedido filtradas, ferramentas e instruções existentes. - carimba todas as mensagens devolvidas por
ProvideAIContextAsynccom informação de origem, indicando que estas mensagens provêm deste fornecedor de contexto. - funde as mensagens, ferramentas e instruções devolvidas por
ProvideAIContextAsynccom as existentes, para produzir a entrada que será usada pelo agente. Mensagens, ferramentas e instruções são adicionadas às existentes.
A InvokedCoreAsync base faz o seguinte:
- verifica se a execução falhou e, em caso afirmativo, retorna sem fazer mais nenhum processamento.
- Filtra a lista de mensagens de entrada apenas para mensagens passadas ao agente pelo chamador. Note que este filtro pode ser substituído através do parâmetro
storeInputMessageFilterno construtorAIContextProvider. - Passa as mensagens de pedido filtradas e todas as mensagens de resposta para
StoreAIContextAsyncarmazenamento.
É possível sobrepor estes métodos para implementar um AIContextProvider, no entanto, isso requer que o implementador realize ele mesmo a funcionalidade base de forma apropriada.
Aqui está um exemplo de tal implementação.
internal sealed class AdvancedServiceMemoryProvider : AIContextProvider
{
private readonly ProviderSessionState<State> _sessionState;
private readonly ServiceClient _client;
public AdvancedServiceMemoryProvider(ServiceClient client, Func<AgentSession?, State>? stateInitializer = null)
: base(null, null)
{
this._sessionState = new ProviderSessionState<State>(
stateInitializer ?? (_ => new State()),
this.GetType().Name);
this._client = client;
}
public override string StateKey => this._sessionState.StateKey;
protected override async ValueTask<AIContext> InvokingCoreAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
var state = this._sessionState.GetOrInitializeState(context.Session);
if (state.MemoriesId == null)
{
// No stored memories yet.
return new AIContext();
}
// We only want to search for memories based on user input, and exclude chat history or other AI context provider messages.
var filteredInputMessages = context.AIContext.Messages?.Where(m => m.GetAgentRequestMessageSourceType() == AgentRequestMessageSourceType.External);
// Find memories that match the current user input.
var memories = this._client.LoadMemories(state.MemoriesId, string.Join("\n", filteredInputMessages?.Select(x => x.Text) ?? []));
// Create a message for the memories, and stamp it to indicate where it came from.
var memoryMessages =
[new ChatMessage(ChatRole.User, "Here are some memories to help answer the user question: " + string.Join("\n", memories.Select(x => x.Text)))]
.Select(m => m.WithAgentRequestMessageSource(AgentRequestMessageSourceType.AIContextProvider, this.GetType().FullName!));
// Return a new merged AIContext.
return new AIContext
{
Instructions = context.AIContext.Instructions,
Messages = context.AIContext.Messages.Concat(memoryMessages),
Tools = context.AIContext.Tools
};
}
protected override async ValueTask InvokedCoreAsync(InvokedContext context, CancellationToken cancellationToken = default)
{
if (context.InvokeException is not null)
{
return;
}
var state = this._sessionState.GetOrInitializeState(context.Session);
// Create a memory container in the service for this session
// and save the returned id in the session.
state.MemoriesId ??= this._client.CreateMemoryContainer();
this._sessionState.SaveState(context.Session, state);
// We only want to store memories based on user input and agent output, and exclude messages from chat history or other AI context providers to avoid feedback loops.
var filteredRequestMessages = context.RequestMessages.Where(m => m.GetAgentRequestMessageSourceType() == AgentRequestMessageSourceType.External);
// Use the service to extract memories from the user input and agent response.
await this._client.StoreMemoriesAsync(state.MemoriesId, filteredRequestMessages.Concat(context.ResponseMessages ?? []), cancellationToken);
}
public class State
{
public string? MemoriesId { get; set; }
}
}
from typing import Any
from agent_framework import AgentSession, BaseContextProvider, SessionContext
class UserPreferenceProvider(BaseContextProvider):
def __init__(self) -> None:
super().__init__("user-preferences")
async def before_run(
self,
*,
agent: Any,
session: AgentSession,
context: SessionContext,
state: dict[str, Any],
) -> None:
if favorite := state.get("favorite_food"):
context.extend_instructions(self.source_id, f"User's favorite food is {favorite}.")
async def after_run(
self,
*,
agent: Any,
session: AgentSession,
context: SessionContext,
state: dict[str, Any],
) -> None:
for message in context.input_messages:
text = (message.text or "") if hasattr(message, "text") else ""
if isinstance(text, str) and "favorite food is" in text.lower():
state["favorite_food"] = text.split("favorite food is", 1)[1].strip().rstrip(".")
Fornecedor de histórico personalizado
Os fornecedores de histórico são fornecedores de contexto especializados para carregar/armazenar mensagens.
from collections.abc import Sequence
from typing import Any
from agent_framework import BaseHistoryProvider, Message
class DatabaseHistoryProvider(BaseHistoryProvider):
def __init__(self, db: Any) -> None:
super().__init__("db-history", load_messages=True)
self._db = db
async def get_messages(
self,
session_id: str | None,
*,
state: dict[str, Any] | None = None,
**kwargs: Any,
) -> list[Message]:
key = (state or {}).get(self.source_id, {}).get("history_key", session_id or "default")
rows = await self._db.load_messages(key)
return [Message.from_dict(row) for row in rows]
async def save_messages(
self,
session_id: str | None,
messages: Sequence[Message],
*,
state: dict[str, Any] | None = None,
**kwargs: Any,
) -> None:
if not messages:
return
if state is not None:
key = state.setdefault(self.source_id, {}).setdefault("history_key", session_id or "default")
else:
key = session_id or "default"
await self._db.save_messages(key, [m.to_dict() for m in messages])
Importante
Em Python, podes configurar vários fornecedores de histórico, mas só um deve usar load_messages=True.
Utilize prestadores adicionais para diagnósticos/avaliações com load_messages=False e store_context_messages=True para que capturem o contexto de outros prestadores em conjunto com a entrada/saída.
Exemplo de padrão:
primary = DatabaseHistoryProvider(db)
audit = InMemoryHistoryProvider("audit", load_messages=False, store_context_messages=True)
agent = OpenAIChatClient().as_agent(context_providers=[primary, audit])
Próximos passos
Armazenamento