Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Замечание
Средства для самостоятельного размещения эндпоинтов OpenAI Responses в .NET скоро появятся.
Замечание
Средства для самостоятельного хостинга эндпоинтов Responses OpenAI в настоящее время недоступны для Go.
Используйте agent-framework-hosting-responses для преобразования запросов и ответов в формате OpenAI Responses в конечной точке, принадлежащей вашему приложению. Сервер выбирает веб-платформу, маршрут, проверку подлинности, авторизацию, параметры запроса и хранилище сеансов.
pip install --pre agent-framework agent-framework-foundry agent-framework-hosting agent-framework-hosting-responses azure-identity
Пример FastAPI является одной реализацией. Те же вспомогательные средства работают с Django, Flask, Starlette, Функции Azure или другой платформой.
Размещение конечной точки агента
Этот пример преобразует запрос в значения выполнения Agent Framework, применяет список разрешений, определенный приложением, и сохраняет обновленный сеанс под только что созданным идентификатором ответа.
app = FastAPI()
state = AgentState(
create_agent,
session_store=FileSessionStore(SESSIONS_DIR / "snapshots"),
)
ALLOWED_REQUEST_OPTIONS = frozenset({"max_tokens", "reasoning"})
@app.post("/responses", response_model=None)
async def responses(body: dict[str, Any] = Body(...)) -> JSONResponse | StreamingResponse: # noqa: B008
"""Handle one OpenAI Responses-shaped request."""
try:
run = responses_to_run(body)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
session_id, is_conversation_id = responses_session_id(body)
conversation_id = session_id if is_conversation_id else None
response_id = create_response_id()
# App-specific policy: allow only the request options this route is willing
# to honor. This denies tools, tool_choice, deployment/persistence fields,
# and all other caller-supplied options by default. Your app decides which
# options are allowed, altered, or denied.
options = {key: value for key, value in run["options"].items() if key in ALLOWED_REQUEST_OPTIONS}
options["reasoning"] = {"effort": "medium", "summary": "auto"}
options_for_run = cast(Any, options)
target = await state.get_target()
lookup_id = session_id or response_id
# An unknown id supplied through `conversation` becomes a new session here. Production apps
# can choose to require a separate "create conversation" API instead.
session = await state.get_or_create_session(lookup_id)
if run["stream"]:
stream = target.run(
run["messages"],
stream=True,
session=session,
options=options_for_run,
)
if not isinstance(stream, ResponseStream):
raise HTTPException(status_code=500, detail="agent did not return a response stream")
async def stream_events() -> AsyncIterator[str]:
async for event in responses_from_streaming_run(
stream,
response_id=response_id,
conversation_id=conversation_id,
):
yield event
# `agent.run(..., stream=True)` updates the session while the stream
# is consumed/finalized. Persist the selected continuation only
# after finalization.
if conversation_id is not None:
# A stable conversation id is a mutable head. Apps must ensure
# only one caller advances it at a time; AgentState does not
# serialize concurrent runs for the same id.
await state.set_session(conversation_id, session)
else:
await state.set_session(response_id, session)
return StreamingResponse(
stream_events(),
media_type="text/event-stream",
)
result = await target.run(
run["messages"],
session=session,
options=options_for_run,
)
# `agent.run(...)` updates the session. Persist the selected continuation
# only after the run completes.
AgentState определяет цель и загружает или создает сеанс. Сохраните сеанс после запуска или после завершения потокового запуска, поскольку запуск обновляет его.
Полное приложение, включая определение агента и список разрешений для запроса, см. в примере локальных ответов.
Разберитесь в преобразовании использования ответов
Для ответов агента и рабочего процесса пакет хостинга сохраняет собственный объект OpenAI ResponseUsage без изменений, если доступен такой объект, совместимый с SDK. Он не объединяет использование собственных ответов с агентом Framework UsageDetails.
Если исходные данные об использовании недоступны, пакет может восстановить данные об использовании Responses на основе следующих семантически соответствующих полей Agent Framework:
| Значение использования | Поле Agent Framework |
|---|---|
| Входные токены | input_token_count |
| Результирующие токены | output_token_count |
| Входные токены, считываемые из кэша | cache_read_input_token_count |
| Входные токены записи в кэш | cache_creation_input_token_count |
| Обоснование выходных маркеров | reasoning_output_token_count |
Явные нулевые значения сохраняются. Если total_tokens отсутствует, а количество входных и выходных данных указано, пакет вычисляет его как сумму входных и выходных данных.
Если доступные данные об использовании Agent Framework неполны или семантически не согласуются со схемой Responses, пакет не включает данные об использовании. Он не строит предположений, не копирует значение одного счётчика в другой и не приводит к сбою в остальном успешного ответа. Неправильно сформированное скалярное число остается ошибкой.
Эта реконструкция намеренно выполняется с потерями, поскольку использование Agent Framework не привязано к конкретному поставщику, а использование OpenAI Responses имеет более богатую, специфичную для поставщика структуру. Счётчики, специфичные для поставщика, о которых сообщает размещённый агент, например данные об использовании, специфичные для Anthropic, поэтому могут не отображаться в ответе, полученном вызывающим приложением. Это преобразование не обеспечивает взаимодействие между различными версиями пакета SDK OpenAI, выполняющегося в одном процессе.
Размещение конечной точки рабочего процесса
WorkflowState завершает процесс, но ваше приложение отвечает за хранилище контрольных точек и сопоставление идентификатора ответа с контрольной точкой. Этот пример восстанавливает контрольную точку, выбранную авторизованным previous_response_id, а затем сохраняет курсор для следующего ответа.
app = FastAPI()
state = WorkflowState(workflow_builder, cache_target=False)
@app.post("/responses", response_model=None)
async def responses(body: dict[str, Any] = Body(...)) -> JSONResponse: # noqa: B008
"""Handle one OpenAI Responses-shaped request for the workflow."""
try:
run = responses_to_run(body)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
# This sample demonstrates only Responses `previous_response_id`
# continuation, so reject `conversation` instead of treating it as a
# checkpoint cursor.
previous_response_id, is_conversation_id = responses_session_id(body)
if is_conversation_id:
raise HTTPException(
status_code=400,
detail="This server supports previous_response_id continuation only; conversation is not implemented.",
)
response_id = create_response_id()
target = await state.get_target()
if previous_response_id and (checkpoint_cursor := checkpoint_cursor_store.get(previous_response_id)) is not None:
# Restore first. Workflow.run does not allow `message` and
# `checkpoint_id` in the same call.
await target.run(
checkpoint_id=checkpoint_cursor["checkpoint_id"],
checkpoint_storage=checkpoint_storage_for(checkpoint_cursor["storage_id"]),
)
storage_id = response_id
checkpoint_storage = checkpoint_storage_for(storage_id)
result = await target.run(
message=workflow_prompt_from_messages(run["messages"]),
checkpoint_storage=checkpoint_storage,
)
latest = await checkpoint_storage.get_latest(workflow_name=target.name)
if latest is not None:
# Responses `previous_response_id` can point to any response id. Store
# the current response id as the cursor for this workflow continuation.
cursor = CheckpointCursor(checkpoint_id=latest.checkpoint_id, storage_id=storage_id)
checkpoint_cursor_store.set_many({response_id: cursor})
return JSONResponse(
responses_from_run(
response_from_workflow_result(result),
response_id=response_id,
)
)
Резервное хранилище примера предназначено для локальной разработки. Используйте устойчивое хранилище, если реплики могут перезапускать или масштабироваться.
Это важно
Обрабатывать previous_response_id и conversation как ненадежные входные данные. Проверяйте подлинность и авторизуйте вызывающую сторону, прежде чем использовать любое из этих значений для загрузки или сохранения сеанса либо контрольной точки. Устаревшее поле запроса conversation_id не рекомендуется к использованию; используйте вместо него поле OpenAI Responses conversation.
Более широкий формат провода см. в статье о конечных точках, совместимых с OpenAI.
Дальнейшие действия
Вернитесь глубже: