雨天小六

读懂 Codex(5.15):Reasoning Summary/Content 的增量组装

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

#Codex#Agent Runtime#Responses API#流式协议#软件架构

Reasoning 流有两条不同合同:可展示的 Summary 带 summary_index 和分节事件,原始 Reasoning Content 带 content_index。并发摘要 Feature 还会把逐 Delta 模式切换为按完整 Summary Part 交付。

具体问题与启用条件

本节研究 Reasoning 的事件路由,不讨论模型是否应显示推理内容;请求侧能力门控已在 5.4、5.6 说明。

条件来源决定字段或状态对本机制的影响
模型supports_reasoning_summaries决定请求是否要求 summary
Feature + ProviderConcurrentReasoningSummaries 且 OpenAI使用 sequential cutoff 的 Done 模式
活动项Reasoning TurnItem 正在 stream允许发摘要/原始内容 Delta

协议、类型与状态所有权

状态或协议所有者生命周期关键不变量
summary_index服务端事件Reasoning Item 内标识摘要分节
content_index服务端事件Reasoning Item 内标识原始内容块
ReasoningContentDelta EventSession event stream暂态 UI摘要文本,不写 History
完整 Reasoning ResponseItemOutputItemDoneHistory/Rollout含 summary/content/encrypted_content

机制调用链如下:

OutputItemAdded(Reasoning)
→ 普通模式:summary delta + part added
→ 或 cutoff 模式:summary done(full part)
→ reasoning_text.delta(content_index)
→ UI summary/raw events
→ OutputItemDone(full Reasoning)
→ History/Rollout
Reasoning Summary 在逐 Delta 与完整 Part 模式间切换
图 5.15-1:两种模式互斥,避免同一摘要重复展示。

机制怎样工作

普通模式把 reasoning_summary_text.delta 映射为带 summary_index 的 ReasoningContentDelta,reasoning_summary_part.added 映射为 section break。启用 ConcurrentReasoningSummaries 且 Provider 是 OpenAI 时,Core忽略这两种事件,改等 reasoning_summary_text.done;当 summary_index>0 时先发 section break,再把完整 part 文本作为一次 Delta 发出。这样避免并发生成摘要时逐 token 截断顺序不稳定。

reasoning_text.delta 是另一条原始内容通道,映射为 ReasoningRawContentDelta 并保留 content_index。两条流都要求 active item 存在且允许 stream;最终 History 仍只记录 Done 的完整 Reasoning Item,其中 encrypted content 还可用于后续请求。UI 摘要是否出现不改变模型上下文事实。

Python 风格伪代码

这段伪代码保留生产实现中会改变结果的状态、分支和异步边界;认证 SDK、遥测字段和 Rust 所有权样板被折叠为明确的领域对象。

async def on_reasoning_event(event: ResponseEvent, state: ReasoningState):
    item = state.active_reasoning_item()
    if item is None or not state.stream_to_client:
        return
    if isinstance(event, ReasoningSummaryDelta):
        if not state.sequential_cutoff:
            await emit_summary_delta(item.id, event.summary_index, event.delta)
    elif isinstance(event, ReasoningSummaryPartAdded):
        if not state.sequential_cutoff:
            await emit_section_break(item.id, event.summary_index)
    elif isinstance(event, ReasoningSummaryDone):
        if state.sequential_cutoff and event.item_id == item.id:
            if event.summary_index > 0:
                await emit_section_break(item.id, event.summary_index)
            await emit_summary_delta(item.id, event.summary_index, event.text)
    elif isinstance(event, ReasoningContentDelta):
        await emit_raw_reasoning_delta(item.id, event.content_index, event.delta)

失败、取消与恢复

Reasoning 的原始内容、摘要展示和完整项提交
图 5.15-2:两个增量通道只服务展示,完整 Reasoning Item 才进入 History。
故障或边界已发生的状态对上层的结果能否直接重试恢复动作
Reasoning Delta 无 active item无法归属 Item内部错误/忽略特定 Done检查事件序列
Done 的 item_id 与 active 不同可能是迟到事件cutoff summary 被忽略不适用等待正确项
切换模式却双重消费摘要会重复实现通过互斥分支避免不适用只选 delta 或 done
流中断UI 有部分摘要完整 Reasoning 不提交重试不带暂态片段

设计取舍与验证

两种摘要交付模式增加了条件分支,却允许普通模型获得低延迟、并发摘要模型获得稳定分段。保留 index 而不是只拼字符串,使客户端可以画分节和并行内容;代价是客户端也要理解 Item ID 与索引。

可验证契约证据方式预期结果
普通 summary delta 保留 indexSSE 映射测试事件文本和 summary_index 相同
Summary Done 携带 item_id/full textparser 测试cutoff 模式可一次交付 part
Reasoning Item 最终进入生命周期items 测试Started/Delta/Completed 使用同一 ID

Mini Codex 对照

Mini Codex 可以只实现 Summary Delta,但事件类型仍应保留 summary_index。若加入并发摘要,使用显式模式枚举,不能同时消费 delta 与 done。原始 content 应单独通道,不与 summary 混写。

本节边界

Reasoning 的增量协议已经拆开。5.16 转向工具参数,并纠正一个关键误区:并非所有 Function Call 都有客户端 Diff 累加器。

评论


← 返回文章列表