Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O contexto de runtime fornece ao middleware acesso a informações sobre o ambiente de execução e a solicitação atuais. Isso permite padrões como configuração por sessão, comportamento específico do usuário e comportamento de middleware dinâmico com base em condições de runtime.
No C#, o contexto de runtime flui por três superfícies principais:
-
AgentRunOptions.AdditionalPropertiespara metadados chave-valor por execução que middleware e ferramentas podem ler. -
FunctionInvocationContextpara inspecionar e modificar argumentos de chamada de ferramenta dentro do middleware de invocação de função. -
AgentSession.StateBagpara o estado compartilhado que persiste entre execuções dentro de uma conversa.
Use a superfície mais estreita que se ajusta. Os metadados por execução pertencem, AdditionalPropertieso estado de conversa persistente pertence à sessão StateBage a manipulação de argumento de ferramenta pertence ao middleware de invocação de função.
Dica
Consulte a página Agente vs Executar Escopo para obter informações sobre como o escopo do middleware afeta o acesso ao contexto de runtime.
Escolha a superfície de runtime certa
| Caso de uso | Superfície da API | Acessado a partir de |
|---|---|---|
| Compartilhar o estado ou os dados da conversa entre execuções | AgentSession.StateBag |
session.StateBag no middleware de execução, AIAgent.CurrentRunContext?.Session em ferramentas |
| Passar metadados por execução para middleware ou ferramentas | AgentRunOptions.AdditionalProperties |
options.AdditionalProperties no middleware de execução, AIAgent.CurrentRunContext?.RunOptions em ferramentas |
| Inspecionar ou modificar argumentos de chamada de ferramenta no middleware | FunctionInvocationContext |
Retorno de chamada de middleware de invocação de função |
Passar valores por execução por meio de AgentRunOptions
AgentRunOptions Use AdditionalProperties para anexar dados chave-valor por execução. O middleware de invocação de função pode encaminhar esses valores para argumentos de ferramenta.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
[Description("Send an email to the specified address.")]
static string SendEmail(
[Description("Recipient email address.")] string address,
[Description("User ID of the sender.")] string userId,
[Description("Tenant name.")] string tenant = "default")
{
return $"Queued email for {address} from {userId} ({tenant})";
}
// Function invocation middleware that injects per-run values into tool arguments
async ValueTask<object?> InjectRunContext(
AIAgent agent,
FunctionInvocationContext context,
Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next,
CancellationToken cancellationToken)
{
var runOptions = AIAgent.CurrentRunContext?.RunOptions;
if (runOptions?.AdditionalProperties is { } props)
{
if (props.TryGetValue("user_id", out var userId))
{
context.Arguments["userId"] = userId;
}
if (props.TryGetValue("tenant", out var tenant))
{
context.Arguments["tenant"] = tenant;
}
}
return await next(context, cancellationToken);
}
AIAgent baseAgent = new AIProjectClient(
new Uri("<your-foundry-project-endpoint>"),
new DefaultAzureCredential())
.AsAIAgent(
model: "gpt-4o-mini",
instructions: "Send email updates.",
tools: [AIFunctionFactory.Create(SendEmail)]);
var agent = baseAgent
.AsBuilder()
.Use(InjectRunContext)
.Build();
var response = await agent.RunAsync(
"Email the launch update to finance@example.com",
options: new AgentRunOptions
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
["user_id"] = "user-123",
["tenant"] = "contoso",
}
});
Console.WriteLine(response);
Aviso
DefaultAzureCredential é conveniente para o desenvolvimento, mas requer uma consideração cuidadosa na produção. Em produção, considere o uso de uma credencial específica (por exemplo, ManagedIdentityCredential) para evitar problemas de latência, investigação de credenciais não intencionais e possíveis riscos de segurança de mecanismos de fallback.
O middleware lê valores AgentRunOptions.AdditionalProperties por execução por meio do ambiente AIAgent.CurrentRunContext e os injeta na ferramenta antes da execução da FunctionInvocationContext.Arguments ferramenta.
O middleware de invocação de função recebe contexto
O middleware de invocação de função usa FunctionInvocationContext para inspecionar ou modificar argumentos de ferramenta, interceptar resultados ou ignorar totalmente a execução da ferramenta.
using System;
using System.Threading;
using System.Threading.Tasks;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
async ValueTask<object?> EnrichToolContext(
AIAgent agent,
FunctionInvocationContext context,
Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next,
CancellationToken cancellationToken)
{
if (!context.Arguments.ContainsKey("tenant"))
{
context.Arguments["tenant"] = "contoso";
}
if (!context.Arguments.ContainsKey("requestSource"))
{
context.Arguments["requestSource"] = "middleware";
}
return await next(context, cancellationToken);
}
AIAgent baseAgent = new AIProjectClient(
new Uri("<your-foundry-project-endpoint>"),
new DefaultAzureCredential())
.AsAIAgent(
model: "gpt-4o-mini",
instructions: "Send email updates.",
tools: [AIFunctionFactory.Create(SendEmail)]);
var agent = baseAgent
.AsBuilder()
.Use(EnrichToolContext)
.Build();
O middleware recebe o contexto de invocação de função e chama next para continuar o pipeline. Mutar context.Arguments antes de chamar nexte a ferramenta verá os valores atualizados.
Usar AgentSession.StateBag para o estado de runtime compartilhado
using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
[Description("Store the specified topic in session state.")]
static string RememberTopic(
[Description("Topic to remember.")] string topic)
{
var session = AIAgent.CurrentRunContext?.Session;
if (session is null)
{
return "No session available.";
}
session.StateBag.SetValue("topic", topic);
return $"Stored '{topic}' in session state.";
}
AIAgent agent = new AIProjectClient(
new Uri("<your-foundry-project-endpoint>"),
new DefaultAzureCredential())
.AsAIAgent(
model: "gpt-4o-mini",
instructions: "Remember important topics.",
tools: [AIFunctionFactory.Create(RememberTopic)]);
var session = await agent.CreateSessionAsync();
await agent.RunAsync("Remember that the budget review is on Friday.", session: session);
Console.WriteLine(session.StateBag.GetValue<string>("topic"));
Passe a sessão explicitamente e session: acesse-a das ferramentas por meio AIAgent.CurrentRunContext?.Sessionde . O StateBag fornece armazenamento com segurança de tipo e thread que persiste entre execuções na mesma sessão.
Compartilhar o estado da sessão entre middleware e ferramentas
O middleware de execução pode ler e gravar a sessão StateBage todas as alterações ficam visíveis para o middleware de invocação de função e as ferramentas em execução na mesma solicitação.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
// Run middleware that stamps the session with request metadata
async Task<AgentResponse> StampRequestMetadata(
IEnumerable<ChatMessage> messages,
AgentSession? session,
AgentRunOptions? options,
AIAgent innerAgent,
CancellationToken cancellationToken)
{
if (session is not null && options?.AdditionalProperties is { } props)
{
if (props.TryGetValue("request_id", out var requestId))
{
session.StateBag.SetValue("requestId", requestId?.ToString());
}
}
return await innerAgent.RunAsync(messages, session, options, cancellationToken);
}
AIAgent baseAgent = new AIProjectClient(
new Uri("<your-foundry-project-endpoint>"),
new DefaultAzureCredential())
.AsAIAgent(
model: "gpt-4o-mini",
instructions: "You are a helpful assistant.");
var agent = baseAgent
.AsBuilder()
.Use(runFunc: StampRequestMetadata, runStreamingFunc: null)
.Build();
var session = await agent.CreateSessionAsync();
await agent.RunAsync(
"Hello!",
session: session,
options: new AgentRunOptions
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
["request_id"] = "req-abc-123",
}
});
Console.WriteLine(session.StateBag.GetValue<string>("requestId"));
O middleware de execução recebe a sessão diretamente como um parâmetro. Use StateBag.SetValue e GetValue para acesso com segurança de tipo. Todos os valores armazenados durante a fase de middleware de execução estão disponíveis para ferramentas e middleware de invocação de função por meio de AIAgent.CurrentRunContext?.Session.
O contexto de runtime do Python é dividido entre três superfícies públicas:
-
session=para o estado e o histórico da conversa. -
function_invocation_kwargs=para valores que somente ferramentas ou middleware de função devem ver. -
client_kwargs=para dados específicos do cliente de chat ou configuração de middleware do cliente.
Use a menor superfície que se ajusta aos dados. Isso mantém as entradas da ferramenta explícitas e evita o vazamento de metadados somente do cliente na execução da ferramenta.
Dica
Trate function_invocation_kwargs como a substituição do antigo padrão de passar público **kwargs arbitrário para agent.run() ou get_response().
Escolher o bucket de runtime certo
| Caso de uso | Superfície da API | Acessado a partir de |
|---|---|---|
| Compartilhar estado da conversa, IDs de sessão de serviço ou histórico | session= |
ctx.session, AgentContext.session |
| Passar valores de runtime somente ferramentas ou middleware de função precisa | function_invocation_kwargs= |
FunctionInvocationContext.kwargs |
| Passar valores de runtime específicos do cliente ou configuração de middleware do cliente | client_kwargs= |
implementações personalizadas get_response(..., client_kwargs=...) |
Passar valores de runtime somente para ferramentas
from typing import Annotated
from agent_framework import FunctionInvocationContext, tool
from agent_framework.openai import OpenAIChatClient
@tool(approval_mode="never_require")
def send_email(
address: Annotated[str, "Recipient email address."],
ctx: FunctionInvocationContext,
) -> str:
user_id = ctx.kwargs["user_id"]
tenant = ctx.kwargs.get("tenant", "default")
return f"Queued email for {address} from {user_id} ({tenant})"
agent = OpenAIChatClient().as_agent(
name="Notifier",
instructions="Send email updates.",
tools=[send_email],
)
response = await agent.run(
"Email the launch update to finance@example.com",
function_invocation_kwargs={
"user_id": "user-123",
"tenant": "contoso",
},
)
print(response.text)
Use ctx.kwargs dentro da ferramenta em vez de declarar o cobertor **kwargs na ferramenta que pode ser chamada. As ferramentas herdadas **kwargs ainda funcionam para compatibilidade, mas serão removidas antes da GA.
Qualquer parâmetro anotado como FunctionInvocationContext é tratado como o parâmetro de contexto de runtime injetado, independentemente de seu nome, e não é exposto no esquema JSON mostrado ao modelo. Se você fornecer um modelo de esquema/entrada explícito, um parâmetro sem anotação simples nomeado ctx também será reconhecido como o parâmetro de contexto injetado.
Se o valor for um estado de ferramenta de longa duração ou uma dependência em vez de dados por invocação, mantenha-o em uma instância de classe de ferramenta em vez de passá-lo.function_invocation_kwargs Para esse padrão, consulte Criar uma classe com várias ferramentas de função.
O middleware de função recebe o mesmo contexto
O middleware de função usa o mesmo FunctionInvocationContext objeto que as ferramentas recebem. Isso significa que o middleware pode inspecionarcontext.arguments, context.kwargse context.sessioncontext.result.
from collections.abc import Awaitable, Callable
from agent_framework import FunctionInvocationContext
from agent_framework.openai import OpenAIChatClient
async def enrich_tool_runtime_context(
context: FunctionInvocationContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
context.kwargs.setdefault("tenant", "contoso")
context.kwargs.setdefault("request_source", "middleware")
await call_next()
agent = OpenAIChatClient().as_agent(
name="Notifier",
instructions="Send email updates.",
tools=[send_email],
middleware=[enrich_tool_runtime_context],
)
O contrato de middleware usa call_next() sem argumentos. Mutar context.kwargs antes de chamá-lo, e a ferramenta selecionada vê esses valores por meio de sua injeção FunctionInvocationContext.
Usar session= para o estado de runtime compartilhado
from typing import Annotated
from agent_framework import FunctionInvocationContext, tool
from agent_framework.openai import OpenAIChatClient
@tool(approval_mode="never_require")
def remember_topic(
topic: Annotated[str, "Topic to remember."],
ctx: FunctionInvocationContext,
) -> str:
if ctx.session is None:
return "No session available."
ctx.session.state["topic"] = topic
return f"Stored {topic!r} in session state."
agent = OpenAIChatClient().as_agent(
name="MemoryAgent",
instructions="Remember important topics.",
tools=[remember_topic],
)
session = agent.create_session()
await agent.run("Remember that the budget review is on Friday.", session=session)
print(session.state["topic"])
Passe a sessão explicitamente com session= e leia-a de ctx.session. O acesso à sessão não precisa mais percorrer kwargs de runtime.
Compartilhar o estado da sessão com agentes delegados
Quando um agente é exposto como uma ferramenta por meio as_tool()de kwargs de função de runtime que já fluem por ctx.kwargs. Adicione propagate_session=True somente quando o subagente deve compartilhar o chamador AgentSession.
from agent_framework import FunctionInvocationContext, tool
from agent_framework.openai import OpenAIChatClient
@tool(description="Store findings for later steps.")
def store_findings(findings: str, ctx: FunctionInvocationContext) -> None:
if ctx.session is not None:
ctx.session.state["findings"] = findings
client = OpenAIChatClient()
research_agent = client.as_agent(
name="ResearchAgent",
instructions="Research the topic and store findings.",
tools=[store_findings],
)
research_tool = research_agent.as_tool(
name="research",
description="Research a topic and store findings.",
arg_name="query",
propagate_session=True,
)
Com propagate_session=True, o agente delegado vê o mesmo ctx.session estado que o chamador. Deixe-o False isolar o agente filho em sua própria sessão.
Clientes e agentes de chat personalizados
Se você implementar métodos públicos run() ou get_response() personalizados, adicione os buckets de runtime explícitos à assinatura.
from collections.abc import Mapping, Sequence
from typing import Any
from agent_framework import ChatOptions, Message
async def get_response(
self,
messages: Sequence[Message],
*,
options: ChatOptions[Any] | None = None,
function_invocation_kwargs: Mapping[str, Any] | None = None,
client_kwargs: Mapping[str, Any] | None = None,
**kwargs: Any,
):
...
Use function_invocation_kwargs para fluxos de invocação de ferramentas e client_kwargs para comportamento específico do cliente. Passar valores específicos do cliente diretamente pelo público **kwargs é apenas um caminho de compatibilidade e deve ser tratado como preterido. Da mesma forma, definir novas ferramentas com **kwargs a compatibilidade somente migração é consumir dados de runtime por meio do objeto de contexto injetado.