Skip to content

代理管道架构

MAF 中的 Agent 使用分层管道架构来处理请求。理解这一架构有助于在适当的层添加中间件、上下文提供程序或进行客户端级别的修改,来自定义 Agent 的行为。


ChatClientAgent 管道总览

用户请求


┌──────────────────────────────────┐
│  代理中间件层 (Agent Middleware)  │ ← .Use() 装饰器(日志、验证、转换)
│  包装整个代理执行                  │
└──────────────┬───────────────────┘

┌──────────────────────────────────┐
│  上下文层                         │
│  ├─ ChatHistoryProvider (单一)    │ ← 管理对话历史
│  └─ AIContextProviders (列表)     │ ← 注入记忆、RAG、动态指令
└──────────────┬───────────────────┘

┌──────────────────────────────────┐
│  聊天客户端层 (IChatClient)        │ ← 与 LLM 通信
│  └─ IChatClient 中间件 (可选)      │ ← .Use() 修饰
└──────────────┬───────────────────┘

            LLM 推理

当调用 RunAsync() 时,请求按顺序流经每个层,响应再按相反路径返回。

代理中间件层

代理中间件会截获对代理的运行方法的每个调用,使你能够检查或修改输入和输出。

添加中间件

csharp
var middlewareAgent = originalAgent
    .AsBuilder()
    .Use(runFunc: MyAgentMiddleware,
         runStreamingFunc: MyStreamingMiddleware)
    .Build();

使用 AI 上下文提供程序作为中间件

MessageAIContextProvider 可作为代理中间件使用,将额外的消息注入请求:

csharp
var contextAgent = originalAgent
    .AsBuilder()
    .UseAIContextProviders(new MyMessageContextProvider())
    .Build();

关键优势:代理中间件适用于任何代理类型(AIAgent 子类),包括 A2AAgentGitHubCopilotAgent 等,而不仅仅是 ChatClientAgent。但这也意味着此级别的修饰器不能对底层代理类型做假设——它们仅限于通用功能。

上下文层

上下文层在每次 LLM 调用之前运行,以生成完整的消息历史记录并注入其他上下文。

ChatClientAgent 具有两种不同的提供程序类型:

提供程序数量职责
ChatHistoryProvider单一管理对话历史记录的存储和检索
AIContextProviders列表注入其他上下文(记忆、检索的文档、动态指令)
csharp
var agent = new ChatClientAgent(chatClient,
    new ChatClientAgentOptions
    {
        ChatHistoryProvider = new InMemoryChatHistoryProvider(),
        AIContextProviders = [
            new MyMemoryProvider(),
            new MyRagProvider()
        ],
    });

Agent 先调用每个提供程序 InvokingAsync() 方法,然后再将消息发送到聊天客户端,并将每个提供程序的输出作为输入传递给下一个提供程序。

聊天客户端层

聊天客户端层处理与 LLM 服务的实际通信。ChatClientAgent 使用一个 IChatClient 实例,可以用额外的中间件进行修饰。

csharp
var chatClient = new AIProjectClient(endpoint, credential)
    .GetProjectOpenAIClient()
    .GetProjectResponsesClient()
    .AsIChatClient(deploymentName)
    .AsBuilder()
    .Use(CustomChatClientMiddleware)
    .Build();

var agent = new ChatClientAgent(
    chatClient,
    instructions: "You are helpful.");

同样可以在客户端级别使用 AIContextProvider 来增强消息、工具和指令:

csharp
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 选项可以跳过此默认包装。

完整执行流

  1. 代理中间件执行(如果已配置)
  2. ChatHistoryProvider 将对话历史记录加载到请求消息列表中
  3. AIContextProviders 向请求添加消息、工具或指令
  4. IChatClient 中间件执行(如果已修饰)
  5. IChatClient 将请求发送到 LLM
  6. 响应通过相同的层反向返回
  7. ChatHistoryProvider 和 AIContextProviders 收到新消息的通知

其他代理类型的管道

并非所有代理都使用完整的 ChatClientAgent 管道。A2AAgentGitHubCopilotAgentCopilotStudioAgent 与远程服务通信,而不是使用本地 IChatClient。但是,它们仍支持代理级中间件

csharp
// Agent middleware works with any AIAgent
var a2aAgent = originalA2AAgent
    .AsBuilder()
    .Use(runFunc: LoggingMiddleware)
    .UseAIContextProviders(new MyMessageContextProvider())
    .Build();

下一步:多模态 — 为 Agent 添加图像分析能力。

学而不思则罔,思而不学则殆