Microsoft Agent Framework 中的代理使用分层管道体系结构来处理请求。 了解这一架构有助于您通过在适当的层添加中间件、上下文提供程序或进行客户端级别的修改,来自定义代理的行为。
ChatClientAgent 管道
构建 ChatClientAgent 的管道包含三个主要层:
-
代理中间件 - 可通过
.Use()来包装代理的可选装饰器,用于记录、验证或转换 -
上下文层 - 管理聊天历史记录(
ChatHistoryProvider)并注入其他上下文(AIContextProviders) -
聊天客户端层 -
IChatClient使用可选的中间件修饰器来处理 LLM 通信
调用 RunAsync()时,请求按顺序流经每个层。
代理管道
该 Agent 类使用两个主要组件通过类组合生成管道:
代理 (外部组件):
-
代理中间件 + 遥测 -
AgentMiddlewareLayer和AgentTelemetryLayer类处理中间件调用和 OpenTelemetry 检测 - RawAgent - 核心代理逻辑,用于调用上下文提供程序并收集提供程序添加的中间件
-
上下文提供程序 - 统一
context_providers列表管理历史记录、其他上下文和每次运行的聊天/功能中间件
ChatClient (独立组件和可互换组件):
- FunctionInvocation - 处理工具调用循环,调用功能中间件 + 每次工具调用的遥测
- 聊天中间件 + 遥测 - 可选中间件链和检测层,包括由上下文提供程序添加的任何聊天中间件,在每个模型调用期间运行
- RawChatClient - 与 LLM 通信的针对提供商的特殊实现(Azure OpenAI、OpenAI、Anthropic 等)
调用 run()时,请求将流经代理层,然后流入 ChatClient 管道进行 LLM 通信。
代理中间件层
代理中间件会截获对代理的运行方法的每个调用,使你能够检查或修改输入和输出。
使用代理生成器模式添加中间件:
var middlewareAgent = originalAgent
.AsBuilder()
.Use(runFunc: MyAgentMiddleware, runStreamingFunc: MyStreamingMiddleware)
.Build();
还可以用作 MessageAIContextProvider 代理中间件,将其他消息注入请求。 这适用于任何代理类型,而不仅仅是 ChatClientAgent:
var contextAgent = originalAgent
.AsBuilder()
.UseAIContextProviders(new MyMessageContextProvider())
.Build();
此层包装整个代理执行,包括上下文解析和聊天客户端调用。
这有好处,因为这些修饰器可以与任何类型的代理一起使用,例如 A2AAgent ,或者 GitHubCopilotAgent,而不仅仅是 ChatClientAgent。
这也意味着,此级别的修饰器不一定能对正在修饰的代理做出假设,即它们仅限于自定义或影响通用功能。
创建代理时添加中间件:
from agent_framework import Agent
agent = Agent(
client=my_client,
instructions="You are helpful.",
middleware=[my_middleware_func],
)
类 Agent 继承自 AgentMiddlewareLayer该类,该类在委托核心代理逻辑之前处理中间件调用。
它还继承自 AgentTelemetryLayer,该类负责向配置的 OpenTelemetry 后端传送范围、事件和指标。
这两个层在未配置时不执行任何操作。
有关详细的中间件和可观测性模式,请参阅 代理中间件 和 可观测性。
上下文层
上下文层在每次 LLM 调用之前运行,以生成完整的消息历史记录并注入其他上下文。
ChatClientAgent 具有两种不同的提供程序类型。
-
ChatHistoryProvider(单一) - 管理对话历史记录存储和检索 -
AIContextProviders(列表) - 注入其他上下文,如记忆、检索的文档或动态指令
var agent = new ChatClientAgent(chatClient, new ChatClientAgentOptions
{
ChatHistoryProvider = new InMemoryChatHistoryProvider(),
AIContextProviders = [new MyMemoryProvider(), new MyRagProvider()],
});
代理先调用每个提供程序 InvokingAsync() 的方法,然后再将消息发送到聊天客户端,并将每个提供程序的输出作为输入传递给下一个提供程序。
Agent 类使用统一 context_providers 列表,该列表可以包含历史记录提供程序和上下文提供程序。
from agent_framework import Agent, InMemoryHistoryProvider
agent = Agent(
client=my_client,
context_providers=[
InMemoryHistoryProvider(),
MyMemoryProvider(),
MyRagProvider(),
],
)
上下文提供程序还可以通过SessionContext.extend_middleware()将聊天或功能中间件附加到一个调用。 代理在进入 ChatClient 管道之前,按照提供者的顺序将这些附加项展平。
有关详细的上下文提供程序模式,请参阅 上下文提供程序。
聊天客户端层
聊天客户端层处理与 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 作为聊天客户端的中间件,以在客户端级别上增强消息、工具和指令。 这必须在正在运行 AIAgent的上下文中使用:
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 选项以跳过此默认包装。
该 Agent 类接受任何实现的 SupportsChatGetResponse客户端。 ChatClient 管道处理中间件、遥测、函数调用和提供程序特定的通信:
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
client = FoundryChatClient(
credential=credential,
project_endpoint=endpoint,
model=model,
)
agent = Agent(client=client, instructions="You are helpful.")
ChatClient 中的 RawChatClient 实现了与不同 LLM 服务进行通信的提供程序特定逻辑。
执行流
调用代理时,请求将流经管道:
- 代理中间件 执行(如果已配置)
- ChatHistoryProvider 将对话历史记录加载到请求消息列表中
- AIContextProviders 向请求添加消息、工具或说明
- IChatClient 中间件 执行(如果已修饰)
- IChatClient 将请求发送到 LLM
- 响应通过相同的层返回
- ChatHistoryProvider 和 AIContextProviders 收到新消息的通知
代理管道:
- 代理中间件 + 遥测 执行中间件(如果已配置)和记录跨度
- RawAgent 调用上下文提供程序来加载历史记录、添加上下文并收集提供程序添加的聊天/函数中间件
- 请求传递到 ChatClient
ChatClient 流水线:
-
FunctionInvocation 管理工具调用循环
- 在每次工具调用时,函数中间件+遥测都会执行,包括由上下文提供程序添加的任何函数中间件。
- 聊天中间件 + 遥测 在每个模型调用时执行(如果已配置),包括由上下文提供者添加的任何聊天中间件。
- RawChatClient 处理提供程序特定的 LLM 通信
- 响应通过相同的层返回
- 上下文提供程序 会收到用于存储的新消息通知。
注释
专用代理的工作方式可能与此处所述的管道不同。
其他代理类型
并非所有代理都使用完整的 ChatClientAgent 管道。 代理(例如 A2AAgent,GitHubCopilotAgent 或 CopilotStudioAgent)与远程服务通信,而不是使用本地 IChatClient。 但是,它们仍支持代理级中间件。
由于这些代理派生自 AIAgent,因此可以使用相同的代理中间件模式:
// Agent middleware works with any AIAgent
var a2aAgent = originalA2AAgent
.AsBuilder()
.Use(runFunc: LoggingMiddleware)
.UseAIContextProviders(new MyMessageContextProvider())
.Build();
// Same pattern works for GitHubCopilotAgent
var copilotAgent = originalCopilotAgent
.AsBuilder()
.Use(runFunc: AuditMiddleware)
.Build();
注释
无法向这些代理添加聊天客户端中间件,因为它们不使用 IChatClient。
其他代理类型
并非每个 Python 代理都使用完整的 Agent + ChatClient 管道。
GitHubCopilotAgent例如,通过 GitHub Copilot CLI 而不是本地聊天客户端发送请求。
即便如此,Python GitHubCopilotAgent 仍支持代理中间件,现在会围绕每个调用运行 context_providers 。 由提供方添加的消息和说明包含在发送到 Copilot 的提示中,当响应可用后,提供方会接收到匹配的 after_run 回调。
注释
由于 GitHubCopilotAgent 不使用本地聊天客户端,聊天客户端中间件仍不适用。