Microsoft Agent Framework - 对 Agent 进AOP(Middleware)编程

📅 2026/6/23 11:36:45
Microsoft Agent Framework - 对 Agent 进AOP(Middleware)编程
目录代码基础创建带工具的 Agent切面 1Run Middleware对整次 Run 执行做前后拦截对应输出场景Run Middleware 日志切面 2Function Calling Middleware拦截工具调用过程对应输出场景Function Calling Middleware 日志可扩展示例增加计时切面常见可插入的切面思路总结上一篇在构建 AI Agent 时经常需要为“执行对话”和“工具调用”加入横切能力Cross-Cutting Concerns例如日志与审计性能与计时异常捕获与统一包装调试与可观测性安全与访问控制在 Microsoft Agent FrameworkMicrosoft.Extensions.AI/Microsoft.Agents.AI中可以通过“函数式 Middleware”直接对 Agent 运行生命周期进行切面化增强无需定义类或接口实现极简、模块化、可组合的拦截。本文示例展示两类切面Run Middleware拦截整个对话执行Function Calling Middleware拦截工具调用代码基础创建带工具的 Agentusing Azure.AI.OpenAI; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; using OpenAI; using System.ClientModel; using System.ComponentModel; // 配置生产环境请用安全方式管理密钥 var azureAiEndpoint https://{your-endpoint}.openai.azure.com; var apiKey {YOUR-API-KEY}; // 1. 定义工具函数即工具 [Description(Get user information by a given user name.)] static string GetUserInfo([Description(The user name)] string userName) ${userName} is from Suzhou, male, 28 years old; // 2. 创建 Agent 并注册工具 AIAgent agent new AzureOpenAIClient( new Uri(azureAiEndpoint), new ApiKeyCredential(apiKey)) .GetChatClient(gpt-4o-mini) .CreateAIAgent( instructions: You are a helpful assistant, tools: [AIFunctionFactory.Create(GetUserInfo)]);这里通过AIFunctionFactory.Create将一个普通 C# 方法暴露为可被模型自主调用的工具Function Calling。切面 1Run Middleware对整次 Run 执行做前后拦截作用记录每次请求输入与模型产生的输出消息。// 自定义 Run Middleware async TaskAgentRunResponse CustomAgentRunMiddleware( IEnumerableChatMessage messages, AgentThread? thread, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken) { foreach (var chatMessage in messages) { Console.WriteLine($Input: {chatMessage}); } var response await innerAgent .RunAsync(messages, thread, options, cancellationToken) .ConfigureAwait(false); foreach (var chatMessage in response.Messages) { Console.WriteLine($Output: {chatMessage.Contents[0].ToString()}); } return response; } // 注册 Run Middleware var agentWithRunMiddleware agent.AsBuilder() .Use(runFunc: CustomAgentRunMiddleware, runStreamingFunc: null) .Build(); Console.WriteLine(await agentWithRunMiddleware.RunAsync(Show me the information of Jim ?));对应输出场景Run Middleware 日志Input: Show me the information of Jim ? Output: Microsoft.Extensions.AI.FunctionCallContent Output: Microsoft.Extensions.AI.FunctionResultContent Output: Jim is a 28-year-old male from Suzhou. Jim is a 28-year-old male from Suzhou.说明第一行原始用户输入中间的 FunctionCall / FunctionResult模型决定调用工具并返回结果的中间内容最后一行最终自然语言回答切面 2Function Calling Middleware拦截工具调用过程作用对每次工具调用做审计 / 计时 / 参数检查 / 结果加工等。// 自定义 Function Calling Middleware async ValueTaskobject? CustomFunctionCallingMiddleware( AIAgent agent, FunctionInvocationContext context, FuncFunctionInvocationContext, CancellationToken, ValueTaskobject? next, CancellationToken cancellationToken) { Console.WriteLine($Function Name: {context.Function.Name}); var result await next(context, cancellationToken); Console.WriteLine($Function Call Result: {result}); return result; } // 注册 Function Calling Middleware var agentWithFunctionCallingMiddleware agent.AsBuilder() .Use(CustomFunctionCallingMiddleware) .Build(); Console.WriteLine(await agentWithFunctionCallingMiddleware.RunAsync(Show me the information of Jim ?));对应输出场景Function Calling Middleware 日志Function Name: _Main_g_GetUserInfo_0_1 Function Call Result: Jim is from Suzhou, male, 28 years old Jim is a 28-year-old male from Suzhou.说明Function Name模型选择调用的工具函数内部生成的名称可用于审计 / 白名单校验Function Call Result该工具函数真实返回值最后一行模型基于工具结果生成的最终回答可扩展示例增加计时切面你可以继续添加更多函数式 Middlewareasync ValueTaskobject? TimingFunctionMiddleware( AIAgent agent, FunctionInvocationContext context, FuncFunctionInvocationContext, CancellationToken, ValueTaskobject? next, CancellationToken ct) { var sw System.Diagnostics.Stopwatch.StartNew(); var result await next(context, ct); sw.Stop(); Console.WriteLine($Function {context.Function.Name} elapsed: {sw.ElapsedMilliseconds} ms); return result; } var enhancedAgent agent.AsBuilder() .Use(CustomFunctionCallingMiddleware) .Use(TimingFunctionMiddleware) .Use(runFunc: CustomAgentRunMiddleware, runStreamingFunc: null) .Build();常见可插入的切面思路参数校验与拒绝危险输入结果缓存相同参数短期复用异常捕获统一格式化返回OpenTelemetry 观测埋点发送 Span / Metric权限控制基于用户上下文阻断某些工具总结Microsoft Agent Framework 的 Middleware 是以“函数”形态实现的而不是传统的类 / 接口这种模式非常接近 JavaScript 生态如 Express / Koa 的中间件管道。它充分体现了 C# 在现代版本中的函数式编程能力一等函数、委托、闭包与组合式构建使得为 Agent 增加切面逻辑变得简洁、高效、低侵入。借助这种函数式 Middleware你可以快速迭代智能体的可观测性、调试性与扩展能力专注核心价值而非样板结构。下一篇引入地址