Arquitetura do pipeline de agentes

Os agentes do Microsoft Agent Framework usam uma arquitetura de pipeline em camadas para processar solicitações. Entender essa arquitetura ajuda você a personalizar o comportamento do agente adicionando middleware, provedores de contexto ou modificações no nível do cliente na camada apropriada.

ChatClientAgent Pipeline

Arquitetura de pipeline do agente C#

ChatClientAgent constrói um pipeline com três camadas principais:

  1. Middleware do agente — Decoradores opcionais que envolvem o agente via .Use() para registro, validação ou transformação
  2. Camada de contexto – gerencia o histórico de chat (ChatHistoryProvider) e injeta contexto adicional (AIContextProviders)
  3. Camada do cliente de chat — A IChatClient com decoradores de middleware opcionais que lidam com a comunicação LLM

Quando você chama RunAsync(), sua solicitação flui por cada camada em sequência.

Pipeline de Agentes

Arquitetura de pipeline do Python Agent

A classe Agent constrói um pipeline por meio da composição de classes com dois componentes principais:

Agente (componente externo):

  1. Middleware do agente + Telemetria — as classes AgentMiddlewareLayer e AgentTelemetryLayer lidam com a invocação do middleware e a instrumentação do OpenTelemetry
  2. RawAgent – Lógica do agente principal que invoca provedores de contexto e coleta middleware adicionado pelo provedor
  3. Provedores de Contexto – Lista unificada context_providers gerencia histórico, contexto adicional e middleware para chat e funções em cada execução

ChatClient (componente separado e intercambiável):

  1. FunctionInvocation — Lida com o loop de chamada da ferramenta, invocando o Middleware da Função + Telemetria por chamada da ferramenta
  2. Middleware do chat + Telemetria — Cadeia de middleware opcional e camadas de instrumentação, incluindo qualquer middleware de chat adicionado pelos provedores de contexto, executado por chamada de modelo
  3. RawChatClient – Implementação específica do provedor (Azure OpenAI, OpenAI, Antropic etc.) que se comunica com o LLM

Quando você chama run(), sua solicitação flui pelas camadas do Agente e, em seguida, para o pipeline do ChatClient para comunicação LLM.

Arquitetura do pipeline de agentes

Arquitetura do pipeline do Go Agent

No Go, os agentes usam um pipeline de middleware em camadas. Os middlewares encapsulam a função Run do agente, cada um chamando next para passar o controle para a próxima camada.

Quando um agente é executado, seu ciclo de vida é aplicado nesta ordem:

  1. Middleware personalizado do agente — Seu agent.Config.Middlewaresregistrado, aplicado na ordem de declaração em todo o ciclo de vida do agente
  2. Provedor de histórico – Carrega mensagens anteriores e, posteriormente, armazena mensagens de solicitação/resposta
  3. Provedores de contexto - Injeta contexto, opções e estado de instâncias agent.ContextProvider registradas
  4. Middleware do provedor – middleware registrado pelo provedor, como chamada automática de ferramenta, saídas estruturadas e criação de resposta
  5. Provedor - O provedor de LLM subjacente, como OpenAI ou Anthropic

Camada de middleware do agente

O middleware do agente intercepta todas as chamadas para o método de execução do agente, permitindo que você inspecione ou modifique entradas e saídas.

Adicione middleware usando o padrão do construtor de agentes:

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

Você também pode usar MessageAIContextProvider como middleware de agente para injetar mensagens adicionais na solicitação. Isso funciona com qualquer tipo de agente, não apenas ChatClientAgent:

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

Essa camada encapsula toda a execução do agente, incluindo resolução de contexto e chamadas de cliente de chat. Isso tem benefícios, porque esses decoradores podem ser usados com qualquer tipo de agente, por exemplo A2AAgent , ou GitHubCopilotAgent, não apenas ChatClientAgent. Isso também significa que os decoradores neste nível não podem necessariamente fazer suposições sobre o agente que estão decorando, o que significa que estão restritos a personalizar ou afetar funcionalidades comuns.

Adicione middleware ao criar o agente:

from agent_framework import Agent

agent = Agent(
    client=my_client,
    instructions="You are helpful.",
    middleware=[my_middleware_func],
)

