雨天小六

读懂 Codex(9.19):端到端真实模型测试与录制回放测试

· 更新于 2026-08-03 · 专栏:读懂 Codex

#Codex#Agent Runtime#Python#软件架构

具体问题与边界

怎样既验证真实 Responses 边界,又让默认 CI 可重复、离线、可诊断?

RecordingModelClient 透明包裹任意 ModelClient;ReplayModelClient 按 request fingerprint 回放完整 ModelEvent;live test 只有两个显式环境变量同时存在才运行。 下面同时给出状态所有者、顺序、伪代码、故障残留和不可外推边界。

状态所有权

对象所有者生命周期持久化
inner ModelClientRecordingModelClient测试/运行配置
request fingerprintrecord/replay adapter一条 traceJSONL
recorded ModelEventstrace file跨测试运行
replay cursorReplayModelClient一个实例
live credentials/model环境变量/Host单测试不写 trace

正常路径

端到端真实模型测试与录制回放测试正常路径图
图 9.19-1:怎样既验证真实 Responses 边界,又让默认 CI 可重复、离线、可诊断?
  1. fingerprint 对 instructions、完整 history、tool wire specs、step_sequence 和 tool_generation 做 canonical JSON+SHA-256;不包含随机 step_id/turn_id。
  2. Recording client 把 inner 事件原样 yield 给 Runtime,同时收集;stream 正常结束后追加 fingerprint+events JSONL。
  3. 事件以明确 type 编码:text_delta、message、tool_call、completed。Replay load 严格解码未知类型。
  4. Replay 每次调用先比较实际 fingerprint;不匹配立即失败,而不是把旧答案喂给不同 Prompt。
  5. live test 用真实 HttpxResponsesTransport,只有 OPENAI_API_KEY 与 MINI_CODEX_LIVE_MODEL 都设置时才发请求;默认 pytest 明确显示 skip。

Python 风格伪代码

def fingerprint(request):
    canonical = json.dumps({
        "instructions": request.instructions,
        "history": encode_items(request.history),
        "tools": encode_specs(request.tools),
        "step_sequence": request.step_sequence,
        "tool_generation": request.tool_generation,
    }, sort_keys=True, separators=(",", ":"))
    return sha256(canonical)

async def recording_stream(request, token):
    events = []
    async for event in inner.stream(request, token):
        events.append(event)
        yield event
    append_jsonl({"fingerprint": fingerprint(request),
                  "events": encode_events(events)})

async def replay_stream(request, token):
    trace = traces[next_index()]
    require(fingerprint(request) == trace.fingerprint)
    for event in trace.events:
        token.raise_if_cancelled()
        yield event

live_enabled = bool(OPENAI_API_KEY and MINI_CODEX_LIVE_MODEL)

伪代码没有复制 Rust 语法;它保留了状态修改、await、取消、外部副作用和结果反馈的实际顺序。

失败、取消与恢复

端到端真实模型测试与录制回放测试失败路径图
图 9.19-2:失败不是一个 exception 方框,而是各状态所有者留下的可观察组合。
故障点残留/风险处理
不同 Prompt 误用 trace测试产生虚假确定性fingerprint mismatch fail fast
trace 耗尽没有合法模型响应RuntimeError
录制中途断流事件可能已展示不写成 completed trace
缺 credentials/model不应偷偷联网测试 explicit skip
live Provider 行为变化结果文本不稳定只断言协议达到 ModelCompleted,不断言具体措辞

不变量

回放只能服务同一规范请求;真实网络测试必须显式 opt-in,默认测试不能依赖密钥、网络或模型文本稳定性。

设计取舍与不能外推的结论

完整事件 trace 比 mock 一个最终字符串更接近 Runtime 边界,但会增加 fixture 维护和敏感数据治理成本。Mini 尚未做 trace 脱敏、版本迁移、压缩或 partial-event 录制。

测试与复现

cd examples/mini-codex
uv run pytest -q -k 'test_model_recording_replays_only_matching_request or test_live_responses_stream_reaches_completed'
uv run mypy src
uv run python benchmarks/runtime_baseline.py
  • test_model_recording_replays_only_matching_request
  • test_live_responses_stream_reaches_completed

官方源码导航

Mini Codex 对照

  • src/mini_codex/models/recording.py:fingerprint、录制和回放
  • src/mini_codex/models/responses.py:真实 HTTP/SSE Client
  • tests/test_model_recording.py:离线 deterministic replay
  • tests/test_live_responses.py:opt-in live smoke test

本节结论

回放只能服务同一规范请求;真实网络测试必须显式 opt-in,默认测试不能依赖密钥、网络或模型文本稳定性。

阅读导航

上一节:9.18 · 下一节:9.20

评论


← 返回文章列表