Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El estado compartido permite a los componentes de middleware comunicar y compartir datos durante el procesamiento de una solicitud de agente. Esto resulta útil para pasar información entre el middleware de la cadena, como los datos de tiempo, los identificadores de solicitud o las métricas acumuladas.
En C#, el middleware puede usar objetos de contexto compartidos AgentRunOptions o personalizados para pasar el estado entre los componentes de middleware. También puede usar la Use(sharedFunc: ...) sobrecarga para middleware de inspección de solo entrada.
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;
// Shared state container that middleware instances can reference
var sharedState = new Dictionary<string, object> { ["callCount"] = 0 };
// Middleware that increments a shared call counter
async Task<AgentResponse> CounterMiddleware(
IEnumerable<ChatMessage> messages,
AgentSession? session,
AgentRunOptions? options,
AIAgent innerAgent,
CancellationToken cancellationToken)
{
var count = (int)sharedState["callCount"] + 1;
sharedState["callCount"] = count;
Console.WriteLine($"[Counter] Call #{count}");
return await innerAgent.RunAsync(messages, session, options, cancellationToken);
}
// Middleware that reads shared state to enrich output
async Task<AgentResponse> EnrichMiddleware(
IEnumerable<ChatMessage> messages,
AgentSession? session,
AgentRunOptions? options,
AIAgent innerAgent,
CancellationToken cancellationToken)
{
var response = await innerAgent.RunAsync(messages, session, options, cancellationToken);
var count = (int)sharedState["callCount"];
Console.WriteLine($"[Enrich] Total calls so far: {count}");
return response;
}
AIAgent agent = new AIProjectClient(
new Uri("<your-foundry-project-endpoint>"),
new DefaultAzureCredential())
.AsAIAgent(
model: "gpt-4o-mini",
instructions: "You are a helpful assistant.");
var agentWithState = agent
.AsBuilder()
.Use(runFunc: CounterMiddleware, runStreamingFunc: null)
.Use(runFunc: EnrichMiddleware, runStreamingFunc: null)
.Build();
Console.WriteLine(await agentWithState.RunAsync("What's the weather in New York?"));
Console.WriteLine(await agentWithState.RunAsync("What time is it in London?"));
Console.WriteLine($"Total calls: {sharedState["callCount"]}");
Advertencia
DefaultAzureCredential es conveniente para el desarrollo, pero requiere una consideración cuidadosa en producción. En producción, considere usar una credencial específica (por ejemplo, ManagedIdentityCredential) para evitar problemas de latencia, sondeos de credenciales no deseados y posibles riesgos de seguridad de los mecanismos de respaldo.
Contenedor de middleware con estado compartido
En el ejemplo siguiente se muestra cómo usar un contenedor de middleware para compartir el estado entre los componentes de middleware:
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from collections.abc import Awaitable, Callable
from random import randint
from typing import Annotated
from agent_framework import (
FunctionInvocationContext,
tool,
)
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity.aio import AzureCliCredential
from pydantic import Field
"""
Shared State Function-based MiddlewareTypes Example
This sample demonstrates how to implement function-based middleware within a class to share state.
The example includes:
- A MiddlewareContainer class with two simple function middleware methods
- First middleware: Counts function calls and stores the count in shared state
- Second middleware: Uses the shared count to add call numbers to function results
This approach shows how middleware can work together by sharing state within the same class instance.
"""
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
@tool(approval_mode="never_require")
def get_time(
timezone: Annotated[str, Field(description="The timezone to get the time for.")] = "UTC",
) -> str:
"""Get the current time for a given timezone."""
import datetime
return f"The current time in {timezone} is {datetime.datetime.now().strftime('%H:%M:%S')}"
class MiddlewareContainer:
"""Container class that holds middleware functions with shared state."""
def __init__(self) -> None:
# Simple shared state: count function calls
self.call_count: int = 0
async def call_counter_middleware(
self,
context: FunctionInvocationContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
"""First middleware: increments call count in shared state."""
# Increment the shared call count
self.call_count += 1
print(f"[CallCounter] This is function call #{self.call_count}")
# Call the next middleware/function
await call_next()
async def result_enhancer_middleware(
self,
context: FunctionInvocationContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
"""Second middleware: uses shared call count to enhance function results."""
print(f"[ResultEnhancer] Current total calls so far: {self.call_count}")
# Call the next middleware/function
await call_next()
# After function execution, enhance the result using shared state
if context.result:
enhanced_result = f"[Call #{self.call_count}] {context.result}"
context.result = enhanced_result
print("[ResultEnhancer] Enhanced result with call number")
async def main() -> None:
"""Example demonstrating shared state function-based middleware."""
print("=== Shared State Function-based MiddlewareTypes Example ===")
# Create middleware container with shared state
middleware_container = MiddlewareContainer()
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
Agent(
client=FoundryChatClient(credential=credential),
name="UtilityAgent",
instructions="You are a helpful assistant that can provide weather information and current time.",
tools=[get_weather, get_time],
# Pass both middleware functions from the same container instance
# Order matters: counter runs first to increment count,
# then result enhancer uses the updated count
middleware=[
middleware_container.call_counter_middleware,
middleware_container.result_enhancer_middleware,
],
) as agent,
):
# Test multiple requests to see shared state in action
queries = [
"What's the weather like in New York?",
"What time is it in London?",
"What's the weather in Tokyo?",
]
for i, query in enumerate(queries, 1):
print(f"\n--- Query {i} ---")
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text if result.text else 'No response'}")
# Display final statistics
print("\n=== Final Statistics ===")
print(f"Total function calls made: {middleware_container.call_count}")
if __name__ == "__main__":
asyncio.run(main())