Hospede você mesmo os endpoints de Responses da OpenAI

Note

Os auxiliares de auto-hospedagem para pontos de extremidade do OpenAI Responses no .NET chegarão em breve.

Note

Os auxiliares de auto-hospedagem dos pontos de extremidade do OpenAI Responses não estão disponíveis no momento para Go.

Use agent-framework-hosting-responses para converter solicitações e respostas no formato do OpenAI Responses em um ponto de extremidade que seu aplicativo controla. Seu servidor escolhe a estrutura da Web, a rota, a autenticação, a autorização, as opções de solicitação e o armazenamento de sessão.

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

O exemplo de FastAPI é uma implementação. Os mesmos auxiliares trabalham com Django, Flask, Starlette, Azure Functions ou outra estrutura.

Hospede um endpoint do agente

Este exemplo converte a solicitação em valores de execução do Agent Framework, aplica uma lista de permissões de opção definida pelo aplicativo e persiste a sessão atualizada na ID de resposta recém-criada.

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 resolve o destino e carrega ou cria uma sessão. Salve a sessão após a execução ou após a conclusão de uma execução de streaming, pois a execução a atualiza.

Para a aplicação completa, incluindo a definição do agente e a lista de permissões de opções de solicitação, consulte o exemplo local de Responses.

Compreender a conversão de uso de respostas

Para respostas de agente e fluxo de trabalho, o pacote de hospedagem preserva um objeto OpenAI ResponseUsage nativo válido do SDK inalterado quando um está disponível. Ele não mescla o uso de respostas nativas com o Agent Framework UsageDetails.

Quando o uso nativo não está disponível, o pacote pode reconstruir o uso de Respostas a partir desses campos semanticamente correspondentes do Agent Framework:

Valor de uso Campo Framework do Agente
Tokens de entrada input_token_count
Tokens de saída output_token_count
Tokens de entrada lidos do cache cache_read_input_token_count
Tokens de entrada gravados em cache cache_creation_input_token_count
Tokens de saída de raciocínio reasoning_output_token_count

Valores zero explícitos são preservados. Se total_tokens estiver ausente enquanto as contagens de entrada e saída estiverem presentes, o pacote o deriva como entrada mais saída.

Se o uso do Agent Framework disponível estiver incompleto ou semanticamente inconsistente com o esquema respostas, o pacote omite o uso. Ele não adivinha, copia um contador em outro, ou falha em uma resposta com êxito. Uma contagem escalar malformada permanece um erro.

Essa reconstrução é intencionalmente perdida porque o uso do Agent Framework é neutro no provedor e o uso de respostas OpenAI tem uma forma mais rica e específica do provedor. Contadores específicos do provedor relatados por um agente hospedado, como o uso específico da Anthropic, portanto, podem não aparecer na resposta recebida pelo aplicativo chamador. Essa conversão não fornece interoperabilidade entre versões diferentes do SDK do OpenAI em execução no mesmo processo.

Hospede um endpoint de fluxo de trabalho

WorkflowState processa o fluxo de trabalho, mas seu aplicativo é responsável pelo armazenamento de checkpoints e pelo mapeamento entre um ID de resposta e um checkpoint. Este exemplo restaura o ponto de verificação selecionado por um previous_response_id autorizado e então salva um cursor para a próxima resposta.

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

O armazenamento com suporte de arquivo do exemplo é para desenvolvimento local. Use o armazenamento durável quando as réplicas puderem reiniciar ou escalar horizontalmente.

Important

Tratar previous_response_id e conversation como entrada não confiável. Autentique e autorize o chamador antes de usar qualquer um dos dois valores para carregar ou salvar uma sessão ou ponto de verificação. O campo de solicitação herdado conversation_id foi preterido; use o campo Respostas conversation OpenAI.

Para obter o formato de fio mais amplo, consulte Pontos de extremidade compatíveis com OpenAI.

Próximas Etapas 

Vá mais fundo: