个人网站开发软件WordPress投票主题系统
2026/2/23 20:46:10 网站建设 项目流程
个人网站开发软件,WordPress投票主题系统,百度网络营销推广,珠海手机网站开发序言在构建企业级 AI 应用时#xff0c;直接让大语言模型#xff08;LLM#xff09;与用户或系统交互往往存在风险。需要处理隐私泄露#xff08;PII#xff09;、内容合规性#xff08;Guardrails#xff09;、函数调用的审计以及“人在回路”#xff08;Human-in-the…序言在构建企业级 AI 应用时直接让大语言模型LLM与用户或系统交互往往存在风险。需要处理隐私泄露PII、内容合规性Guardrails、函数调用的审计以及“人在回路”Human-in-the-Loop的审批流程。Microsoft Agent Framework 引入了强大的中间件Middleware机制允许开发者像洋葱皮一样层层包裹代理Agent在消息发送前后、函数调用前后进行拦截和处理。从 ASP.NET Core Middleware 说起如果你有 ASP.NET Core 的开发经验那么你其实已经掌握了理解 Agent Middleware 所需的80% 关键知识。因为无论是 Web 应用还是 AI Agent本质上都面临同一个问题如何在不侵入核心业务逻辑的前提下引入日志、审计、监控等横切能力ASP.NET Core 中的 Middleware Pipeline在一个典型的 Web 应用中请求会依次经过一条中间件管道PipelineRequest → Logging → Authentication → Authorization → MVC → Response这种设计的核心价值在于将日志、鉴权、异常处理、限流等横切关注点从业务代码中剥离每个中间件只关注自己的职责是否继续执行后续逻辑由当前中间件通过next()决定从设计角度看这本质上是一种AOP面向切面编程模型。一个更“真实”的 ASP.NET Core Middleware 示例为了让这个类比更贴近后续的 Agent 场景我们来看一个带计数与耗时统计的中间件示例。public sealedclassRequestMetricsMiddleware { privatestaticlong _requestCount 0; privatereadonly RequestDelegate _next; privatereadonly ILoggerRequestMetricsMiddleware _logger; public RequestMetricsMiddleware( RequestDelegate next, ILoggerRequestMetricsMiddleware logger) { _next next; _logger logger; } public async Task InvokeAsync(HttpContext context) { var requestId Interlocked.Increment(ref _requestCount); var start Stopwatch.GetTimestamp(); _logger.LogInformation( Request #{RequestId} started: {Method} {Path}, requestId, context.Request.Method, context.Request.Path); await _next(context); var elapsedMs (Stopwatch.GetTimestamp() - start) * 1000d / Stopwatch.Frequency; _logger.LogInformation( Request #{RequestId} finished in {Elapsed} ms, requestId, elapsedMs); } }这个中间件做了什么在请求进入时记录请求编号开始计时在请求完成后统计请求耗时输出统一的审计日志整个过程中业务 Controller 完全不需要感知它的存在中间件以“切面”的形式横跨整个请求生命周期Middleware 注册形成 HTTP Pipelinevar builder WebApplication.CreateBuilder(args); var app builder.Build(); app.UseMiddlewareRequestMetricsMiddleware(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();需要注意的是Middleware 按注册顺序执行 Before按相反顺序执行 After共同构成一条完整的请求处理管道从 Web Middleware 到 Agent Middleware如果你将上面的示例换一个视角来看Web 世界AI Agent 世界HttpContextPrompt / Agent ContextHTTP Request用户输入HTTP ResponseAgent / LLM 输出RequestMetricsMiddlewareAgent / LLM 中间件那么你会发现ASP.NET Core Middleware 的核心思想可以被几乎原封不动地迁移到 AI Agent 的执行模型中。区别只在于请求不再是 HTTP Request上下文不再是 HttpContext管道中流转的不再是 HTTP 数据而是Prompt函数调用决策推理结果Microsoft Agent Framework 的 Middleware 机制正是基于这一思想将成熟的 Pipeline / AOP 模型引入到了 AI Agent 的执行生命周期中。Agent Framework 中的 Middleware认知前提在进入具体代码之前需要先建立一个关键认识Agent Framework 并不是在一条统一的 Pipeline 上引入 Middleware而是在 Agent 执行生命周期的不同“责任边界”上刻意引入不同类型的 Middleware这是一个明确的设计选择而非实现细节一次 Agent Run究竟发生了什么从时间轴看一次完整的 Agent Run 至少经历组织 Prompt 并调用大语言模型进行推理模型在推理过程中可能决定调用某个函数ToolAgent 接收模型输出与函数执行结果生成最终响应对应的失败模式与治理需求模型可能产生幻觉或不当输出模型可能错误或越权地触发系统行为最终输出可能违反业务合规或隐私要求这些问题无法在同一层次被统一治理因此 Agent Framework 将 Middleware 拆分为三条并行、但时间上相互嵌套的 Pipeline。三条 Pipeline 三个不可混合的治理边界可以将一次 Agent Run 理解为三条责任明确的 Pipeline模型推理边界LLM Call治理 Agent 与大模型之间的请求与响应行为决策与执行边界Function / Tool Call治理“模型已经决定要做什么但系统是否允许它真的去做”Agent 运行生命周期边界Agent Run治理一次完整 Agent 运行的整体输入与最终输出对比视角ASP.NET Core 只有一条 HTTP PipelineAgent Framework 则必须同时治理模型调用 / 行为执行 / 业务输入输出 三个层面接下来将按这三条 Pipeline 在时间轴上的自然顺序逐一展开。1) IChatClient Middleware模型推理级从距离模型最近的一层开始。作用范围Scope直接包裹对 LLM 的推理调用拦截发送给模型的 PromptChatMessage拦截模型返回的原始响应ChatResponse只要一次 Agent Run 中触发了模型推理就一定会执行为什么这一层不可替代这是系统中唯一仍工作在“模型边界”之内的中间件一旦模型输出被解释为函数调用意图或被封装为 AgentRunResponse后续中间件处理的对象就不再是“模型推理”而是“系统行为”或“业务结果”因此以下能力需要在此层实现才能足够准确Prompt 审计与日志Token / Latency 统计模型调用配额与限流调试真实发送给模型的内容定义async TaskChatResponse CustomChatClientMiddleware( IEnumerableChatMessage messages, ChatOptions? options, IChatClient innerClient, CancellationToken ct) { // BeforePrompt 审查 / 统计 var response await innerClient.GetResponseAsync(messages, options, ct); // After模型输出审计 / 统计 return response; }注册示例var agent new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) .GetChatClient(deploymentName) .AsIChatClient() .AsBuilder() .Use(getResponseFunc: CustomChatClientMiddleware, getStreamingResponseFunc: null) .BuildAIAgent(instructions: 你是一个乐于助人的助手。);2) Function Calling Middleware行为决策 / 执行级当模型完成推理后需要回答一个全新的问题模型“想做什么”系统是否允许它去做作用范围Scope作用于每一次函数Tool调用一次 Agent Run 内可能触发 0..N 次拦截并治理结构化的函数名、参数与返回值核心价值这一层不处理自然语言而是位于“模型决策 → 系统执行”的边界把关模型已作出的行为决策在真正执行前进行安全与合规校验为系统提供可审计、可覆写的控制点典型能力权限控制Allow/Deny、参数白名单/黑名单行为审计函数名、参数、结果、耗时Mock / 结果覆写沙箱、回放、故障注入Human-in-the-loop人工审批/拒绝/修改参数一句话定位Agent Run Middleware 管“说什么”Function Calling Middleware 管“做不做”定义async ValueTaskobject? CustomFunctionCallingMiddleware( AIAgent agent, FunctionInvocationContext context, FuncFunctionInvocationContext, CancellationToken, ValueTaskobject? next, CancellationToken ct) { // Before参数校验 / 审计 var result await next(context, ct); // After结果处理 / 覆写 return result; }注册var agent originalAgent .AsBuilder() .Use(CustomFunctionCallingMiddleware) .Build();执行模型MW2.Before MW1.Before Function Execution MW1.After MW2.After3) Agent Run MiddlewareAgent 生命周期级当模型推理与函数执行都结束后系统仍需对整体输入与整体输出负责。这正是 Agent Run Middleware 的职责。作用范围Scope拦截一次完整 Agent Run 的输入消息最终输出结果处于最外层最贴近业务语义典型用途输入/输出双向 PII 脱敏内容合规Guardrails统一审计、兜底与结果转换注意事项不关心函数内部发生了什么治理的是“这一轮 Agent 运行对外是否合规”定义async TaskAgentRunResponse CustomAgentRunMiddleware( IEnumerableChatMessage messages, AgentThread? thread, AgentRunOptions? options, AIAgent innerAgent, CancellationToken ct) { // Before输入治理 / 审计 var response await innerAgent.RunAsync(messages, thread, options, ct); // After输出治理 / 结果转换 return response; }注册var agent originalAgent .AsBuilder() .Use(runFunc: CustomAgentRunMiddleware, runStreamingFunc: null) .Build();执行模型Messages → AgentRunMiddleware (Before) → innerAgent.RunAsync(...) ← AgentRunMiddleware (After) AgentRunResponse1.1) Agent Run Streaming Middleware流式生命周期级Streaming 场景下Agent 持续输出 AgentRunResponseUpdate。作用范围拦截 Streaming 过程中的每一条 Update典型用途Token/Update 级统计流式过滤、采样、缓存SSE/gRPC 类流式治理定义async IAsyncEnumerableAgentRunResponseUpdate CustomAgentRunStreamingMiddleware( IEnumerableChatMessage messages, AgentThread? thread, AgentRunOptions? options, AIAgent innerAgent, CancellationToken ct) { // Before流式开始前 await foreach (var update in innerAgent.RunStreamingAsync(messages, thread, options, ct)) { // During逐条 update 拦截 yield return update; } // After流式结束后 }注册建议var agent originalAgent .AsBuilder() .Use( runFunc: CustomAgentRunMiddleware, runStreamingFunc: CustomAgentRunStreamingMiddleware) .Build();建议非流式与流式 Middleware 始终成对注册否则 Streaming 可能退化为非流式执行。示例下面的示例将完成三件事情在 LLM 推理阶段记录请求与响应在函数调用阶段审计并覆盖函数结果在 Agent 执行阶段进行隐私脱敏与内容合规过滤示例中会同时出现三类 Middleware这是有意为之 目的是让你看到它们在一次 Agent Run 中是如何协同工作的。定义可被 LLM 调用的函数Tools首先定义两个可被 LLM 调用的函数作为 Agent 的工具Tools,用来模拟Function Calling 中间件[Description(获取指定位置的天气。)] static string GetWeather( [Description(用于查询天气的地点。)] string location) ${location} 的天气是多云最高气温为 15°C。; [Description(当前的日期时间偏移量。)] static string GetDateTime() DateTimeOffset.Now.ToString();说明使用 [Description] 为函数及其参数提供语义信息帮助模型理解用途。这些元数据也便于在 Function Calling Middleware 中进行拦截与审计。IChatClient MiddlewareLLM 推理级IChatClient Middleware 是最底层、最靠近模型的一层用于拦截 Agent 与 LLM 间的请求与响应定义IChatClient 中间件。async TaskChatResponse ChatClientMiddleware(IEnumerableChatMessage message, ChatOptions? options, IChatClient innerChatClient, CancellationToken cancellationToken) { Console.WriteLine(Chat Client 中间件 - 运行前聊天); var response await innerChatClient.GetResponseAsync(message, options, cancellationToken); Console.WriteLine(Chat Client 中间件 - 运行后聊天); return response; }典型用途Prompt 日志与审计Token 统计与调用监控调试模型行为它的角色类似于 ASP.NET Core 中的 HttpClient DelegatingHandler。构建 originalAgent基础 Agent将 IChatClient 中间件注入到底层 ChatClient并构建 Agent包含工具函数// 创建Azure OpenAI客户端并获取ChatCliet对象 var azureOpenAIClient new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) .GetChatClient(deploymentName); // 构建 Agent 时注入底层中间件 var originalAgent azureOpenAIClient.AsIChatClient() .AsBuilder() .Use(getResponseFunc: ChatClientMiddleware, getStreamingResponseFunc: null) .BuildAIAgent(instructions: 你是一个帮助人们查找信息的 AI 助手。, tools: [AIFunctionFactory.Create(GetDateTime, name: nameof(GetDateTime))]); // 添加中间件在agent级别并在其上构建一个新的代理 var middlewareEnabledAgent originalAgent .AsBuilder() .Use(FunctionCallMiddleware) .Use(FunctionCallOverrideWeather) .Use(PIIMiddleware, null) .Use(GuardrailMiddleware, null) .Build(); var thread middlewareEnabledAgent.GetNewThread();此时Agent 已具备 LLM 推理级中间件能力尚未引入 Agent Run 与 Function Calling 两类中间件Function Calling Middleware函数调用级当 Agent 触发函数调用时该类中间件会介入执行流程。FunctionCallMiddleware审计型记录函数执行前后信息async ValueTaskobject? FunctionCallMiddleware(AIAgent agent, FunctionInvocationContext context, FuncFunctionInvocationContext, CancellationToken, ValueTaskobject? next, CancellationToken cancellationToken) { Console.WriteLine($函数: {context!.Function.Name} - 中间件 1 执行前); var result await next(context, cancellationToken); Console.WriteLine($函数: {context!.Function.Name} - 中间件 1 执行后); return result; }FunctionCallOverrideWeather结果覆盖对指定函数结果进行覆写async ValueTaskobject? FunctionCallOverrideWeather(AIAgent agent, FunctionInvocationContext context, FuncFunctionInvocationContext, CancellationToken, ValueTaskobject? next, CancellationToken cancellationToken) { Console.WriteLine($函数: {context!.Function.Name} - 中间件 2 执行前); var result await next(context, cancellationToken); if (context.Function.Name nameof(GetWeather)) { // Override the result of the GetWeather function result 天气晴朗最高气温25°C。; } Console.WriteLine($函数: {context!.Function.Name} - 中间件 2 执行后); return result; }注册顺序与执行顺序var agentWithFunctionCalling originalAgent .AsBuilder() .Use(FunctionCallMiddleware) // 先审计 .Use(FunctionCallOverrideWeather) // 后覆写 .Build(); /* 执行链 FunctionCallMiddleware (Before) → FunctionCallOverrideWeather (Before) → 实际函数执行或被覆盖 ← FunctionCallOverrideWeather (After) ← FunctionCallMiddleware (After) */Agent Run MiddlewareAgent 执行级在 Agent 执行层面引入两种中间件形成典型的企业合规治理组合。PIIMiddleware个人信息脱敏执行前过滤输入消息执行后过滤输出消息示例规则123-456-7890 → [已屏蔽: PII] johnxxx.com → [已屏蔽: PII] John Doe → [已屏蔽: PII]示例实现省略具体正则与消息结构处理async TaskAgentRunResponse PIIMiddleware(IEnumerableChatMessage messages, AgentThread? thread, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken) { var filteredMessages FilterMessages(messages); Console.WriteLine(Pii 中间件 - 运行前过滤消息); var response await innerAgent.RunAsync(filteredMessages, thread, options, cancellationToken).ConfigureAwait(false); response.Messages FilterMessages(response.Messages); Console.WriteLine(Pii 中间件 - 运行后过滤消息); return response; static IListChatMessage FilterMessages(IEnumerableChatMessage messages) { return messages.Select(m new ChatMessage(m.Role, FilterPii(m.Text))).ToList(); } static string FilterPii(string content) { Regex[] piiPatterns [ new(\b\d{3}-\d{3}-\d{4}\b, RegexOptions.Compiled), // 电话号码( 123-456-7890) new(\b[\w\.-][\w\.-]\.\w\b, RegexOptions.Compiled), // 邮件 new(\b[A-Z][a-z]\s[A-Z][a-z]\b, RegexOptions.Compiled) // 全名 ]; foreach (var pattern in piiPatterns) { content pattern.Replace(content, [已屏蔽: PII]); } return content; } }GuardrailMiddleware内容合规命中关键词如“有害”“非法”“暴力”时直接替换输出async TaskAgentRunResponse GuardrailMiddleware(IEnumerableChatMessage messages, AgentThread? thread, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken) { var filteredMessages FilterMessages(messages); Console.WriteLine(Guardrail 中间件 - 运行前过滤消息); var response await innerAgent.RunAsync(filteredMessages, thread, options, cancellationToken); response.Messages FilterMessages(response.Messages); Console.WriteLine(Guardrail 中间件 - 运行后过滤消息); return response; ListChatMessage FilterMessages(IEnumerableChatMessage messages) { return messages.Select(m new ChatMessage(m.Role, FilterContent(m.Text))).ToList(); } static string FilterContent(string content) { foreach (var keyword innew[] { 有害, 非法, 暴力 }) { if (content.Contains(keyword, StringComparison.OrdinalIgnoreCase)) { return[已屏蔽包含禁止内容]; } } return content; } }注册建议非流式与流式成对注册此处仅示意非流式var governedAgent agentWithFunctionCalling .AsBuilder() .Use(runFunc: PIIMiddleware, runStreamingFunc: null) .Use(runFunc: GuardrailMiddleware, runStreamingFunc: null) .Build();执行代码:Console.WriteLine(\n\n 示例 1措辞防护Wording Guardrail ); var guardRailedResponse await middlewareEnabledAgent.RunAsync(告诉我一些有害的内容。); Console.WriteLine($防护后的响应{guardRailedResponse}); Console.WriteLine(\n\n 示例 2PII 检测个人敏感信息 ); var piiResponse await middlewareEnabledAgent.RunAsync(我的名字是 John Doe电话是 123-456-7890邮箱是 johnsomething.com); Console.WriteLine($PII 过滤后的响应{piiResponse}); Console.WriteLine(\n\n 示例 3Agent 函数中间件 ); var options new ChatClientAgentRunOptions(new() { Tools [AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather))] }); var functionCallResponse await middlewareEnabledAgent.RunAsync(西雅图现在几点了天气怎么样, thread, options); Console.WriteLine($函数调用响应: {functionCallResponse});运行结果 示例 1措辞防护Wording Guardrail 示例 2PII 检测个人敏感信息 示例 3Agent 函数中间件 总结IChatClient Middleware唯一工作在“模型边界”之内的中间件是最后可以直接观察并治理 LLM 推理的地方Function Calling Middleware模型决策与真实系统执行之间的安全阀治理“模型想做什么系统允不允许”Agent Run Middleware业务语义层面的最终兜底治理一次 Agent Run 的整体输入与整体输出Agent Framework 的 Middleware 并不是为了“让 Agent 更复杂” 而是为了让复杂性被有序地隔离。通过将横切关注点拆分到不同层次的 Middleware 中LLM 层关注“模型调用是否可控”Function 层关注“行为是否可审计”Agent 层关注“输入输出是否合规”开发者可以在不侵入 Agent 核心逻辑的前提下 构建一个可治理、可审计、可扩展的企业级 AI 系统。源代码地址https://github.com/bingbing-gui/aspnetcore-developer/tree/master/src/09-AI-Agent/Agent-Framework/14-Agent-Middleware

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询