Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Laufzeitkontext bietet Middleware Zugriff auf Informationen zur aktuellen Ausführungsumgebung und Anforderung. Dies ermöglicht Muster wie sitzungsspezifische Konfiguration, benutzerspezifisches Verhalten und dynamisches Middleware-Verhalten basierend auf Laufzeitbedingungen.
In C# fließt der Laufzeitkontext über drei Hauptoberflächen:
-
AgentRunOptions.AdditionalPropertiesfür schlüsselwertbasierte Metadaten, die Middleware und Tools lesen können. -
FunctionInvocationContextzum Überprüfen und Ändern von Toolaufrufargumenten innerhalb der Funktionsaufruf-Middleware. -
AgentSession.StateBagfür freigegebenen Zustand, der in einer Unterhaltung weiterhin ausgeführt wird.
Verwenden Sie die schmalste Oberfläche, die passt. Pro Ausführungsmetadaten gehören in AdditionalPropertiesden Zustand der beständigen Unterhaltung in die Sitzung StateBag, und die Toolargumentmanipulation gehört in Funktionsaufruf-Middleware.
Tipp
Informationen dazu, wie sich middleware-Bereich auf den Zugriff auf den Laufzeitkontext auswirkt, finden Sie auf der Seite "Agent vs Run Scope ".
Auswählen der richtigen Laufzeitoberfläche
| Anwendungsfall | API-Oberfläche | Zugriff von |
|---|---|---|
| Freigeben des Unterhaltungszustands oder der datenübergreifend ausgeführten Daten | AgentSession.StateBag |
session.StateBag in Der Middleware ausführen, AIAgent.CurrentRunContext?.Session in Tools |
| Übergeben von Metadaten pro Ausführung an Middleware oder Tools | AgentRunOptions.AdditionalProperties |
options.AdditionalProperties in Der Middleware ausführen, AIAgent.CurrentRunContext?.RunOptions in Tools |
| Überprüfen oder Ändern von Toolaufrufargumenten in Middleware | FunctionInvocationContext |
Rückruf von Middleware-Funktionen |
Übergeben von Werten pro Ausführung über AgentRunOptions
Verwenden Sie AdditionalProperties "On AgentRunOptions ", um Schlüsselwertdaten pro Ausführung anzufügen. Funktionsaufruf-Middleware kann diese Werte in Toolargumente weiterleiten.
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);
Warnung
DefaultAzureCredential ist praktisch für die Entwicklung, erfordert aber sorgfältige Überlegungen in der Produktion. Berücksichtigen Sie in der Produktion die Verwendung bestimmter Anmeldeinformationen (z. B. ManagedIdentityCredential), um Latenzprobleme, unbeabsichtigte Abfragen von Anmeldeinformationen und potenzielle Sicherheitsrisiken durch Ausweichmechanismen zu vermeiden.
Die Middleware liest Werte pro Ausführung über AgentRunOptions.AdditionalProperties die Umgebung AIAgent.CurrentRunContext und fügt sie in die Tool FunctionInvocationContext.Arguments ein, bevor das Tool ausgeführt wird.
Funktionsaufruf-Middleware empfängt Kontext
Funktionsaufruf-Middleware verwendet FunctionInvocationContext , um Toolargumente zu prüfen oder zu ändern, Ergebnisse abzufangen oder die Toolausführung vollständig zu überspringen.
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();
Die Middleware empfängt den Funktionsaufrufkontext und Aufrufe next , um die Pipeline fortzusetzen. Stummschalten context.Arguments vor dem Aufrufen next, und das Tool sieht die aktualisierten Werte.
Wird für den freigegebenen Laufzeitstatus verwendet AgentSession.StateBag
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"));
Übergeben Sie die Sitzung explizit mit session: den Tools, und greifen Sie über die Tools AIAgent.CurrentRunContext?.Sessiondarauf zu. Dies StateBag bietet typsicheren, threadsicheren Speicher, der während der Ausführung innerhalb derselben Sitzung beibehalten wird.
Freigeben des Sitzungszustands über Middleware und Tools
Middleware ausführen kann die Sitzung StateBaglesen und schreiben, und alle Änderungen sind sichtbar, um die Aufrufen von Middleware und Tools, die in derselben Anforderung ausgeführt werden, zu funktionieren.
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"));
Middleware ausführen empfängt die Sitzung direkt als Parameter. Verwenden und StateBag.SetValueGetValue für typsicheren Zugriff. Alle während der Middleware-Ausführungsphase gespeicherten Werte sind für Tools und Funktionsaufrufe middleware über AIAgent.CurrentRunContext?.Session.
Der Python-Laufzeitkontext wird auf drei öffentliche Oberflächen aufgeteilt:
-
session=für Unterhaltungsstatus und Verlauf. -
function_invocation_kwargs=für Werte, die nur Tools oder Funktions-Middleware angezeigt werden sollen. -
client_kwargs=für chat-clientspezifische Daten oder Client-Middleware-Konfiguration.
Verwenden Sie die kleinste Oberfläche, die den Daten entspricht. Dadurch werden Die Tooleingaben explizit beibehalten und verhindern, dass nur Clientmetadaten in die Toolausführung eingespeckt werden.
Tipp
Behandeln Sie function_invocation_kwargs den Ersatz für das alte Muster der Übergabe beliebiger Öffentlicher **kwargs an agent.run() oder get_response().
Auswählen des richtigen Laufzeit-Buckets
| Anwendungsfall | API-Oberfläche | Zugriff von |
|---|---|---|
| Freigeben des Unterhaltungsstatus, Dienstsitzungs-IDs oder Verlaufs | session= |
ctx.session, AgentContext.session |
| Übergeben von Laufzeitwerten nur Tools oder Funktions-Middleware | function_invocation_kwargs= |
FunctionInvocationContext.kwargs |
| Übergeben clientspezifischer Laufzeitwerte oder Client-Middleware-Konfiguration | client_kwargs= |
Benutzerdefinierte get_response(..., client_kwargs=...) Implementierungen |
Übergeben von Nur-Tool-Laufzeitwerten
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)
Verwenden Sie ctx.kwargs innerhalb des Tools, anstatt eine Decke **kwargs auf dem Tool zu deklarieren, das aufgerufen werden kann. Legacytools **kwargs funktionieren weiterhin zur Kompatibilität, werden jedoch vor ga entfernt.
Jeder Parameter, der wie FunctionInvocationContext der injizierte Laufzeitkontextparameter behandelt wird, unabhängig vom Namen und nicht im JSON-Schema, das dem Modell angezeigt wird, verfügbar gemacht wird. Wenn Sie ein explizites Schema-/Eingabemodell angeben, wird auch ein unanmerkter Parameter namens ctx "Nur nicht kommentiert" als der injizierte Kontextparameter erkannt.
Wenn der Wert ein langlebiger Toolstatus oder eine Abhängigkeit anstelle von Daten per Aufruf ist, behalten Sie ihn in einer Toolklasseninstanz bei, anstatt ihn zu function_invocation_kwargsübergeben. Dieses Muster finden Sie unter Erstellen einer Klasse mit mehreren Funktionstools.
Funktions-Middleware empfängt denselben Kontext
Funktions-Middleware verwendet dasselbe FunctionInvocationContext Objekt, das Tools empfangen. Dies bedeutet, dass Middleware die Prüfung context.arguments, context.kwargs, , context.sessionund 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],
)
Der Middleware-Vertrag verwendet call_next() ohne Argumente. Stummschalten context.kwargs sie vor dem Aufrufen, und das ausgewählte Tool sieht diese Werte durch die eingefügte FunctionInvocationContext.
Wird für den freigegebenen Laufzeitstatus verwendet session=
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"])
Übergeben Sie die Sitzung explizit mit session= und lesen Sie sie aus ctx.session. Der Sitzungszugriff muss nicht mehr durch Laufzeit-Kwargs reisen.
Freigeben des Sitzungsstatus für delegierte Agents
Wenn ein Agent als Tool as_tool()verfügbar gemacht wird, fließen laufzeitfunktion kwargs bereits durch ctx.kwargs. Fügen Sie nur hinzu propagate_session=True , wenn der Unter-Agent die Anrufer AgentSessionteilen soll.
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,
)
Mit propagate_session=Truedem delegierten Agent wird derselbe ctx.session Zustand wie der Anrufer angezeigt. Lassen Sie es False , um den untergeordneten Agent in einer eigenen Sitzung zu isolieren.
Benutzerdefinierte Chatclients und Agents
Wenn Sie benutzerdefinierte öffentliche run() oder get_response() Methoden implementieren, fügen Sie der Signatur die expliziten Laufzeit-Buckets hinzu.
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,
):
...
Wird für Toolaufrufflüsse und function_invocation_kwargs für clientspezifisches Verhalten verwendetclient_kwargs. Das direkte Übergeben clientspezifischer Werte über öffentliche **kwargs Daten ist nur ein Kompatibilitätspfad und sollte als veraltet behandelt werden. Ebenso ist die Definition neuer Tools **kwargs nur für die Migrationskompatibilität geeignet – verwenden Sie stattdessen Laufzeitdaten über das injizierte Kontextobjekt.