代理管線架構

Microsoft Agent Framework 中的代理程式採用分層管線架構來處理請求。 了解此架構有助於你透過在適當層級加入中介軟體、情境提供者或用戶端層級的修改,來自訂代理行為。

ChatClientAgent 管線

C# 代理管線架構

ChatClientAgent 建構出由三個主要層組成的管線:

  1. 代理中介軟體 - 選用的修飾器,可 .Use() 透過包裝代理進行日誌記錄、驗證或轉換
  2. 上下文層 - 管理聊天歷史ChatHistoryProvider()並注入額外的上下文(AIContextProviders
  3. 聊天用戶端層 —— IChatClient 配備可選的中介軟體裝飾器,負責大型語言模型通訊

當你呼叫 RunAsync()時,請求會依序通過每一層。

代理流程

Python 代理管線架構

Agent 類別透過類別組合建立一個管道,包含兩個主要部分:

代理人 (外部成分):

  1. 代理中介軟體 + 遙測——AgentMiddlewareLayerAgentTelemetryLayer 類別負責中介軟體調用與 OpenTelemetry 工具化
  2. RawAgent - 核心代理邏輯,呼叫上下文提供者並收集提供者新增的中介軟體
  3. 情境提供者 - 統一 context_providers 清單管理歷史、額外情境及每次執行的聊天/功能中介軟體

ChatClient (獨立且可互換的元件):

  1. FunctionInvocation - 處理工具呼叫迴圈,每次工具呼叫時調用函式中介軟體和進行遙測
  2. 聊天中介軟體 + 遙測 - 可選的中介軟體鏈與儀器層,包含上下文提供者新增的任何聊天中介軟體,依模型呼叫執行
  3. RawChatClient - 提供者專用實作(Azure OpenAI、OpenAI、Anthropic 等),與大型語言模型(Large Language Model, LLM)通訊

當你呼叫 run()時,你的請求會經過代理層,然後進入 ChatClient 管道進行 LLM 通訊。

可選的 Agent Hooks 功能可將一個中介軟體套件安裝於代理、聊天及功能層。 核心串流閘控和持久化閘控會延伸此邊界,確保輸出不會在適用的判定結果允許之前就被釋出或儲存。

代理管線架構

Go 代理程式管線架構

在 Go 中,代理使用分層中介軟體管線。 中介層會包裹代理程式的 Run 函式,每一層都會呼叫 next,將控制權傳遞給下一層。

當代理程式執行時,其生命週期會依下列順序套用:

  1. 自訂代理程式中介軟體 —— 你註冊的 agent.Config.Middlewares,依宣告順序套用於整個代理程式生命週期
  2. 歷史提供者 - 載入先前訊息,之後儲存請求/回應訊息
  3. 情境提供者 - 從註冊 agent.ContextProvider 實例注入情境、選項與狀態
  4. 提供者中介軟體 -提供者註冊的中介軟體,如工具自動呼叫、結構化輸出與回應撰寫
  5. 提供者 - 底層大型語言模型提供者,例如 OpenAI 或 Anthropic

代理中介軟體層

代理中介軟體會攔截每一次呼叫代理執行方法,讓你能檢查或修改輸入與輸出。

使用代理建構器模式新增中介軟體:

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,負責傳送 span、事件與指標到已設定的 OpenTelemetry 後端。 這兩層如果沒設定好,都沒什麼作用。

透過實作 Middleware 介面,或使用 agent.MiddlewareFunc 新增輕量型中介軟體:

type Middleware interface {
    Run(next RunFunc, ctx context.Context, messages []*message.Message,
        options ...agent.Option) iter.Seq2[*agent.ResponseUpdate, error]
}

每個中介軟體都會接收鏈中的 next 函式,並可在呼叫 next 前修改訊息或選項、在呼叫 next 後處理回應,或直接短路整個管線。

timing := agent.MiddlewareFunc(
    func(next agent.RunFunc, ctx context.Context, messages []*message.Message, options ...agent.Option) iter.Seq2[*agent.ResponseUpdate, error] {
        start := time.Now()
        return func(yield func(*agent.ResponseUpdate, error) bool) {
            defer log.Printf("agent run completed in %s", time.Since(start))
            for update, err := range next(ctx, messages, options...) {
                if !yield(update, err) {
                    return
                }
            }
        }
    },
)

a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
    Config: agent.Config{
        Middlewares: []agent.Middleware{timing},
    },
})

如需詳細的中介軟體與可觀察性模式,請參見 代理中介軟體可觀察性。

上下文層

上下文層會在每次 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 管道之前,會依提供者順序展平這些新增內容。

情境提供者會在代理程式生命週期內執行,時間點是在自訂中介軟體進入該次執行之後,並在提供者中介軟體呼叫模型之前。 情境提供者可以在提供者呼叫前加入訊息或選項,並在執行後持續維持狀態。

a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
    Config: agent.Config{
        ContextProviders: []agent.ContextProvider{memoryProvider},
    },
})

欲了解詳細的情境提供者模式,請參見 情境提供者

聊天用戶端層

聊天客戶端層負責處理與大型語言模型服務的實際通訊。

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.")

RawChatClient ChatClient 內部實作了提供者專屬邏輯,用於與不同 LLM 服務溝通。

提供者中介層會在歷程與上下文提供者之後執行,並緊接在底層 LLM 提供者之前執行。 代理層級的輔助工具如 OpenTelemetry 和執行日誌被註冊為自訂代理中介軟體,並包裝早期的生命週期步驟。

組件 Registration 層級 Purpose
自動呼叫 agent/harness/toolautocall 供應者中介軟體 自動叫用函式工具
結構化輸出 agent.WithStructuredOutput 供應者中介軟體 處理結構化輸出解析
OpenTelemetry provider/otelprovider 代理中介軟體 追蹤代理程式叫用
運行記錄器 agent.Config.Logger 代理中介軟體 記錄代理互動

agent.ContextProvider 值是生命週期元件,而非 agent.Middleware 實作。 它們是在自訂代理中介軟體和提供者中介軟體之間運行的。

執行流程

當你呼叫代理時,請求會透過管線流動:

  1. 代理中介軟體執行(若已設定)
  2. ChatHistoryProvider 會將對話歷史載入請求訊息清單
  3. AIContextProviders 會在請求中加入訊息、工具或指示
  4. IChatClient 中介軟體 執行(如果有裝飾)
  5. IChatClient 會將請求傳送給 LLM
  6. 回應會流經相同的層次
  7. ChatHistoryProviderAIContextProviders 會收到新訊息通知

代理流程:

  1. 代理中介軟體 + 遙測執行 中介軟體(若已設定),並記錄跨度
  2. RawAgent 會呼叫上下文提供者來載入歷史、新增上下文,並收集提供者新增的聊天/功能中介軟體
  3. 請求會轉交給聊天客戶端

ChatClient 流程:

  1. FunctionInvocation 管理工具呼叫迴圈
    • 每次工具呼叫都會執行 Function Middleware + Telemetry ,包括由上下文提供者新增的任何函式中介軟體
  2. 聊天中介軟體 + 遙測 (若設定後)執行每個模型呼叫,包括上下文提供者新增的任何聊天中介軟體
  3. RawChatClient 處理提供者專屬的 LLM 通訊
  4. 回應會流經相同的層次
  5. 情境提供者 會收到新的訊息儲存通知

Note

專業代理人的運作方式可能與此處描述的管線不同。

  1. 自訂代理中介軟體 會先執行並包裝整個代理生命週期。
  2. 歷史提供者 會在當地歷史啟動時載入當前會話的對話歷史。
  3. 情境提供者 會在提供者呼叫前加入訊息、選項或狀態。
  4. 提供者中介軟體會執行;若已啟用,則包括工具自動呼叫中介軟體及結構化輸出處理。
  5. 提供者將請求發送給模型。
  6. 回應更新會透過提供者中介軟體和自訂代理中介軟體回傳。
  7. 歷史提供者上下文提供者 會在成功執行後儲存回應狀態。

其他藥劑類型

並非所有代理程式都會使用完整的 ChatClientAgent 作業流程。 代理程式如 A2AAgentGitHubCopilotAgentCopilotStudioAgent 與遠端服務通訊,而非使用本地 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();

Note

你不能在這些代理上加入聊天客戶端中介軟體,因為它們不使用 IChatClient.

其他藥劑類型

並非每個 Python 代理程式都使用完整的 Agent + ChatClient 管線。 GitHubCopilotAgent例如,透過 GitHub Copilot CLI 而非本地聊天客戶端發送請求。

即便如此,Python GitHubCopilotAgent 仍然支援代理中介軟體,並且現在會繞 context_providers 過每個調用。 提供者新增的訊息與指示會包含在發送給 Copilot 的提示中,當回應可用時,提供者會收到相應 after_run 的回撥。

Note

因為 GitHubCopilotAgent 不使用本地聊天客戶端,聊天客戶端中介軟體仍然不適用。

下一步