代理管道架构
MAF 中的 Agent 使用分层管道架构来处理请求。理解这一架构有助于在适当的层添加中间件、上下文提供程序或进行客户端级别的修改,来自定义 Agent 的行为。
ChatClientAgent 管道总览
用户请求
│
▼
┌──────────────────────────────────┐
│ 代理中间件层 (Agent Middleware) │ ← .Use() 装饰器(日志、验证、转换)
│ 包装整个代理执行 │
└──────────────┬───────────────────┘
▼
┌──────────────────────────────────┐
│ 上下文层 │
│ ├─ ChatHistoryProvider (单一) │ ← 管理对话历史
│ └─ AIContextProviders (列表) │ ← 注入记忆、RAG、动态指令
└──────────────┬───────────────────┘
▼
┌──────────────────────────────────┐
│ 聊天客户端层 (IChatClient) │ ← 与 LLM 通信
│ └─ IChatClient 中间件 (可选) │ ← .Use() 修饰
└──────────────┬───────────────────┘
▼
LLM 推理当调用 RunAsync() 时,请求按顺序流经每个层,响应再按相反路径返回。
代理中间件层
代理中间件会截获对代理的运行方法的每个调用,使你能够检查或修改输入和输出。
添加中间件
var middlewareAgent = originalAgent
.AsBuilder()
.Use(runFunc: MyAgentMiddleware,
runStreamingFunc: MyStreamingMiddleware)
.Build();使用 AI 上下文提供程序作为中间件
MessageAIContextProvider 可作为代理中间件使用,将额外的消息注入请求:
var contextAgent = originalAgent
.AsBuilder()
.UseAIContextProviders(new MyMessageContextProvider())
.Build();关键优势:代理中间件适用于任何代理类型(AIAgent 子类),包括 A2AAgent、GitHubCopilotAgent 等,而不仅仅是 ChatClientAgent。但这也意味着此级别的修饰器不能对底层代理类型做假设——它们仅限于通用功能。
上下文层
上下文层在每次 LLM 调用之前运行,以生成完整的消息历史记录并注入其他上下文。
ChatClientAgent 具有两种不同的提供程序类型:
| 提供程序 | 数量 | 职责 |
|---|---|---|
ChatHistoryProvider | 单一 | 管理对话历史记录的存储和检索 |
AIContextProviders | 列表 | 注入其他上下文(记忆、检索的文档、动态指令) |
var agent = new ChatClientAgent(chatClient,
new ChatClientAgentOptions
{
ChatHistoryProvider = new InMemoryChatHistoryProvider(),
AIContextProviders = [
new MyMemoryProvider(),
new MyRagProvider()
],
});Agent 先调用每个提供程序 InvokingAsync() 方法,然后再将消息发送到聊天客户端,并将每个提供程序的输出作为输入传递给下一个提供程序。
聊天客户端层
聊天客户端层处理与 LLM 服务的实际通信。ChatClientAgent 使用一个 IChatClient 实例,可以用额外的中间件进行修饰。
var chatClient = new AIProjectClient(endpoint, credential)
.GetProjectOpenAIClient()
.GetProjectResponsesClient()
.AsIChatClient(deploymentName)
.AsBuilder()
.Use(CustomChatClientMiddleware)
.Build();
var agent = new ChatClientAgent(
chatClient,
instructions: "You are helpful.");同样可以在客户端级别使用 AIContextProvider 来增强消息、工具和指令:
var chatClient = new AIProjectClient(endpoint, credential)
.GetProjectOpenAIClient()
.GetProjectResponsesClient()
.AsIChatClient(deploymentName)
.AsBuilder()
.UseAIContextProviders(new MyContextProvider())
.Build();
var agent = new ChatClientAgent(
chatClient,
instructions: "You are helpful.");默认情况下,
ChatClientAgent会为提供的聊天客户端添加函数调用支持。设置UseProvidedChatClientAsIs = true选项可以跳过此默认包装。
完整执行流
- 代理中间件执行(如果已配置)
- ChatHistoryProvider 将对话历史记录加载到请求消息列表中
- AIContextProviders 向请求添加消息、工具或指令
- IChatClient 中间件执行(如果已修饰)
- IChatClient 将请求发送到 LLM
- 响应通过相同的层反向返回
- ChatHistoryProvider 和 AIContextProviders 收到新消息的通知
其他代理类型的管道
并非所有代理都使用完整的 ChatClientAgent 管道。A2AAgent、GitHubCopilotAgent 或 CopilotStudioAgent 与远程服务通信,而不是使用本地 IChatClient。但是,它们仍支持代理级中间件:
// Agent middleware works with any AIAgent
var a2aAgent = originalA2AAgent
.AsBuilder()
.Use(runFunc: LoggingMiddleware)
.UseAIContextProviders(new MyMessageContextProvider())
.Build();下一步:多模态 — 为 Agent 添加图像分析能力。