Codex 不靠字符串出现顺序模拟指令优先级,而是保留 developer 与 user 角色。Developer Instructions 描述运行方施加的工作规则;User Instructions 和实际任务描述用户目标。两者可以同处 History,却不能在合并时跨角色折叠。
两类来源先分桶,再生成消息
初始上下文构造器维护 Developer、Contextual User 和“必须独立的 Developer”三个容器。配置级 Developer Instructions、Skills 目录和多数 World State 片段进入 Developer 桶;推荐插件等面向用户的动态信息进入 User 桶;Guardian 策略等审计敏感内容可要求独立消息。
def route_fragment(fragment, buckets):
if fragment.role == "developer" and fragment.separate:
buckets.separate_developer.append(fragment.render())
elif fragment.role == "developer":
buckets.developer.append(fragment.render())
elif fragment.role == "user":
buckets.contextual_user.append(fragment.render())
所谓优先级不是“后写的一定覆盖先写的”。模型协议把 Developer 角色置于 User 角色之上;在同一角色内部,语义更具体的后续片段可以说明替换或撤销。Codex 的 World State 更新正是用明确文本表达这种变更,而不是让模型猜最后出现者获胜。
User Instructions 与本轮 User Input 也不同
Host 提供的 User Instructions 会交给 AgentsMdManager,并与项目文档组成项目规则上下文。用户在界面输入的任务则作为本轮 ResponseItem::Message(role="user") 进入 History。二者角色可能相同,生命周期却不同:前者是可随环境范围更新的上下文,后者是不可随意撤销的事件记录。
async def compile_turn_context(turn, world_state):
context_items = build_initial_context(
developer=turn.developer_instructions,
user_rules=await agents_manager.load(turn.environments),
world_state=world_state,
)
task_item = Message(role="user", content=turn.user_input)
return [*context_items, task_item]
合并边界
build_developer_update_item 可以把多个 Developer section 用约定分隔符合成一条消息;build_contextual_user_message 对 User section 做同类处理。它们只是减少 ResponseItem 数量,不改变每个 section 自带的标记。要求隔离的 Developer 片段绕过聚合,用于保持策略边界可审计。
若实现把两类文字直接拼进同一条 user 消息,模型会把运行方约束当成可被用户请求覆盖的内容;若把用户任务塞进 developer 消息,又会错误提升其权限。测试应捕获最终请求中角色、条数和相对顺序,而不只比较纯文本是否出现。
源码与测试锚点
codex-rs/core/src/session/mod.rs:初始上下文分桶和消息生成。codex-rs/core/src/context_manager/updates.rs:Developer/User 更新项构造。codex-rs/core/src/agents_md.rs:Host User Instructions 与项目规则组合。codex-rs/core/src/prompt_debug.rs:沿真实链路捕获最终角色结构。
评论
登录后即可评论