具体问题与边界
怎样把领域 ModelRequest 编译成真实 Responses API 请求,同时让 Runtime 完全不知道 HTTP 与认证细节?
Runtime 依赖 ModelClient.stream();ResponsesModelClient 负责编译 wire payload;HttpxResponsesTransport 负责认证、HTTP status、SSE 连接与取消。 本节以官方 Codex 锁定提交为事实基线,以 Mini Codex 的可执行断言检验 Python 设计;二者不是逐行翻译关系。
OpenAI 官方迁移文档明确要求 Responses 流消费者按 typed SSE event 的 type 分支;文本常见事件包括 response.output_text.delta、response.completed 与 error,函数调用还会出现 arguments delta/done。见 官方 Responses streaming 迁移说明。
协议、类型与状态所有权
| 对象 | 创建/所有者 | 生命周期与作用域 | 是否持久化 |
|---|---|---|---|
| ModelRequest | PromptCompiler/Session | 一个 Step | 否 |
| Responses payload | ResponsesModelClient | 一次 HTTP 请求 | 否 |
| HTTP/SSE connection | HttpxResponsesTransport | 一个 stream 调用 | 否 |
| API key | Host 配置 | Transport 生命周期 | 绝不进入 History/Rollout |
正常路径
ModelClient是只有stream(request, cancellation)的 Protocol;Session 不导入 httpx 或 OpenAI SDK 类型。- Adapter 把 Message 编成 role/content,把 ToolCall 编成 function_call,把 ToolResult 编成 function_call_output,并序列化 arguments。
- ToolSpec 通过
to_responses_api()生成type=function、name、description、strict 和 parameters;内部 output_schema 不发给普通 Responses tools。 - 请求显式携带 model、instructions、input、tools、stream=true 与 store 配置。教学实现默认 store=false,避免把本地 Rollout 与远端存储含混。
- Transport 使用 Authorization header 打开
POST /v1/responses;HTTP 只产出 JSON event,领域 Adapter 再映射为 ModelEvent。
调用链与等待点
1. `ModelClient` 是只有 `stream(request, cancellation)` 的 Protocol;Session 不导入 httpx 或 OpenAI SDK 类型
→ 2. Adapter 把 Message 编成 role/content,把 ToolCall 编成 function_call,把 ToolResult 编成 function_call_output,并序列化 arguments
→ 3. ToolSpec 通过 `to_responses_api()` 生成 `type=function`、name、description、strict 和 parameters;内部 output_schema 不发给普通 Responses tools
→ 4. 请求显式携带 model、instructions、input、tools、stream=true 与 store 配置
→ 5. Transport 使用 Authorization header 打开 `POST /v1/responses`;HTTP 只产出 JSON event,领域 Adapter 再映射为 ModelEvent
每个 await 都是状态可被取消、外部副作用可能已经发生或其他任务能够推进的边界。正文因此同时写清输入形状、所有者、成功产物和失败残留,而不是只列方法名。
Python 风格伪代码
class ModelClient(Protocol):
def stream(request, cancellation) -> AsyncIterator[ModelEvent]: ...
class ResponsesModelClient:
def build_payload(request):
return {
"model": configured_model,
"instructions": request.base_instructions,
"input": [to_wire(item) for item in request.history],
"tools": [spec.to_responses_api() for spec in request.tool_specs],
"stream": True,
"store": False,
}
async def stream(request, cancellation):
payload = build_payload(request)
async for wire_event in transport.stream_json(payload, cancellation):
cancellation.raise_if_cancelled()
if model_event := map_typed_event(wire_event):
yield model_event
伪代码表达顺序和责任。真实可运行实现没有把万能调用当作未解释黑箱;对应模块见 Mini 导航。
失败、取消与恢复
| 故障点 | 已发生/残留状态 | 处理与模型可见结果 |
|---|---|---|
| ToolSpec 不是预期类型 | 无法可靠生成线格式 | Adapter 在发请求前 TypeError |
| HTTP 4xx/5xx | 没有领域 ModelCompleted | Transport raise_for_status,Turn owner Aborted |
| API key 写进 ModelRequest | 可能进入 trace/日志 | 认证只属于 Transport header |
| 断线前没有 completed | Accumulator 拒绝 finish | 半响应不进入规范历史 |
必须保持的不变量
Session 只能看见领域 ModelEvent;认证、HTTP status 和 SSE 资源清理必须留在 Transport;只有真实 complete 事件能结束一次成功采样。
设计取舍
Adapter 分层增加一次 wire/domain 转换,却允许离线 Scripted、录制回放和真实 API 复用同一个 Turn Loop。Mini 不实现官方 Provider 能力协商、WebSocket、重试和 previous_response 优化。
“为什么”的表述是从源码状态机、调用顺序和测试反推的工程解释;源码未声明的动机不写成官方承诺。
测试与复现实验
cd examples/mini-codex
uv run pytest -q -k 'test_responses_adapter_builds_wire_payload_and_maps_typed_events or test_function_tool_spec_serializes_responses_wire_shape or test_function_tool_wire_omits_internal_output_schema'
uv run mypy src
关键断言:
test_responses_adapter_builds_wire_payload_and_maps_typed_eventstest_function_tool_spec_serializes_responses_wire_shapetest_function_tool_wire_omits_internal_output_schema
官方源码导航
- codex-rs/core/src/client.rs:模型客户端生命周期、Prompt 请求与流入口
- codex-rs/core/src/client_common.rs:Responses 请求公共编译与能力分支
- codex-rs/codex-api/src:Responses wire 类型与事件协议
Mini Codex 对照
src/mini_codex/models/client.py:Provider 中立 Protocolsrc/mini_codex/models/responses.py:真实 payload 和 HTTP/SSE Adaptersrc/mini_codex/tools/specs.py:Function Tool 线格式
本节边界
已经证明:Session 只能看见领域 ModelEvent;认证、HTTP status 和 SSE 资源清理必须留在 Transport;只有真实 complete 事件能结束一次成功采样。
评论
登录后即可评论