A classe Agent herda de AgentMiddlewareLayer, que gerencia a invocação das funções de middleware antes de delegar para a lógica central do agente. Ele também herda de AgentTelemetryLayer, que lida com a emissão de spans, eventos e métricas para um backend OpenTelemetry configurado. Essas duas camadas não fazem nada quando não estão configuradas.

Adicione middleware implementando a interface Middleware ou usando agent.MiddlewareFunc para middleware leve:

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

Cada middleware recebe a função next na cadeia e pode modificar mensagens ou opções antes de chamar next, processar respostas após chamar next ou interromper o pipeline.

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},
    },
})

Para obter padrões detalhados de middleware e observabilidade, consulte Middleware do Agente e Observabilidade.

Camada de contexto

A camada de contexto é executada antes de cada chamada LLM para criar o histórico de mensagens completo e injetar contexto adicional.

ChatClientAgent tem dois tipos de provedor distintos:

  • ChatHistoryProvider (único) – Gerencia o armazenamento e a recuperação do histórico de conversas
  • AIContextProviders (lista) - Injeta contexto adicional, como memórias, documentos recuperados ou instruções dinâmicas
var agent = new ChatClientAgent(chatClient, new ChatClientAgentOptions
{
    ChatHistoryProvider = new InMemoryChatHistoryProvider(),
    AIContextProviders = [new MyMemoryProvider(), new MyRagProvider()],
});

O agente invoca o método de cada provedor antes de enviar mensagens para o cliente de chat, fazendo com que a saída de cada provedor seja passada como entrada para o próximo provedor.

A Agent classe usa uma lista unificada context_providers que pode incluir provedores de histórico e provedores de contexto:

from agent_framework import Agent, InMemoryHistoryProvider

agent = Agent(
    client=my_client,
    context_providers=[
        InMemoryHistoryProvider(),
        MyMemoryProvider(),
        MyRagProvider(),
    ],
)

Os provedores de contexto também podem anexar middleware de chat ou função a uma única invocação via SessionContext.extend_middleware(). O agente nivela essas adições na ordem do provedor antes de entrar no pipeline do ChatClient.

Os provedores de contexto são executados dentro do ciclo de vida do agente, depois que o middleware personalizado entra na execução e antes que o middleware do provedor chame o modelo. Os provedores de contexto podem adicionar mensagens ou opções antes da chamada do provedor e manter o estado após a execução.

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

Para obter padrões detalhados do provedor de contexto, consulte Provedores de Contexto.

Camada de cliente de chat

A camada do cliente de chat lida com a comunicação propriamente dita com o serviço LLM.

ChatClientAgent usa uma IChatClient instância, que pode ser decorada com middleware adicional:

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

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

Você também pode usar AIContextProvider como middleware de cliente de chat para enriquecer mensagens, ferramentas e instruções no nível do cliente. Isso deve ser usado no contexto de um AIAgent em execução:

var chatClient = new AIProjectClient(endpoint, credential)
    .GetProjectOpenAIClient()
    .GetProjectResponsesClient()
    .AsIChatClient(deploymentName)
    .AsBuilder()
    .UseAIContextProviders(new MyContextProvider())
    .Build();

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

Por padrão, ChatClientAgent encapsula o cliente de chat fornecido com suporte para chamadas de funções. Defina UseProvidedChatClientAsIs = true nas opções para ignorar esse encapsulamento padrão.

A Agent classe aceita qualquer cliente que implemente SupportsChatGetResponse. O pipeline do ChatClient manipula middleware, telemetria, invocação de funções e comunicação específica do provedor.

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

O RawChatClient dentro do ChatClient implementa a lógica específica do provedor para comunicação com diferentes serviços LLM.

O middleware do provedor é executado após os provedores de histórico e contexto, imediatamente antes do provedor LLM subjacente. Auxiliares de nível de agente, como OpenTelemetry e registro de execução, são registrados como middleware de agente personalizado e encapsulam as etapas anteriores do ciclo de vida.

