雨天小六

读懂 Codex(4.17):Function Call 与 Output 的配对修复

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

#Codex#Agent Runtime#Prompt#上下文工程#软件架构

普通函数调用靠 call_idFunctionCallOutput 配对。发送前规范化执行两个方向的检查:有 call 无 output 时在 call 后插入合成 aborted;有 output 无 call 时删除孤儿 output。修复顺序固定为“先补缺,再删孤儿”。

先建立所有 output ID 集合

规范化器先扫描现有 outputs,构造 function_output_ids;再遍历 calls,收集所有缺失 output 及其插入位置。最后按索引逆序插入,防止前一次插入改变后续位置。

FunctionCall 缺少结果时在其后插入 aborted 合成结果
图 4.17-1:先扫描、后逆序插入保证多次缺失调用各自紧邻结果,时间顺序不被索引移动破坏。
def ensure_function_outputs(items):
    output_ids = {x.call_id for x in items if is_function_output(x)}
    pending = []
    for index, item in enumerate(items):
        if is_function_call(item) and item.call_id not in output_ids:
            pending.append((index, FunctionOutput(
                id=stable_synthetic_id("fco", item.id),
                call_id=item.call_id,
                output="aborted",
            )))
    for index, output in reversed(pending):
        items.insert(index + 1, output)

aborted 不是工具真的返回了该文本,而是告诉模型这次调用已不可能继续,避免它等待一个永远不会到来的结果。

合成 ID 必须稳定

若源 call 有 item ID,合成 output ID 用固定 UUID namespace 和 prefix:source_id 生成 UUIDv5;同一原始历史在重试或恢复时得到同一个 ID。源 call 没 ID 时保持兼容,合成 ID 也为空。

缺失结果补全与孤儿结果删除的双向配对规则
图 4.17-2:call 是意图,output 是观察。任何一边孤立都会破坏因果结构;合成修复只存在于 Prompt 副本。
def remove_orphan_function_outputs(items):
    call_ids = {x.call_id for x in items if is_function_call(x)}
    shell_ids = {x.call_id for x in items if is_local_shell_call(x)}
    items[:] = [x for x in items
                if not is_function_output(x)
                or x.call_id in call_ids | shell_ids]

Function output 也可以对应 LocalShellCall,删除孤儿时要把两类 call ID 联合判断。重复 call_id 属于上游协议异常,规范化器不是通用事件数据库,不负责猜测应该匹配哪一次。

源码与测试锚点

  • codex-rs/core/src/context_manager/normalize.rs:补缺、稳定 ID 与删孤儿。
  • codex-rs/core/src/context_manager/history.rs::for_prompt:调用边界。
  • codex-rs/core/src/context_manager/history_tests.rs:missing/orphan function output。

评论


← 返回文章列表