雨天小六

读懂 Codex(4.6):初始上下文为什么不等于普通用户消息

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

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

初始上下文是 Runtime 在新上下文窗口中建立的“模型视图基线”。它包含 Developer Instructions、Skills 元数据、扩展贡献、完整 World State 和部分窗口元数据;普通用户消息只记录一个真实输入事件。两者即使都表现为 ResponseItem::Message,也不能共享同一种生命周期。

初始上下文是一组编译产物

构造器依次收集静态指令、Thread/Turn Extension 贡献、Token Budget 上下文和 world_state.render_full()。模型切换片段被提前放到 Developer bundle 首部;Multi-Agent Mode 在 usage hint 之后单独插入,使当前模式能够覆盖通用提示。

初始上下文由静态指令、扩展贡献和完整 World State 分层编译
图 4.6-1:初始上下文不是单一来源。构造顺序还承担覆盖语义,因此不能把所有文本放入无序集合后随意拼接。
async def build_initial_context(turn, world_state):
    dev = collect_developer_instructions(turn)
    dev += render_skill_catalog(turn.skills)
    dev += await extension_thread_and_turn_fragments(turn)
    dev += render_token_budget_context(turn)
    dev, user, isolated = route(world_state.render_full(), dev)
    return compile_role_items(dev, user, isolated)

构造完成后,每个 item 会补上当前 Turn ID。压缩创建新窗口时可以直接把这组 items 安装进替代 History,并仍能知道它属于哪个上下文边界。

与普通用户消息的四个差别

维度初始上下文普通用户消息
事实语义当前仍成立的状态与规则某时刻发生的用户输入
角色developer 与 contextual user 混合user
更新可差分、替换、撤销追加保存
压缩后处理必须重建完整基线可被摘要保留语义
初始上下文与普通用户消息在更新和压缩语义上的区别
图 4.6-2:用户消息进入事件时间线;初始上下文建立状态基线。压缩可以摘要事件,却不能假定摘要仍完整携带动态状态。
async def record_first_turn(session, turn):
    world = await build_world_state(turn.step)
    context = await session.build_initial_context(turn, world)
    session.history.set_world_state_baseline(world.snapshot())
    session.history.record_items(context)
    session.history.record_items([Message.user(turn.input)])

为什么需要引用基线

History 保存了初始上下文,并不自动证明 Runtime 仍知道它对应哪份 Snapshot。Session 还会持有引用上下文项和 World State baseline;缺少引用或 History 整体替换时,下一边界必须再次完整注入。否则 Runtime 可能只发“权限从 A 改为 B”,而模型实际已经看不到 A。

测试不能只断言字符串出现,还应验证首次记录顺序、World State full item、TurnContext 基线和重复调用时的去重。

源码与测试锚点

  • codex-rs/core/src/session/mod.rs::build_initial_context_with_world_state
  • codex-rs/core/src/session/world_state.rs:首个 Step 状态构造。
  • codex-rs/core/src/session/tests.rs:基线缺失、清空后重注入和无差异场景。
  • codex-rs/core/src/compact.rs:压缩后初始上下文安装。

评论


← 返回文章列表