Componente Registration Camada Purpose
Chamada automática agent/harness/toolautocall Middleware do provedor Invoca automaticamente ferramentas de função
Saída estruturada agent.WithStructuredOutput Middleware do provedor Lida com a análise sintática de saída estruturada
OpenTelemetry provider/otelprovider Middleware do agente Rastreia invocações de agente
Registrador de execução agent.Config.Logger Middleware do agente Registra as interações do agente

Os valores de agent.ContextProvider são componentes do ciclo de vida, e não implementações de agent.Middleware. Eles são executados entre o middleware de agente personalizado e o middleware de provedor.

Fluxo de execução

Quando você invoca um agente, a solicitação flui pelo pipeline:

  1. O middleware do agente Agent middleware é executado (se configurado)
  2. ChatHistoryProvider carrega o histórico de conversas na lista de mensagens de solicitação
  3. AIContextProviders adicionam mensagens, ferramentas ou instruções à solicitação
  4. O middleware do cliente IChat IChatClient middleware é executado (se decorado)
  5. O IChatClient envia a solicitação para a LLM
  6. A resposta flui de volta pelas mesmas camadas
  7. ChatHistoryProvider e AIContextProviders são notificados sobre novas mensagens

Pipeline do agente:

  1. O middleware do agente + telemetria Agent middleware + telemetria é executado (se configurado) e registra os spans
  2. RawAgent invoca provedores de contexto para carregar o histórico, adicionar contexto e coletar middleware de chat/função adicionado pelo provedor
  3. A solicitação é passada para o ChatClient

Pipeline do ChatClient:

  1. FunctionInvocation gerencia o loop de chamada da ferramenta
    • Para cada chamada de ferramenta, o middleware da função + telemetria Function Middleware + telemetria é executado, incluindo qualquer middleware de função adicionado pelos provedores de contexto
  2. O middleware do chat + telemetria Chat Middleware + telemetria é executado por chamada de modelo (se configurado), incluindo qualquer middleware de chat adicionado pelos provedores de contexto
  3. RawChatClient gerencia a comunicação LLM específica do provedor
  4. A resposta flui de volta pelas mesmas camadas
  5. Os provedores de contexto são notificados sobre novas mensagens para armazenamento

Observação

Agentes especializados podem funcionar de maneira diferente do pipeline descrito aqui.

  1. O middleware do agente personalizado é executado primeiro e encapsula o ciclo de vida completo do agente.
  2. O provedor de histórico carrega o histórico de conversas para a sessão atual quando o histórico local está ativo.
  3. Os provedores de contexto adicionam mensagens, opções ou estado antes da chamada do provedor.
  4. O middleware do provedor Provider middleware é executado, incluindo o middleware de chamada automática da ferramenta e o tratamento de saída estruturada quando habilitado.
  5. O provedor envia a solicitação para o modelo.
  6. As atualizações de resposta fluem de volta pelo middleware do provedor e pelo middleware personalizado do agente.
  7. Provedores de histórico e provedores de contexto armazenam o estado de resposta após uma execução bem-sucedida.

Outros tipos de agente

Nem todos os agentes utilizam a totalidade do ChatClientAgent pipeline. Agentes como A2AAgent, GitHubCopilotAgentou CopilotStudioAgent se comunicam com serviços remotos em vez de usar um local IChatClient. No entanto, eles ainda dão suporte ao middleware no nível do agente.

Outros Tipos de Agentes Pipeline

Como esses agentes derivam de AIAgent, você pode usar os mesmos padrões de middleware de agente:

// 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();

Observação

Você não pode adicionar middleware de cliente de chat a esses agentes porque eles não usam IChatClient.

Outros tipos de agente

Nem todo agente do Python usa o pipeline completo Agent + ChatClient . GitHubCopilotAgent, por exemplo, envia solicitações por meio da CLI do GitHub Copilot em vez de um cliente de chat local.

Mesmo assim, o Python GitHubCopilotAgent ainda suporta middleware de agente e agora executa context_providers em torno de cada invocação. Mensagens e instruções adicionadas pelo provedor são incluídas no prompt enviado ao Copilot, e os provedores recebem o retorno de chamada after_run correspondente assim que uma resposta estiver disponível.

Observação

Como GitHubCopilotAgent não usa um cliente de chat local, o middleware do cliente de chat ainda não se aplica.

Próximas Etapas