Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Körningskontext ger mellanprogram åtkomst till information om den aktuella körningsmiljön och begäran. Detta möjliggör mönster som konfiguration per session, användarspecifikt beteende och dynamiskt mellanprogramsbeteende baserat på körningsvillkor.
I C#flödar körningskontexten genom tre huvudytor:
-
AgentRunOptions.AdditionalPropertiesför nyckelvärdesmetadata per körning som mellanprogram och verktyg kan läsa. -
FunctionInvocationContextför att inspektera och ändra verktygsanropsargument i funktionsanropsmellanprogram. -
AgentSession.StateBagför delat tillstånd som bevaras mellan körningar i en konversation.
Använd den smalaste ytan som passar. Metadata per körning hör hemma i AdditionalProperties, beständiga konversationstillstånd hör hemma i sessionens , och verktygsargumentmanipulering StateBaghör hemma i funktionsanropsmellanprogram.
Tips/Råd
Mer information om hur mellanprogramsomfånget påverkar åtkomsten till körningskontext finns på sidan Agent kontra Körningsomfång .
Välj rätt körningsyta
| Användningsfall | API-yta | Nås från |
|---|---|---|
| Dela konversationstillstånd eller data mellan körningar | AgentSession.StateBag |
session.StateBag i kör mellanprogram, AIAgent.CurrentRunContext?.Session i verktyg |
| Skicka metadata per körning till mellanprogram eller verktyg | AgentRunOptions.AdditionalProperties |
options.AdditionalProperties i kör mellanprogram, AIAgent.CurrentRunContext?.RunOptions i verktyg |
| Granska eller ändra argument för verktygsanrop i mellanprogram | FunctionInvocationContext |
Återanrop av funktionsanrop för mellanprogram |
Skicka per körningsvärden via AgentRunOptions
Använd AdditionalProperties på AgentRunOptions för att koppla nyckelvärdesdata per körning. Funktionsanrop mellanprogram kan vidarebefordra dessa värden till verktygsargument.
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);
Varning
DefaultAzureCredential är praktiskt för utveckling men kräver noggrant övervägande i produktion. I produktion bör du överväga att använda en specifik autentiseringsuppgift (t.ex. ManagedIdentityCredential) för att undvika problem med svarstid, oavsiktlig avsökning av autentiseringsuppgifter och potentiella säkerhetsrisker från reservmekanismer.
Mellanprogrammet läser per körningsvärden från AgentRunOptions.AdditionalProperties omgivningen AIAgent.CurrentRunContext och matar in dem i verktygets FunctionInvocationContext.Arguments innan verktyget körs.
Funktionsanropsmellanprogram tar emot kontext
Funktionsanrop mellanprogram använder FunctionInvocationContext för att inspektera eller ändra verktygsargument, fånga upp resultat eller hoppa över verktygskörning helt.
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();
Mellanprogrammet tar emot funktionsanropskontexten och anropar next för att fortsätta pipelinen. Mutera context.Arguments innan du anropar nextoch verktyget ser de uppdaterade värdena.
Använd AgentSession.StateBag för tillstånd för delad körning
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"));
Skicka sessionen explicit med session: och få åtkomst till den från verktyg via AIAgent.CurrentRunContext?.Session. Tillhandahåller StateBag typsäker, trådsäker lagring som bevaras mellan körningar inom samma session.
Dela sessionstillstånd mellan mellanprogram och verktyg
Kör mellanprogram kan läsa och skriva sessionens StateBag, och alla ändringar är synliga för funktionsanrop mellanprogram och verktyg som körs i samma begäran.
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"));
Kör mellanprogram tar emot sessionen direkt som en parameter. Använd StateBag.SetValue och GetValue för typsäker åtkomst. Alla värden som lagras under körningsfasen för mellanprogram är tillgängliga för verktyg och funktionsanrop mellanprogram via AIAgent.CurrentRunContext?.Session.
Python-körningskontexten delas upp på tre offentliga ytor:
-
session=för konversationstillstånd och historik. -
function_invocation_kwargs=för värden som endast verktyg eller funktionsmellanprogram ska se. -
client_kwargs=för konfiguration av chattklientspecifika data eller klientmellanprogram.
Använd den minsta ytan som passar data. Detta håller verktygsindata explicita och undviker att läcka enbart klientmetadata till verktygskörning.
Tips/Råd
Behandla function_invocation_kwargs som ersättning för det gamla mönstret för att skicka godtyckliga offentliga **kwargs till agent.run() eller get_response().
Välj rätt körningshink
| Användningsfall | API-yta | Nås från |
|---|---|---|
| Dela konversationstillstånd, tjänstsessions-ID eller historik | session= |
ctx.session, AgentContext.session |
| Endast verktyg eller funktionsmellanprogram behöver passera körningsvärden | function_invocation_kwargs= |
FunctionInvocationContext.kwargs |
| Skicka klientspecifika körningsvärden eller konfiguration av mellanprogram för klienten | client_kwargs= |
anpassade get_response(..., client_kwargs=...) implementeringar |
Skicka körningsvärden endast för verktyg
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)
Använd ctx.kwargs inuti verktyget i stället för att deklarera filten **kwargs på verktyget som kan anropas. Äldre **kwargs verktyg fungerar fortfarande för kompatibilitet, men tas bort före ga.
Alla parametrar som kommenteras som FunctionInvocationContext behandlas som den inmatade körningskontextparametern, oavsett namn, och den exponeras inte i JSON-schemat som visas för modellen. Om du anger en explicit schema-/indatamodell identifieras även en oannoterad parameter med namnet ctx som den inmatade kontextparametern.
Om värdet är ett långvarigt verktygstillstånd eller ett beroende i stället för data per anrop behåller du det på en verktygsklassinstans i stället för att skicka det via function_invocation_kwargs. Det här mönstret finns i Skapa en klass med flera funktionsverktyg.
Funktionens mellanprogram tar emot samma kontext
Funktionens mellanprogram använder samma FunctionInvocationContext objekt som verktygen tar emot. Det innebär att mellanprogram kan inspektera context.arguments, context.kwargs, context.sessionoch context.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],
)
Mellanprogramskontraktet använder call_next() utan argument. Mutera context.kwargs innan du anropar det, och det valda verktyget ser dessa värden genom dess inmatade FunctionInvocationContext.
Använd session= för tillstånd för delad körning
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"])
Skicka sessionen explicit med session= och läs den från ctx.session. Sessionsåtkomst behöver inte längre färdas via runtime kwargs.
Dela sessionstillstånd med delegerade agenter
När en agent exponeras som ett verktyg via as_tool()flödar runtime-funktionen kwargs redan genom ctx.kwargs. Lägg bara till propagate_session=True när underagenten ska dela anroparens 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,
)
Med propagate_session=Trueser den delegerade agenten samma ctx.session tillstånd som anroparen. Låt den False isolera den underordnade agenten i sin egen session.
Anpassade chattklienter och agenter
Om du implementerar anpassade offentliga run() eller get_response() metoder lägger du till explicita körnings bucketar i signaturen.
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,
):
...
Används function_invocation_kwargs för verktygsanropsflöden och client_kwargs för klientspecifikt beteende. Att skicka klientspecifika värden direkt via offentlig **kwargs är bara en kompatibilitetssökväg och bör behandlas som inaktuell. På samma sätt är definitionen av nya verktyg med **kwargs kompatibilitet endast för migrering – förbruka körningsdata via det inmatade kontextobjektet i stället.