雨天小六

读懂 Codex(4.5):ContextualUserFragment 的边界标记和合并规则

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

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

ContextualUserFragment 是 Runtime 注入上下文的统一协议:每个实现声明角色、正文、起止标记,以及是否必须独立成一条消息。它解决的不是排版问题,而是“这段模型可见文本以后还能否被准确识别、替换和迁移”。

片段的五个契约

方法含义
role()生成 developer 还是 user 消息
markers()当前实例的起止边界
type_markers()类型级识别边界
body()标记内部正文
requires_separate_message()禁止与相邻同角色片段合并
ContextualUserFragment 用角色、标记和正文形成可识别边界
图 4.5-1:标记包围整个正文,识别器要求去除首尾空白后同时匹配起止标记。只有一个边界命中不会被当成合法注入片段。
class ContextFragment(Protocol):
    role: Literal["developer", "user"]
    start_marker: str
    end_marker: str
    separate: bool

    def render(self) -> str:
        if not self.start_marker and not self.end_marker:
            return self.body()
        return self.start_marker + self.body() + self.end_marker

matches_marked_text 对标记大小写不敏感,但要求两端同时存在。空标记片段永远不会用“任意文本匹配”冒充某种上下文。这个保守策略可避免用户恰好输入类似内容时被迁移代码误删。

合并发生在渲染之后

初始构造先按角色和隔离要求分桶,普通片段在桶内渲染,再由 build_*_item 合成 ResponseItem。后续 World State 差异则由 merge_contextual_fragments 只合并相邻、同角色且均允许合并的片段。

相邻同角色上下文片段的合并与隔离规则
图 4.5-2:角色变化或 separate 标志都会切断合并组;片段自己的边界仍完整保留,所以合并只减少消息条数,不丢失类型身份。
def merge_fragments(fragments):
    groups = []
    for fragment in fragments:
        if (not groups or fragment.separate
                or groups[-1].separate
                or groups[-1].role != fragment.role):
            groups.append(MessageGroup.from_fragment(fragment))
        else:
            groups[-1].append(fragment.render())
    return [group.to_response_item() for group in groups]

失败边界

若只用开标签识别,截断历史可能留下半个片段并被误判;若合并跨角色,指令权限会改变;若先拼正文后丢掉每段标记,World State 无法确认保留历史里究竟还有哪个分区。要求独立消息的策略片段则用于审计和上游协议边界,不能为了节省一个 item 强制合并。

源码与测试锚点

  • codex-rs/context-fragments/src/fragment.rs:trait、渲染和双端识别。
  • codex-rs/core/src/context_manager/updates.rs:相邻片段合并。
  • codex-rs/core/src/session/mod.rs:初始上下文分桶与隔离。
  • codex-rs/core/src/context/world_state/*_tests.rs:旧片段识别与保留匹配。

评论


← 返回文章列表