Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Informazioni su come aggiungere middleware agli agenti in pochi semplici passaggi. Il middleware consente di intercettare e modificare le interazioni degli agenti per la registrazione, la sicurezza e altre problematiche trasversali.
Prerequisiti
Per i prerequisiti e l'installazione dei pacchetti NuGet, vedere il passaggio Creare ed eseguire un agente semplice in questa esercitazione.
Passaggio 1: Creare un agente semplice
Creare prima di tutto un agente di base con uno strumento per le funzioni.
using System;
using System.ComponentModel;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
[Description("The current datetime offset.")]
static string GetDateTime()
=> DateTimeOffset.Now.ToString();
AIAgent baseAgent = new AIProjectClient(
new Uri("<your-foundry-project-endpoint>"),
new DefaultAzureCredential())
.AsAIAgent(
model: "gpt-4o-mini",
instructions: "You are an AI assistant that helps people find information.",
tools: [AIFunctionFactory.Create(GetDateTime, name: nameof(GetDateTime))]);
Avviso
DefaultAzureCredential è utile per lo sviluppo, ma richiede un'attenta considerazione nell'ambiente di produzione. Nell'ambiente di produzione prendere in considerazione l'uso di credenziali specifiche ,ad esempio ManagedIdentityCredential, per evitare problemi di latenza, probe di credenziali indesiderate e potenziali rischi per la sicurezza dai meccanismi di fallback.
Passaggio 2: Creare il middleware di esecuzione per il tuo agente
Creare quindi una funzione che verrà richiamata per ogni esecuzione dell'agente. Consente di controllare l'input e l'output dell'agente.
A meno che l'intenzione non sia quella di utilizzare il middleware per arrestare l'esecuzione del processo, la funzione dovrebbe chiamare RunAsync su innerAgent fornito.
Questo middleware di esempio ispeziona solo l'input e l'output del processo dell'agente e restituisce il numero di messaggi trasmessi dentro e fuori dall'agente.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
async Task<AgentResponse> CustomAgentRunMiddleware(
IEnumerable<ChatMessage> messages,
AgentSession? session,
AgentRunOptions? options,
AIAgent innerAgent,
CancellationToken cancellationToken)
{
Console.WriteLine($"Input: {messages.Count()}");
var response = await innerAgent.RunAsync(messages, session, options, cancellationToken).ConfigureAwait(false);
Console.WriteLine($"Output: {response.Messages.Count}");
return response;
}
Passaggio 3: Aggiungere il middleware di esecuzione agente al tuo agente
Per aggiungere questa funzione middleware all'oggetto baseAgent creato nel passaggio 1, usare il modello di generatore.
Verrà creato un nuovo agente con il middleware applicato.
L'originale baseAgent non viene modificato.
var middlewareEnabledAgent = baseAgent
.AsBuilder()
.Use(runFunc: CustomAgentRunMiddleware, runStreamingFunc: null)
.Build();
Ora, quando si esegue l'agente con una query, il middleware dovrebbe essere richiamato, visualizzando il numero di messaggi di input e il numero di messaggi di risposta.
Console.WriteLine(await middlewareEnabledAgent.RunAsync("What's the current time?"));
Passaggio 4: Creare un middleware per chiamate di funzione
Annotazioni
Il middleware per la chiamata di funzioni è attualmente supportato solo con un AIAgent che utilizza FunctionInvokingChatClient, ad esempio ChatClientAgent.
È anche possibile creare middleware che viene chiamato per ogni strumento di funzione richiamato. Di seguito è riportato un esempio di middleware per la chiamata di funzioni che può analizzare e/o modificare la funzione chiamata e il risultato della chiamata di funzione.
A meno che l'intenzione non sia quella di usare il middleware per non eseguire lo strumento di funzione, il middleware deve chiamare l'oggetto fornito nextFunc.
using System.Threading;
using System.Threading.Tasks;
async ValueTask<object?> CustomFunctionCallingMiddleware(
AIAgent agent,
FunctionInvocationContext context,
Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next,
CancellationToken cancellationToken)
{
Console.WriteLine($"Function Name: {context!.Function.Name}");
var result = await next(context, cancellationToken);
Console.WriteLine($"Function Call Result: {result}");
return result;
}
Passaggio 5: Aggiungere il middleware per la chiamata di funzione all'agente
Come per l'aggiunta del middleware di esecuzione dell'agente, puoi aggiungere middleware per la chiamata delle funzioni come indicato di seguito:
var middlewareEnabledAgent = baseAgent
.AsBuilder()
.Use(CustomFunctionCallingMiddleware)
.Build();
Ora, quando si esegue l'agente con una query che richiama una funzione, il middleware dovrebbe essere richiamato, visualizzando il nome della funzione e il risultato della chiamata.
Console.WriteLine(await middlewareEnabledAgent.RunAsync("What's the current time?"));
Passaggio 6: Creare il middleware per il client di chat
Per gli agenti costruiti tramite IChatClient, è possibile intercettare le chiamate in uscita dall'agente verso l'oggetto IChatClient.
In questo caso, è possibile usare il middleware per IChatClient.
Di seguito è riportato un esempio di middleware client di chat in grado di esaminare e/o modificare l'input e l'output per la richiesta al servizio di inferenza fornito dal client di chat.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
async Task<ChatResponse> CustomChatClientMiddleware(
IEnumerable<ChatMessage> messages,
ChatOptions? options,
IChatClient innerChatClient,
CancellationToken cancellationToken)
{
Console.WriteLine($"Input: {messages.Count()}");
var response = await innerChatClient.GetResponseAsync(messages, options, cancellationToken);
Console.WriteLine($"Output: {response.Messages.Count}");
return response;
}
Annotazioni
Per altre informazioni sul IChatClient middleware, vedere Middleware IChatClient personalizzato.
Passaggio 7: Aggiungere il middleware del client di chat a un IChatClient
Per aggiungere middleware a IChatClient, è possibile usare il modello di generatore.
Dopo aver aggiunto il middleware, è possibile usare il IChatClient con l'agente come di consueto.
var chatClient = new AIProjectClient(
new Uri("<your-foundry-project-endpoint>"),
new DefaultAzureCredential())
.GetProjectOpenAIClient()
.GetProjectResponsesClient()
.AsIChatClient("gpt-4o-mini");
var middlewareEnabledChatClient = chatClient
.AsBuilder()
.Use(getResponseFunc: CustomChatClientMiddleware, getStreamingResponseFunc: null)
.Build();
var agent = new ChatClientAgent(middlewareEnabledChatClient, instructions: "You are a helpful assistant.");
IChatClient il middleware può anche essere registrato usando un metodo factory quando si costruisce un agente tramite uno dei metodi helper nei client SDK.
var agent = new AIProjectClient(
new Uri("<your-foundry-project-endpoint>"),
new DefaultAzureCredential())
.AsAIAgent(
model: "gpt-4o-mini",
instructions: "You are a helpful assistant.",
clientFactory: (chatClient) => chatClient
.AsBuilder()
.Use(getResponseFunc: CustomChatClientMiddleware, getStreamingResponseFunc: null)
.Build());
Passaggio 1: Creare un agente semplice
Creare prima di tutto un agente di base:
import asyncio
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity.aio import AzureCliCredential
async def main():
credential = AzureCliCredential()
async with Agent(
client=FoundryChatClient(credential=credential),
name="GreetingAgent",
instructions="You are a friendly greeting assistant.",
) as agent:
result = await agent.run("Hello!")
print(result.text)
if __name__ == "__main__":
asyncio.run(main())
Passaggio 2: Creare il middleware
Creare un middleware semplice per il logging al fine di verificare quando l'agente viene eseguito:
from collections.abc import Awaitable, Callable
from agent_framework import AgentContext
async def logging_agent_middleware(
context: AgentContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
"""Simple middleware that logs agent execution."""
print("Agent starting...")
# Continue to agent execution
await call_next()
print("Agent finished!")
Passaggio 3: Aggiungere middleware all'agente
Aggiungere il middleware durante la creazione dell'agente:
async def main():
credential = AzureCliCredential()
async with Agent(
client=FoundryChatClient(credential=credential),
name="GreetingAgent",
instructions="You are a friendly greeting assistant.",
middleware=[logging_agent_middleware], # Add your middleware here
) as agent:
result = await agent.run("Hello!")
print(result.text)
Passaggio 4: Creare un middleware per le funzioni
Se il tuo agente usa funzioni, è possibile intercettare le chiamate di funzione e impostare i valori di runtime solo per lo strumento prima che lo strumento venga eseguito.
from collections.abc import Awaitable, Callable
from agent_framework import FunctionInvocationContext
def get_time(ctx: FunctionInvocationContext) -> str:
"""Get the current time."""
from datetime import datetime
source = ctx.kwargs.get("request_source", "direct")
return f"[{source}] {datetime.now().strftime('%H:%M:%S')}"
async def inject_function_kwargs(
context: FunctionInvocationContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
"""Middleware that adds tool-only runtime values before execution."""
context.kwargs.setdefault("request_source", "middleware")
await call_next()
# Add both the function and middleware to your agent
async with Agent(
client=FoundryChatClient(credential=credential),
name="TimeAgent",
instructions="You can tell the current time.",
tools=[get_time],
middleware=[inject_function_kwargs],
) as agent:
result = await agent.run("What time is it?")
Passaggio 5: Usare il middleware a livello di esecuzione
È anche possibile aggiungere middleware per esecuzioni specifiche:
# Use middleware for this specific run only
result = await agent.run(
"This is important!",
middleware=[logging_function_middleware]
)
Che cos'è avanti?
Per scenari più avanzati, vedere la Guida per l'utente del middleware dell'agente, che illustra:
- Tipi diversi di middleware (agente, funzione, chat).
- Middleware basato su classi per scenari complessi.
- Terminazione del middleware e override dei risultati.
- Modelli middleware avanzati e procedure consigliate.
Esempi completi
Middleware basato su classi
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import time
from collections.abc import Awaitable, Callable
from random import randint
from typing import Annotated
from agent_framework import (
AgentContext,
AgentMiddleware,
AgentResponse,
FunctionInvocationContext,
FunctionMiddleware,
Message,
tool,
)
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity.aio import AzureCliCredential
from pydantic import Field
"""
Class-based MiddlewareTypes Example
This sample demonstrates how to implement middleware using class-based approach by inheriting
from AgentMiddleware and FunctionMiddleware base classes. The example includes:
- SecurityAgentMiddleware: Checks for security violations in user queries and blocks requests
containing sensitive information like passwords or secrets
- LoggingFunctionMiddleware: Logs function execution details including timing and parameters
This approach is useful when you need stateful middleware or complex logic that benefits
from object-oriented design patterns.
"""
# 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."
class SecurityAgentMiddleware(AgentMiddleware):
"""Agent middleware that checks for security violations."""
async def process(
self,
context: AgentContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
# Check for potential security violations in the query
# Look at the last user message
last_message = context.messages[-1] if context.messages else None
if last_message and last_message.text:
query = last_message.text
if "password" in query.lower() or "secret" in query.lower():
print("[SecurityAgentMiddleware] Security Warning: Detected sensitive information, blocking request.")
# Override the result with warning message
context.result = AgentResponse(
messages=[Message("assistant", ["Detected sensitive information, the request is blocked."])]
)
# Simply don't call call_next() to prevent execution
return
print("[SecurityAgentMiddleware] Security check passed.")
await call_next()
class LoggingFunctionMiddleware(FunctionMiddleware):
"""Function middleware that logs function calls."""
async def process(
self,
context: FunctionInvocationContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
function_name = context.function.name
print(f"[LoggingFunctionMiddleware] About to call function: {function_name}.")
start_time = time.time()
await call_next()
end_time = time.time()
duration = end_time - start_time
print(f"[LoggingFunctionMiddleware] Function {function_name} completed in {duration:.5f}s.")
async def main() -> None:
"""Example demonstrating class-based middleware."""
print("=== Class-based MiddlewareTypes Example ===")
# 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="WeatherAgent",
instructions="You are a helpful weather assistant.",
tools=get_weather,
middleware=[SecurityAgentMiddleware(), LoggingFunctionMiddleware()],
) as agent,
):
# Test with normal query
print("\n--- Normal Query ---")
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
# Test with security-related query
print("--- Security Test ---")
query = "What's the password for the weather service?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
if __name__ == "__main__":
asyncio.run(main())
Middleware basato su funzioni
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import time
from collections.abc import Awaitable, Callable
from random import randint
from typing import Annotated
from agent_framework import (
AgentContext,
AgentMiddleware,
AgentResponse,
FunctionInvocationContext,
FunctionMiddleware,
Message,
tool,
)
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity.aio import AzureCliCredential
from pydantic import Field
"""
Class-based MiddlewareTypes Example
This sample demonstrates how to implement middleware using class-based approach by inheriting
from AgentMiddleware and FunctionMiddleware base classes. The example includes:
- SecurityAgentMiddleware: Checks for security violations in user queries and blocks requests
containing sensitive information like passwords or secrets
- LoggingFunctionMiddleware: Logs function execution details including timing and parameters
This approach is useful when you need stateful middleware or complex logic that benefits
from object-oriented design patterns.
"""
# 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."
class SecurityAgentMiddleware(AgentMiddleware):
"""Agent middleware that checks for security violations."""
async def process(
self,
context: AgentContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
# Check for potential security violations in the query
# Look at the last user message
last_message = context.messages[-1] if context.messages else None
if last_message and last_message.text:
query = last_message.text
if "password" in query.lower() or "secret" in query.lower():
print("[SecurityAgentMiddleware] Security Warning: Detected sensitive information, blocking request.")
# Override the result with warning message
context.result = AgentResponse(
messages=[Message("assistant", ["Detected sensitive information, the request is blocked."])]
)
# Simply don't call call_next() to prevent execution
return
print("[SecurityAgentMiddleware] Security check passed.")
await call_next()
class LoggingFunctionMiddleware(FunctionMiddleware):
"""Function middleware that logs function calls."""
async def process(
self,
context: FunctionInvocationContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
function_name = context.function.name
print(f"[LoggingFunctionMiddleware] About to call function: {function_name}.")
start_time = time.time()
await call_next()
end_time = time.time()
duration = end_time - start_time
print(f"[LoggingFunctionMiddleware] Function {function_name} completed in {duration:.5f}s.")
async def main() -> None:
"""Example demonstrating class-based middleware."""
print("=== Class-based MiddlewareTypes Example ===")
# 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="WeatherAgent",
instructions="You are a helpful weather assistant.",
tools=get_weather,
middleware=[SecurityAgentMiddleware(), LoggingFunctionMiddleware()],
) as agent,
):
# Test with normal query
print("\n--- Normal Query ---")
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
# Test with security-related query
print("--- Security Test ---")
query = "What's the password for the weather service?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
if __name__ == "__main__":
asyncio.run(main())
Middleware basato su Decorator
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import time
from collections.abc import Awaitable, Callable
from random import randint
from typing import Annotated
from agent_framework import (
AgentContext,
AgentMiddleware,
AgentResponse,
FunctionInvocationContext,
FunctionMiddleware,
Message,
tool,
)
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity.aio import AzureCliCredential
from pydantic import Field
"""
Class-based MiddlewareTypes Example
This sample demonstrates how to implement middleware using class-based approach by inheriting
from AgentMiddleware and FunctionMiddleware base classes. The example includes:
- SecurityAgentMiddleware: Checks for security violations in user queries and blocks requests
containing sensitive information like passwords or secrets
- LoggingFunctionMiddleware: Logs function execution details including timing and parameters
This approach is useful when you need stateful middleware or complex logic that benefits
from object-oriented design patterns.
"""
# 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."
class SecurityAgentMiddleware(AgentMiddleware):
"""Agent middleware that checks for security violations."""
async def process(
self,
context: AgentContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
# Check for potential security violations in the query
# Look at the last user message
last_message = context.messages[-1] if context.messages else None
if last_message and last_message.text:
query = last_message.text
if "password" in query.lower() or "secret" in query.lower():
print("[SecurityAgentMiddleware] Security Warning: Detected sensitive information, blocking request.")
# Override the result with warning message
context.result = AgentResponse(
messages=[Message("assistant", ["Detected sensitive information, the request is blocked."])]
)
# Simply don't call call_next() to prevent execution
return
print("[SecurityAgentMiddleware] Security check passed.")
await call_next()
class LoggingFunctionMiddleware(FunctionMiddleware):
"""Function middleware that logs function calls."""
async def process(
self,
context: FunctionInvocationContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
function_name = context.function.name
print(f"[LoggingFunctionMiddleware] About to call function: {function_name}.")
start_time = time.time()
await call_next()
end_time = time.time()
duration = end_time - start_time
print(f"[LoggingFunctionMiddleware] Function {function_name} completed in {duration:.5f}s.")
async def main() -> None:
"""Example demonstrating class-based middleware."""
print("=== Class-based MiddlewareTypes Example ===")
# 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="WeatherAgent",
instructions="You are a helpful weather assistant.",
tools=get_weather,
middleware=[SecurityAgentMiddleware(), LoggingFunctionMiddleware()],
) as agent,
):
# Test with normal query
print("\n--- Normal Query ---")
query = "What's the weather like in Seattle?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
# Test with security-related query
print("--- Security Test ---")
query = "What's the password for the weather service?"
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text}\n")
if __name__ == "__main__":
asyncio.run(main())