Архитектура конвейера агента

Агенты в Microsoft Agent Framework используют многоуровневую архитектуру конвейера для обработки запросов. Понимание этой архитектуры помогает настроить поведение агента путем добавления промежуточного слоя, контекстных провайдеров или изменений клиентского уровня на соответствующем уровне.

Конвейер ChatClientAgent

Архитектура конвейера агента C#

ChatClientAgent создает конвейер с тремя основными слоями.

  1. Промежуточное программное обеспечение агента — необязательные декораторы, которые оборачивают агент через .Use() для ведения журнала, проверки или преобразования
  2. Уровень контекста — управляет журналом чата (ChatHistoryProvider) и внедряет дополнительный контекст (AIContextProviders)
  3. Уровень клиента чата — с необязательными декораторами, которые обрабатывают взаимодействие LLM посредством промежуточного слоя

При вызове RunAsync()запрос передается по каждому уровню последовательности.

Конвейер агента

Архитектура конвейера агента Python

Класс Agent создает конвейер с помощью композиции классов с двумя основными компонентами:

Агент (внешний компонент):

  1. Промежуточное программное обеспечение агента + телеметрияAgentMiddlewareLayer и AgentTelemetryLayer классы обрабатывают вызовы промежуточного слоя и интеграцию OpenTelemetry
  2. RawAgent — основная логика агента, которая вызывает поставщиков контекстов и собирает добавленное поставщиком промежуточное ПО
  3. Поставщики контекстов — единый context_providers список управляет историей, дополнительным контекстом и промежуточными программами для чата или функций.

ChatClient (отдельный и взаимозаменяемый компонент):

  1. FunctionInvocation — обрабатывает цикл вызова средства, вызывая промежуточное ПО функции и телеметрию для каждого вызова средства.
  2. Промежуточное ПО чата + телеметрия — необязательные уровни цепочки промежуточного ПО и инструментирования, включая любое ПО для чата, добавленное поставщиками контекстов, выполняемое для каждого вызова модели.
  3. RawChatClient — реализация для конкретного поставщика (Azure OpenAI, OpenAI, Anthropic и т. д.), которая взаимодействует с LLM

При вызове run()запрос передается через слои агента, а затем в конвейер ChatClient для взаимодействия LLM.

Архитектура конвейера агента

Архитектура конвейера Go Agent

В Go агенты используют многослойную цепочку промежуточного ПО. Промежуточные обработчики оборачивают функцию агента Run, и каждый вызывает next, передавая управление следующему слою.

При запуске агента его жизненный цикл применяется в следующем порядке:

  1. Пользовательское промежуточное ПО агента — ваш зарегистрированный agent.Config.Middlewares, применяемый в порядке объявления на протяжении всего жизненного цикла агента
  2. Поставщик журнала — загружает предыдущие сообщения и позже сохраняет сообщения запроса и ответа
  3. Поставщики контекста — внедрение контекста, параметров и состояния из зарегистрированных agent.ContextProvider экземпляров
  4. Промежуточное ПО поставщика — промежуточное ПО, зарегистрированное поставщиком, например автоматический вызов инструментов, структурированные выходные данные и формирование ответов
  5. Поставщик — базовый поставщик LLM, например 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, который управляет передачей диапазонов, событий и метрик в настроенный бэкенд 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},
    },
})

Подробные шаблоны по промежуточному слою и наблюдаемости см. в Agent Middleware и Observability.

Слой контекста

Слой контекста работает до каждого вызова 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},
    },
})

Подробные шаблоны поставщиков контекста см. в разделе "Поставщики контекстов".

Уровень клиента чата

Уровень клиента чата обрабатывает фактическое взаимодействие со службой 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.")

В 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. ChatHistoryProvider и AIContextProviders уведомляются о новых сообщениях

Конвейер агента:

  1. ПО промежуточного слоя агента + телеметрия выполняет ПО промежуточного слоя (если настроено) и записывает диапазоны
  2. RawAgent вызывает поставщиков контекста для загрузки истории, добавления контекста и сбора промежуточного ПО для чата или функций, добавленного поставщиком.
  3. Запрос передается в ChatClient

Конвейер ChatClient:

  1. FunctionInvocation управляет циклом вызова средства
    • Для каждого вызова инструмента выполняется ПО промежуточного слоя функций и телеметрии, включая любое ПО промежуточного слоя функций, добавленное поставщиками контекста.
  2. Промежуточное ПО для чата и телеметрии выполняется при вызове модели (если настроено), включая любое добавленное поставщиками контекста.
  3. RawChatClient обрабатывает специфичную для поставщика связь LLM
  4. Ответ возвращается через те же слои
  5. Поставщики контекстов получают уведомления о новых сообщениях для хранения.

Замечание

Специализированные агенты могут работать иначе, чем это описано в данной схеме.

  1. Пользовательское промежуточное ПО агента выполняется первым и охватывает весь жизненный цикл агента.
  2. Поставщик журнала загружает журнал бесед для текущего сеанса, если локальная история активна.
  3. Поставщики контекстов добавляют сообщения, параметры или состояние перед вызовом поставщика.
  4. Промежуточное ПО провайдера выполняется, включая промежуточное ПО для автоматического вызова инструментов и обработку структурированного вывода, если они включены.
  5. Поставщик отправляет запрос модели.
  6. Обновления ответа передаются обратно через промежуточное ПО поставщика и пользовательское промежуточное ПО агента.
  7. Поставщики журнала и поставщики контекстов хранят состояние ответа после успешного выполнения.

Другие типы агентов

Не все агенты используют полный 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 не использует локальный клиент чата, промежуточное программное обеспечение для чата всё ещё не применяется.

Дальнейшие действия