Агенты, размещенные на платформе Foundry

Размещаемые агенты в службе Microsoft Foundry Agent Service позволяют развертывать агентные приложения в контейнерах в инфраструктуре под управлением Microsoft. Платформа обрабатывает масштабирование, сохраняемость состояния сеанса, безопасность и управление жизненным циклом, чтобы сосредоточиться на логике агента. Размещённые агенты Microsoft Foundry стали общедоступны и поддерживают агентов, созданных на основе вашего собственного кода или с использованием предпочитаемого фреймворка для агентов. В этой статье рассматривается именно интеграция размещения в Agent Framework.

С помощью интеграции размещения Agent Framework можно сделать Agent доступным через протокол Foundry Responses или Invocations с минимальным кодом. Python также поддерживает размещение собственного нативного Workflow напрямую, не преобразовывая его в агент.

Замечание

Вы также можете развернуть код агента, созданный с помощью других фреймворков, в размещённых агентах Foundry с помощью рабочих процессов Azure Developer CLI (azd). С понятиями, не зависящими от платформы, и рекомендациями по развертыванию см. в статье Что такое размещенные агенты? Остальная часть этой статьи посвящена интеграции с Agent Framework.

Когда следует использовать размещенные агенты

Выберите размещенные агенты Foundry, если требуется:

  • Управляемая инфраструктура — не нужно настраивать контейнеры, веб-серверы или правила масштабирования самостоятельно.
  • Встроенное управление сеансами — платформа сохраняет и загруженные файлы между циклами взаимодействия и в периодах простоя.
  • Удостоверение выделенного агента — каждый развернутый агент получает собственное удостоверение Entra для безопасного доступа к моделям, средствам и подчиненным службам.
  • Конечные точки, совместимые с OpenAI , — клиенты могут взаимодействовать с агентом с помощью любого пакета SDK, совместимого с OpenAI, через протокол Responses.
  • Для аудиоагентов реального времени используйте размещённые агенты с Azure Speech в Foundry Tools (Voice Live) для обнаружения голосовой активности на стороне сервера, эхоподавления и шумоподавления. Дополнительные сведения см. в статье Использование Voice Live с размещенными агентами.

Замечание

Интеграция Python agent-framework-foundry-hosting находится в предварительной версии. Размещённые агенты Microsoft Foundry, сервис управляемого хостинга, стали общедоступными.

Prerequisites

  • подписка Azure
  • Интерфейс командной строки разработчика Azure (azd) с расширением для агента ИИ:

Для локального тестирования также требуется:

Установите пакет NuGet для хостинга.

dotnet add package Microsoft.Agents.AI.Foundry.Hosting --prerelease
  • Python 3.10 или более поздней версии

Установите пакет предварительного размещения, клиент Foundry и пакет проверки подлинности Azure:

pip install --pre agent-framework-foundry agent-framework-foundry-hosting azure-identity

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

Протокол ответов

Протокол Responses является рекомендуемой отправной точкой для большинства агентов. Она предоставляет конечную точку, совместимую /responses с OpenAI, и платформа автоматически управляет журналом бесед, потоковой передачей и жизненным циклом сеансов.

У размещённых агентов Python ответ, который прерывается преждевременно, имеет состояние incomplete. Клиенты потоковой передачи получают завершающее событие response.incomplete, а непотоковые клиенты получают status со значением incomplete. Причина завершения content_filter соответствует значению incomplete_details.reason, установленному в content_filter, а length соответствует max_output_tokens. Все созданные выходные данные или содержимое отказа остается доступным в ответе.

using Azure.AI.AgentServer.Core;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry.Hosting;

