尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

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

Microsoft Agent Framework - 对 Agent 进AOP(Middleware)编程
📅 发布时间:2026/6/23 11:47:12

目录

代码基础:创建带工具的 Agent

切面 1:Run Middleware(对整次 Run 执行做前后拦截)

对应输出场景(Run Middleware 日志)

切面 2:Function Calling Middleware(拦截工具调用过程)

对应输出场景(Function Calling Middleware 日志)

可扩展示例:增加计时切面

常见可插入的切面思路

总结


上一篇

在构建 AI Agent 时,经常需要为“执行对话”和“工具调用”加入横切能力(Cross-Cutting Concerns),例如:

  • 日志与审计

  • 性能与计时

  • 异常捕获与统一包装

  • 调试与可观测性

  • 安全与访问控制

在 Microsoft Agent Framework(Microsoft.Extensions.AI/Microsoft.Agents.AI)中,可以通过“函数式 Middleware”直接对 Agent 运行生命周期进行切面化增强,无需定义类或接口,实现极简、模块化、可组合的拦截。

本文示例展示两类切面:

  1. Run Middleware(拦截整个对话执行)

  2. Function Calling Middleware(拦截工具调用)

代码基础:创建带工具的 Agent

using 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)。

切面 1:Run Middleware(对整次 Run 执行做前后拦截)

作用:记录每次请求输入与模型产生的输出消息。

// 自定义 Run Middleware async Task<AgentRunResponse> CustomAgentRunMiddleware( IEnumerable<ChatMessage> 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:模型决定调用工具并返回结果的中间内容

  • 最后一行:最终自然语言回答

切面 2:Function Calling Middleware(拦截工具调用过程)

作用:对每次工具调用做审计 / 计时 / 参数检查 / 结果加工等。

// 自定义 Function Calling Middleware 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; } // 注册 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:该工具函数真实返回值

  • 最后一行:模型基于工具结果生成的最终回答

可扩展示例:增加计时切面

你可以继续添加更多函数式 Middleware:

async ValueTask<object?> TimingFunctionMiddleware( AIAgent agent, FunctionInvocationContext context, Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> 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,你可以快速迭代智能体的可观测性、调试性与扩展能力,专注核心价值而非样板结构。

下一篇

引入地址

相关新闻

  • 深度拆解:从零构建生产级 Multi-Agent 驾驭层(Harness)全景架构
  • aws-waf-token 亚马逊waf盾逆向分析
  • 环保行业选择 TDengine:环境监测数据的国产时序数据库实践

最新新闻

  • 终极免费Verilog仿真工具:Icarus Verilog完整使用指南
  • 深入解析ANSI C标准库:数学函数与文件I/O的核心原理与实战避坑
  • 3分钟掌握开源Verilog仿真:Icarus Verilog完整实战指南
  • ESP32-C2在Arduino-ESP32中的技术实现与生态整合策略
  • 深入解析NXP LS2088A SEC Job Ring架构与中断处理机制
  • NXP QCVS安装配置指南:嵌入式硬件开发效率提升利器

日新闻

  • Arduino-ESP32项目深度解析:解锁隐藏芯片支持与架构演进
  • 2026年 系统窗厂家/品牌推荐榜单:隔音系统窗+高端系统门窗的核心优势与选购指南 - 品牌发掘
  • NVBench:首个双语非言语发声语音合成评测基准详解与实践

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号