var projectEndpoint = new Uri(Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
    ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set."));
var deployment = Environment.GetEnvironmentVariable("FOUNDRY_MODEL")
    ?? Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME")
    ?? "gpt-4o";

AIAgent agent = new AIProjectClient(projectEndpoint, new DefaultAzureCredential())
    .AsAIAgent(
        model: deployment,
        instructions: "You are a helpful AI assistant.",
        name: "my-agent");

var builder = AgentHost.CreateBuilder(args);
builder.Services.AddFoundryResponses(agent);
builder.RegisterProtocol("responses", endpoints => endpoints.MapFoundryResponses());

var app = builder.Build();
app.Run();

Создает AgentHost.CreateBuilder хост приложения, предварительно настроенный для среды размещения Foundry. AddFoundryResponses регистрирует агент с помощью обработчика протокола Responses и MapFoundryResponses сопоставляет конечную точку /responses HTTP.

import os

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from agent_framework_foundry_hosting import ResponsesHostServer
from azure.identity import DefaultAzureCredential

client = FoundryChatClient(
    project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
    model=os.environ.get("FOUNDRY_MODEL") or os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
    credential=DefaultAzureCredential(),
)

agent = Agent(
    client=client,
    instructions="You are a helpful AI assistant.",
)

server = ResponsesHostServer(agent)
server.run()

Упаковывает ResponsesHostServer агент и предоставляет его через протокол Foundry Responses. Поле store вызывающей стороны определяет, сохраняются ли внешний ответ, сеанс, управляемый хостом, и статус утверждения. Параметр history_source независимо выбирает, кто предоставляет журнал моделей:

history_source Поведение истории модели
"agent_server" (по умолчанию) Хост восстанавливает сохранённый внешний журнал Responses и отключает хранение в нижестоящем сервисе, чтобы предотвратить дублирование истории.
"service" Хост отправляет только текущий ввод и сохраняет у себя идентификатор продолжения сервиса хранимой модели. Беседа с сохранённым поставщиком не может разветвляться от более раннего ответа.
"agent" Хост отправляет только текущий ввод. Хранилище агента HistoryProvider или параметры хранилища нисходящей службы по умолчанию управляют историей.

Не используйте "service" или "agent_server" вместе с HistoryProvider с поддержкой загрузки. Режим по умолчанию также отклоняет фиксированные варианты продолжения нижестоящего потока, такие как conversation_id, previous_response_idи conversation. Используйте history_source="agent" для пользовательской реализации SupportsAgentRun.

Параметр конструктора response_store выбирает бэкенд для постоянного хранения внешних Responses. Старый параметр store конструктора является устаревшим псевдонимом для response_store; ни один из параметров не задает поле вызывающего объекта для каждого запроса store . Запрос с store=false является одноразовым: он не сохраняет состояние, управляемое хостом, отключает поддерживаемое нижележащее хранилище и не может использовать background=true.

Хост является владельцем предоставленного агента и может добавлять поставщиков контекста, специфичных для хостинга. Не используйте агент повторно с другим хостом и не вызывайте его напрямую после создания хоста.

Хост Responses сохраняет собственные системные вызовы компьютера, снимки экрана и проверки безопасности. Приложение должно выполнить запрошенные действия и явно подтвердить все проверки безопасности. Описание полного процесса см. в разделе Использование локального компьютера.

Выберите экземпляр агента или фабрику

И ResponsesHostServer, и InvocationsHostServer принимают через параметр agent либо экземпляр агента, либо синхронный или асинхронный вызываемый объект без аргументов. Хост повторно использует один и тот же экземпляр в течение всего времени своей работы. Вызываемый объект вызывается один раз для каждого запроса, и возвращаемый агент относится к этому запросу.

Используйте вызываемый элемент, если обычный агент сохраняет изменяемое состояние за пределами AgentSession. Хосты сохраняют только поддерживаемые хранилища сеансов, контрольных точек и утверждений функций, а не произвольные поля в агенте с областью запроса.

Предупреждение

WorkflowAgentРазмещение, например workflow.as_agent(), через agent= устарело. WorkflowAgent сохраняет состояние рабочего процесса в памяти между выполнениями, поэтому один экземпляр никогда не должен обслуживать запросы от разных пользователей или бесед. Размещайте рабочий процесс нативно через workflow= и фабрику, учитывающую запросы.

Пока вы не переносите хост Responses, фабрика, которая создает свежий рабочий процесс, исполнителей, обёрнутых агентов, агентов, клиентов, поставщиков и инструменты для каждого запроса, является безопасным устаревшим вариантом. Сохраняйте стабильное имя рабочего процесса и идентификаторы исполнителей, чтобы узел смог восстановить контрольные точки. Для узла вызовов эта устаревшая форма фабрики подходит только для рабочих процессов без сохранения состояния, выполняемых за один шаг, так как размещение агента не восстанавливает контрольные точки рабочего процесса.

Кроме того, используйте фабрику, когда интеграция содержит идентификатор запроса или управляет ресурсами, специфичными для запроса. Например, создайте внутри фабрики подключения MCP, наборы инструментов, поставщиков навыков, клиентов поиска, поставщиков памяти и их учетные данные, если они используют текущий вызов платформы или контекст пользователя. Повторное использование подключения MCP, общего для всего процесса, может сохранить идентификатор запроса, который его открыл.

Узел вводит и покидает созданные фабрикой агенты для каждого запроса. Agent управляет клиентами, управляемыми через контекст, и инструментами MCP, но ваша фабрика должна закрывать любые другие провайдеры, транспорты или учетные данные, которые она создает. Не закрывайте общие объекты, предоставленные приложением за пределами фабрики.

Разверните собственный рабочий процесс с помощью Responses

Python может выполнять готовый рабочий процесс напрямую через workflow=. Для нативного рабочего процесса требуется callback-функция parse_response, которая сопоставляет текущий запрос Responses с типизированным начальным вводом или полным пакетом ожидающих реплик:

from pydantic import BaseModel

from agent_framework_foundry_hosting import (
    CheckpointStoreProvider,
    HostedResponseRequest,
    ResponsesHostServer,
    WorkflowTurn,
)


class Ticket(BaseModel):
    text: str


def build_workflow(request: HostedResponseRequest):
    return build_fresh_workflow()


async def parse_response(request: HostedResponseRequest) -> WorkflowTurn[Ticket]:
    items = await request.get_input_items()
    if any(item.get("type") in ("function_call_output", "mcp_approval_response") for item in items):
        return WorkflowTurn(responses=await request.get_workflow_responses())

    text = await request.get_input_text()
    return WorkflowTurn(input=Ticket.model_validate_json(text or ""))


server = ResponsesHostServer(
    workflow=build_workflow,
    parse_response=parse_response,
    checkpoint_store_provider=CheckpointStoreProvider(
        allowed_checkpoint_types=[f"{Ticket.__module__}:{Ticket.__qualname__}"],
    ),
)

Используйте синхронную или асинхронную фабрику, учитывающую контекст запроса, для рабочих процессов, которые могут приостанавливаться, продолжаться или восстанавливаться при выполнении фоновой работы. Фабрика должна возвращать недавно созданный граф с новыми изменяемыми исполнителями, агентами, клиентами, поставщиками и инструментами. Сохраняйте стабильное имя рабочего процесса и идентификаторы executor, чтобы узел смог восстановить точную контрольную точку, связанную с внешним ответом.

доверенный пользователь платформы и песочница Foundry изолируют состояние нативного рабочего процесса. Хост проверяет полный пакет ожидающих ответов, прежде чем использовать какие-либо полномочия на ответ. Устаревшие, частичные, повторяющиеся, повторно отправленные, межпользовательские и ответы между песочницами завершаются сбоем до выполнения рабочего процесса. Запрос с store=false не сохраняет состояние рабочего процесса и не может вернуть возобновляемую паузу.

Для устаревшего рабочего процесса, который принимает list[Message], используйте response_input_messages(request) для преобразования только текущего хода Responses. Он не загружает предыдущую внешнюю историю и не декодирует ожидающие ответы workflow. Хостинг agent=workflow.as_agent() остается доступным во время текущей бета-версии, но выдает предупреждение об устаревании. Полные примеры см. в примерах рабочих процессов Responses.

Сохранять состояние и обрабатывать длительные диалоги

ResponsesHostServer и InvocationsHostServer по умолчанию настраивают постоянные хранилища сеансов. AgentSessionStoreProvider предоставляет FoundryAgentSessionStore; сеансы Responses используют логическое хранилище agent_sessions, а сеансы Invocations используют отдельное хранилище invocation_sessions. Эти хранилища используют Хранилище состояний Foundry при размещении в облаке и файловое хранилище SDK при локальном запуске.

Для агентов рабочего процесса Responses CheckpointStoreProvider предоставляет FoundryCheckpointStore. Рабочие процессы Native Responses и Invocations используют один и тот же провайдер для их точных контрольных точек продолжения. FunctionApprovalStoreProvider предоставляет информацию FoundryFunctionApprovalStore об ожидающих утверждениях инструмента агента. Вместо этого запросы и ответы на запросы на утверждение собственного рабочего процесса привязаны к контрольным точкам рабочего процесса.

При запуске в Foundry Python по умолчанию сохраняет состояние пространства имен идентификатором пользователя платформы и идентификатором сеанса песочницы Foundry. Для каждой операции состояния также требуется идентификатор вызова платформы. Идентификатор вызова служит для авторизации и соотнесения операции; он не является идентификатором разговора и не входит в состав ключа хранения.

Для Responses песочницу идентифицирует настроенный на платформе FOUNDRY_AGENT_SESSION_ID, а другой agent_session_id, переданный вызывающей стороной, отклоняется. Для вызовов хост сверяет маршрутизируемый параметр строки запроса agent_session_id с контекстом запроса. Если FOUNDRY_AGENT_SESSION_ID не настроен, параметр запроса должен присутствовать, быть непустым и соответствовать контексту запроса. Отсутствующие, повторяющиеся или конфликтующие значения отклоняются вместо использования резервного идентификатора пакета SDK.

Эти гарантии применяются к размещённым по умолчанию магазинам. Поставщики пользовательских хранилищ должны обеспечивать эквивалентную изоляцию пользователя и песочницы, хранить внутренний элемент AgentSession.session_id отдельно от ключей поиска хоста и использовать условные записи, чтобы устаревшие запросы не могли перезаписывать более новые снимки состояния. Для новых ключей следует использовать операции записи create-only, а не безусловные операции upsert. Ознакомьтесь с примером пользовательского хранилища, содержащим реализацию для Cosmos DB с операциями записи и удаления, защищёнными ETag.

С history_source="agent" настроенное хранилище сеансов сохраняет состояние провайдера, передаваемое через AgentSession, включая сообщения из InMemoryHistoryProvider.

Оба хоста принимают от StoreProvider[SessionStore] до agent_session_store_provider. Состояние сеанса должно поддерживать сериализацию AgentSession. Регистрируйте кодеки для пользовательских типов состояния с помощью register_state_type(); восстановленное состояние не сохраняет идентичность объекта Python. В новых хранилищах по умолчанию срок действия сеансов истекает через 30 дней после последней записи в них. Пользовательские поставщики самостоятельно управляют сроками хранения данных.

Хранилища по умолчанию с областью видимости не считывают устаревшие данные без области видимости: invocation_sessions, agent_sessions, данные контрольных точек или данные об утверждении функций. Начните новый диалог Responses вместо повторного использования существующего previous_response_id или идентификатора диалога. Вызовы начинаются с пустого сеанса Agent Framework в контекстном хранилище.

Загруженные AgentSession записи используют условия ETag. Если другой запрос успевает сначала обновить состояние того же сеанса, устаревшая операция записи завершается с ошибкой вместо того, чтобы перезаписать более новое состояние. Эта проверка не предоставляет транзакции или точно однократное выполнение для побочных эффектов агента или средства, поэтому приложения по-прежнему должны координировать перекрывающиеся запросы.

Для хранилища, специфичного для Responses, передайте объект StoreProvider в function_approval_store_provider или объект ContextScopedStoreProvider в checkpoint_store_provider.

Внешняя фоновая работа использует вызывающий объект, видимый response.id для опроса. По умолчанию background_source="agent_server" оставляет фоновое выполнение на хосте. Задавайте background_source="provider" только с history_source="service" и клиентом Responses с хранением данных и возможностью возобновления. Если ResponsesServerOptions(resilient_background=True) также задан, хост может возобновить опрос поставщика только после того, как сохранит приватный токен продолжения. Сделайте побочные действия локального инструмента идемпотентными, так как сбой до сохранения следующего токена может привести к их повторному выполнению.

Импортируйте azure.ai.agentserver.responses из ResponsesServerOptions и передайте его в options через параметр ResponsesHostServer. Доступные варианты длительных диалогов зависят от типа агента:

Функциональность Тип агента Требования и поведение
Фоновое восстановление контрольных точек рабочего процесса Только рабочий процесс Задайте ResponsesServerOptions(resilient_background=True). Отправьте запрос Responses с store=true и background=true. После перезапуска хост возобновляет выполнение с последней контрольной точки отказоустойчивого рабочего процесса или повторно воспроизводит исходные входные данные, если контрольная точка отсутствует. Не настраивайте хранилище контрольных точек в рабочем процессе, так как хост управляет им. Сделайте внешние побочные эффекты идемпотентными, так как выполненная после последней сохранённой контрольной точки работа может быть повторена.
Собственные фоновые ответы провайдера Неработающий рабочий процесс Agent с клиентом для хранения ответов Установить history_source="service" и background_source="provider". Установите resilient_background=True, если сохранённые токены продолжения поставщика должны сохраняться после перезапуска узла.
Управляемые беседы Временно недоступен Не указывайте steerable_conversations=True. Хост выдаёт RuntimeError при создании, пока Agent Server SDK не начнёт безопасно обрабатывать отклонённые команды поворота.

Примеры полных реализаций см. в примере пользовательского хранилища, примере базовой истории Responses и выполнения в фоновом режиме и примере отказоустойчивого длительного рабочего процесса.

Чтение файлов из размещенной песочницы

Считайте постоянное хранилище $HOME размещённой песочницы ресурсом, маршрутизируемым по запросу, а не общей границей файловой системы. Принимайте только файлы, которые ваше приложение явно загружает в специально выделенный каталог, проверяйте текущий идентификатор песочницы и отклоняйте абсолютные пути, последовательности обхода каталогов, ссылки, файлы, не являющиеся обычными файлами, а также слишком большое или недопустимое содержимое.

Для протокола Responses направьте запрос в сеанс, размещённый на сервере, с помощью поля agent_session_id в теле запроса. Селектор строки запроса предназначен для вызовов. Загрузки сеанса и файлы интерпретатора кода Toolbox — это отдельные ресурсы; файл, загруженный в песочницу, не монтируется автоматически в контейнер Toolbox. Ознакомьтесь с примером работы с файлами сеансов, где приведены рекомендации по ограниченному чтению UTF-8, а также по локальной загрузке и загрузке в размещённой среде.

Параметры запроса управления

Хост сопоставляет собственные поля генерации Responses с параметрами запуска Agent Framework. Например, max_output_tokens становится max_tokensи parallel_tool_calls становится allow_multiple_tool_calls. Развёрнутые значения из extra_body переопределяют переведённые исходные значения.

Используйте синхронный или асинхронный prepare_options(request, options) хук, чтобы удалить или заменить параметры модели вызывающей стороны до запуска обычного агента. Хук не может задавать поля идентификатора, хранилища, продолжения или транспорта, управляемые хостом. Для пользовательской реализации SupportsAgentRun, которая не может принимать параметры модели во время выполнения, установите для "warn" значение unsupported_options (по умолчанию), "ignore" или "error".

Если для средства MCP, размещенного в Foundry, требуется согласие пользователя, ResponsesHostServer возвращает неполный ответ с выходным элементом oauth_consent_request . Покажите пользователю его consent_link, а затем используйте идентификатор неполного ответа в качестве previous_response_id после того, как пользователь даст согласие. Хост сохраняет сеанс агента при этой повторной попытке и предоставляет только абсолютные HTTPS-ссылки для согласия.

Если ваш хост знает ожидаемые origin-адреса авторизации, ограничьте ссылки для получения согласия с помощью allowed_oauth_consent_origins:

server = ResponsesHostServer(
    agent,
    allowed_oauth_consent_origins=[
        "https://logic-region.consent.azure-apihub.net",
        "https://auth.partner.example",
    ],
)

Опущение списка разрешений сохраняет проверку абсолютного HTTPS без ограничения источника назначения. Предоставление пустого списка отклоняет каждую ссылку согласия. Указывайте только точно совпадающие HTTPS-источники; записи с путём, запросом или фрагментом отклоняются.

Протокол вызовов

Протокол вызовов обеспечивает полный контроль над HTTP-запросом и ответом. Используйте его, если вам нужны нестандартные полезные нагрузки, не требующие обработки разговоров, или протоколы потоковой передачи, не совместимые с OpenAI.

С помощью протокола Invocations в C#вы реализуете пользовательский InvocationHandler метод обработки входящих запросов:

using Azure.AI.AgentServer.Core;
using Azure.AI.AgentServer.Invocations;
using Microsoft.Agents.AI;

var builder = AgentHost.CreateBuilder(args);

builder.Services.AddSingleton<AIAgent, MyAgent>();
builder.Services.AddInvocationsServer();
builder.Services.AddScoped<InvocationHandler, MyInvocationHandler>();

builder.RegisterProtocol("invocations", endpoints => endpoints.MapInvocationsServer());

var app = builder.Build();
app.Run();

Метод AddInvocationsServer регистрирует службы протокола Invocations. Вы реализуете InvocationHandler, чтобы определить, как ваш агент обрабатывает каждый запрос.

Для упрощенной настройки используйте InvocationsHostServer из agent_framework_foundry_hosting пакета. Он упаковывает агент так же, как ResponsesHostServer и обрабатывает управление сеансами автоматически:

import os

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from agent_framework_foundry_hosting import InvocationsHostServer
from azure.identity import DefaultAzureCredential

client = FoundryChatClient(
    project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
    model=os.environ.get("FOUNDRY_MODEL") or os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
    credential=DefaultAzureCredential(),
)

agent = Agent(
    client=client,
    instructions="You are a friendly assistant. Keep your answers brief.",
    default_options={"store": False},
)

server = InvocationsHostServer(agent)
server.run()

InvocationsHostServer принимает те же формы экземпляра или фабрики с областью действия запроса, которые описаны для хоста Responses. Он восстанавливает сериализованные сеансы из настроенного хранилища, поэтому завершенные беседы могут продолжаться после перезапуска узла. Сведения о поведении хранилища, сохранении и настройке см. в статье Сохранение состояния и обработка долгих диалогов.

В размещённом варианте Invocations использует проверенную область видимости запроса, описанную в Сохранение состояния и обработка длительных диалогов. Считайте AgentSession.session_id одним непрозрачным значением; не разбирайте его и не полагайтесь на его внутреннее представление. Локальные запуски сохраняют существующий однопользовательский режим хранения.

Разместите собственный рабочий процесс с Invocations

Передайте workflow= и явный parse_request обратный вызов для размещения нативного рабочего процесса. Функция обратного вызова определяет схему JSON приложения и возвращает объект WorkflowTurn с типизированными входными данными или полным пакетом ожидающих ответов:

from pydantic import BaseModel
from starlette.requests import Request

from agent_framework_foundry_hosting import (
    CheckpointStoreProvider,
    InvocationsHostServer,
    WorkflowTurn,
)


class Ticket(BaseModel):
    ticket_id: str
    question: str


class TicketDecision(BaseModel):
    approved: bool


def build_workflow(_request: Request):
    return build_fresh_workflow()


async def parse_request(request: Request) -> WorkflowTurn[Ticket]:
    payload = await request.json()
    stream = payload.get("stream", False)

    if "responses" in payload:
        decisions = {
            request_id: TicketDecision.model_validate(value)
            for request_id, value in payload["responses"].items()
        }
        return WorkflowTurn(responses=decisions, stream=stream)

    ticket = Ticket.model_validate(payload)
    return WorkflowTurn(input=ticket, stream=stream)


server = InvocationsHostServer(
    workflow=build_workflow,
    parse_request=parse_request,
    checkpoint_store_provider=CheckpointStoreProvider(
        allowed_checkpoint_types=[
            f"{Ticket.__module__}:{Ticket.__qualname__}",
            f"{TicketDecision.__module__}:{TicketDecision.__qualname__}",
        ],
    ),
)

Включите каждый пользовательский тип приложения, который рабочий процесс сохраняет в список allowed_checkpoint_types поставщика контрольных точек.

Для хостируемых рабочих процессов требуется фабрика с поддержкой запросов, которая возвращает свежий собранный граф со стабильными идентификаторами рабочего процесса и исполнителя. Рабочий процесс прямой сборки доступен только для локального однократного запуска, который не приостанавливается.

Ответы рабочих процессов без потоковой передачи используют JSON приложения со списком output событий. Потоковая передача передает события output и request_info во фреймах, после которых done следует только после сохранения точного курсора workflow. Рассматривайте потоковые выходные данные как временные до done. Собственные рабочие процессы не поддерживают legacy_wire_format=True.

Хост проверяет ответы по точной ожидающей контрольной точке в области доверенного пользователя и песочницы. Если рабочий процесс имеет несколько ожидающих запросов, ответьте на полный пакет в один раз. Сведения об исполняемом парсере, типизированном процессе обработки тикетов, списке разрешённых типов контрольных точек и примеры JSON/SSE см. в примере собственного workflow Invocations.

Настройка запросов и ответов Invocations

По умолчанию POST /invocations принимает объект JSON со строкой message, необязательным объектом options и необязательным логическим значением stream. Чтобы принять полезную нагрузку, зависящую от приложения, передайте синхронный или асинхронный обратный вызов parse_request, который возвращает InvocationRun(messages, options, stream). Используйте prepare_options для фильтрации или замены копии параметров генерации вызывающей стороны перед запуском агента.

Хост проверяет выходные данные хука и отклоняет элементы управления идентификацией платформы, хранилищем, продолжением и выполнением агента. Для агентов, которые не принимают параметры среды выполнения, установите значение unsupported_options"warn" (по умолчанию) "ignore"или "error". См. пример средства синтаксического анализа вызовов для полной реализации.

Успешное выполнение без потоковой передачи возвращает JSON в форме {"response": "..."}. Потоковая передача данных использует события, отправляемые сервером: один или несколько кадров event: delta, за которыми следует event: done в случае успеха или event: error в случае сбоя. Поток может выдавать разностные значения перед ошибкой, поэтому клиенты должны обрабатывать , а не разностное doneзначение, как успешное завершение. Хост отправляет done только после того, как завершает поток ответа и сохраняет AgentSession. Его session_id — это идентификатор маршрута песочницы платформы, а не сериализованный AgentSession.session_id.

Устанавливайте legacy_wire_format=True только при миграции существующих клиентов, которым требуются прежний ответ в виде обычного текста и необработанный поток текстовых фрагментов. Этот режим совместимости устарел и не преобразует сбои в успешный текст. Хост сериализует запросы в рамках одного сеанса только в пределах одного процесса; межпроцессный конфликт compare-and-swap (CAS) всё ещё может возникнуть после воздействия внешних инструментов.

Протокол Invocations не возобновляет запуски рабочих процессов, находящиеся в ожидании или прерванные. Используйте шаблон пользовательского обработчика в следующем разделе, если требуется другое поведение продолжения рабочего процесса.

Для полного управления обработкой запросов используйте InvocationAgentServerHost непосредственно из azure.ai.agentserver.invocations пакета и реализуйте собственный обработчик вызова:

import os
from collections.abc import AsyncGenerator

from agent_framework import Agent, AgentSession
from agent_framework.foundry import FoundryChatClient
from azure.ai.agentserver.invocations import InvocationAgentServerHost
from azure.identity import DefaultAzureCredential
from starlette.requests import Request
from starlette.responses import JSONResponse, Response, StreamingResponse

_sessions: dict[str, AgentSession] = {}

client = FoundryChatClient(
    project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
    model=os.environ.get("FOUNDRY_MODEL") or os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
    credential=DefaultAzureCredential(),
)

agent = Agent(
    client=client,
    instructions="You are a friendly assistant. Keep your answers brief.",
    default_options={"store": False},
)

app = InvocationAgentServerHost()


@app.invoke_handler
async def handle_invoke(request: Request):
    """Handle streaming multi-turn chat."""
    data = await request.json()
    session_id = request.state.session_id
    stream = data.get("stream", False)
    user_message = data.get("message", None)

    if user_message is None:
        return Response(content="Missing 'message' in request", status_code=400)

    session = _sessions.setdefault(session_id, AgentSession(session_id=session_id))

    if stream:

        async def stream_response() -> AsyncGenerator[str]:
            async for update in agent.run(user_message, session=session, stream=True):
                yield update.text

        return StreamingResponse(
            stream_response(),
            media_type="text/event-stream",
            headers={"Cache-Control": "no-cache", "Connection": "keep-alive"},
        )

    response = await agent.run([user_message], session=session, stream=stream)
    return JSONResponse({"response": response.text})


if __name__ == "__main__":
    app.run()

Предупреждение

Хранилище сеансов в памяти в примере пользовательского обработчика теряется при перезапуске. Используйте устойчивое хранилище (например, Cosmos DB) в рабочей среде.

Полный пример развертывания Invocations см. в примере Telegram, размещённом в Foundry. Решение размещает API Management перед вебхуком размещённого агента и использует управляемые удостоверения, Key Vault и Cosmos DB для долговременного хранения истории диалогов.

Замечание

Скоро появится поддержка Go для размещенных агентов Foundry. Сведения о последнем состоянии см. в репозитории Agent Framework Go .

Tip

См. примеры Python или примеры C#, чтобы ознакомиться с примерами проекта размещённого агента. Или используйте команду azd ai agent init, чтобы создать структуру проекта нового размещенного агента с нуля. В этом кратком руководстве приведены пошаговые инструкции.

Запуск на локальной машине

Интерфейс командной строки разработчика Azure (azd) предоставляет самый простой способ запуска и тестирования размещенного агента локально.

Инициализация проекта

Создайте новую папку и инициализируйте из примера манифеста:

mkdir my-hosted-agent && cd my-hosted-agent
azd ai agent init -m <path-to-agent.manifest.yaml>

Tip

Манифест может быть путем к локальному файлу YAML или URL-адресу удаленного манифеста.

Настройка переменных среды

export FOUNDRY_PROJECT_ENDPOINT="https://<account>.services.ai.azure.com/api/projects/<project>"
export FOUNDRY_MODEL="<your-model-deployment>"

Запуск хоста агента

azd ai agent run

Агентский узел запускается на http://localhost:8088.

Вызов агента

azd ai agent invoke --local "Hello!"

Или используйте curl:

curl -X POST http://localhost:8088/responses \
  -H "Content-Type: application/json" \
  -d '{"input": "Hello!"}'

Или в PowerShell:

(Invoke-WebRequest -Uri http://localhost:8088/responses -Method POST -ContentType "application/json" -Body '{"input": "Hello!"}').Content

Развертывание в Foundry

После локальной проверки агента разверните его в Microsoft Foundry:

  1. Подготовка ресурсов (если у вас еще нет проекта Foundry):

    azd provision
    

    При этом создается группа ресурсов с экземпляром Foundry, проектом, развертыванием модели, Application Insights и реестром контейнеров.

  2. Разверните агент:

    azd deploy
    

    Это упаковывает ваш агент в виде образа контейнера, отправляет его в Реестр контейнеров Azure и развертывает в службе Foundry Agent Service.

Инфраструктура размещения Foundry автоматически внедряет следующие переменные среды в контейнер агента во время выполнения:

Variable Описание
FOUNDRY_PROJECT_ENDPOINT URL-адрес конечной точки для проекта Foundry.
AZURE_AI_MODEL_DEPLOYMENT_NAME Имя развертывания модели под управлением azd, настроенное во время azd ai agent init. Код Python может использовать FOUNDRY_MODEL локально и использовать это размещённое значение как резервное.
APPLICATIONINSIGHTS_CONNECTION_STRING Строка подключения Application Insights для телеметрии.

После развертывания ваш агент доступен через выделенную конечную точку Foundry и его также можно протестировать на портале Foundry.

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