Skip to content
研究方法
待周评
两条指令都保存了,为什么恢复后意思反了?从 Codex 到 Agent 上下文的接受顺序
开源工程观察 · 受控实验

两条指令都保存了,为什么恢复后意思反了?从 Codex 到 Agent 上下文的接受顺序

顺序本身也是上下文的一部分。两条输入一条没丢,只因保存顺序与接受顺序不同,重放结果就可能翻转。受 Codex 改动启发,我们用七组受控实验区分收到、接受、保存、恢复与授权;并未证实 CodeFlowMu 存在真实会话排序缺陷。

2026-09-05English →

两条指令都保存了,为什么恢复后意思反了?从 Codex 到 Agent 上下文的接受顺序

查看题图原图

假设你先对一个 Agent——能够调用工具执行任务的智能体——说“允许执行”,随后改变主意,又说“撤销允许”。

如果系统已经依次接受了这两条要求,最后的意思当然是“不允许”。

现在,两条消息都保存了,一条没丢。但后台异步写入,第二条先写完,第一条反而后写完。程序重新启动后,如果只按文件里的先后恢复这段历史,看到的就成了“撤销在前,允许在后”。

文字没有少,意思却可能反了。

这里不是模型突然不理解“撤销”,而是系统把哪条记录先写完,当成了哪条指令先被接受。对于这类顺序敏感的输入,保存全部内容,并不意味着保存了原来的上下文。

顺序本身也是上下文的一部分。

最近,OpenAI 的编程智能体项目 Codex 合并了一项直接处理这个问题的改动。它促使我们做了一组最小实验:不让模型参与,只改变恢复时采用的顺序,看决定是否会翻转;然后再检查,这个问题与 CodeFlowMu 已有的执行保护究竟是什么关系。

1. “接受”为什么不等于“保存”?

可以把它想成餐厅点单。顾客先点了一杯咖啡,随后取消,服务员都确认了。后台却因为不同队列的延迟,先打印取消小票,再打印下单小票。

审阅纸堆的人如果只看打印顺序,可能误以为最后应该做咖啡。问题不是少了一张小票,而是打印完成的先后,不等于服务员确认要求的先后

智能体也会遇到类似的交接:输入到达、系统接受、写入存储,发生得很近,却并非同一个事件。

这里的宿主执行环境(Host),指承载智能体会话、接收输入并组织上下文的系统。“接受顺序”指负责这一过程的系统正式接纳输入的逻辑顺序,而不只是网络请求到达或文件写入完成的时间。

Codex #42770 于 2026 年 9 月 4 日合并。按该变更说明,排队输入和人工交互回答可能按不同于宿主接受它们的顺序被保存。直接采用记录顺序,会影响后续保留的线程上下文,也可能影响回滚边界——恢复到较早位置时,究竟保留哪些输入。

这项改动在启用保留线程上下文的能力时,为相关输入保存接受序号,用于后续重放与边界处理。没有接受元数据的旧记录,则继续按原来的记录顺序兼容处理。

它的价值不只是增加一个数字,而是让恢复程序有依据区分“先被接受”和“先被保存”。但这个序号仍然不是授权凭证:它说明先后,不说明谁有权批准什么。

2. 我们怎样只研究顺序,不把模型能力混进来?

这次没有模拟大语言模型。我们写了一个透明的状态归约器——按顺序读取操作、逐步更新状态的小程序——只认识两种输入:

  • allow:把实验状态设为允许;
  • revoke:把实验状态设为禁止。

两条输入被视为同一实验范围内、同等权威的操作。这个设定用来隔离顺序的影响,不负责模拟管理员与普通用户之间的权限层级,也不是实际业务授权服务。

每个场景保存两份材料:一份记录输入是否被接受及其序号;另一份按指定顺序写入逐行记录文件,每写一条便请求同步到存储。随后另起一个 Node.js 进程——运行实验脚本的独立进程——重新读盘,分别按文件顺序和接受序号计算结果。

最关键的一组对照是:

text
系统接受:1 允许 → 2 撤销
文件保存:2 撤销 → 1 允许

按文件顺序重放:允许
按接受顺序重放:禁止

O1实验示意:相同记录按接受顺序得到禁止,按保存顺序得到允许

图 1:O1 的两种重放方式。两行不是两次独立授权,而是对同一组已接受记录的不同排序;编号始终跟随原输入。实验输入同等权威,不代表真实会话已经发生越权。 来源:本文受控实验的机制示意,非原始观测截图。点击图片查看高清原图。

两种读法使用同一份记录,没有改变消息内容。最终决定翻转,只因为恢复时相信了不同的排序依据。

这里必须说明:反序是我们主动安排的,并不是观察到一次自然发生的生产事故。实验回答“这类顺序分离能否改变结果”,不回答“真实系统多久发生一次”。

同样,另起进程读盘证明的是这份实验日志可以被新进程重放,不是完成了一次真实智能体会话的崩溃恢复。

3. 反序不一定出错,七组对照把条件找出来

七个场景各运行两轮,共得到 14 条新进程重放观测,两轮结果一致。下表用中文呈现程序输出:允许对应 allow,禁止对应 deny,未知对应 unknown

场景输入与扰动按记录顺序按接受顺序
O0允许 → 撤销,正常保存禁止禁止
O1允许 → 撤销,反序保存允许禁止
O2撤销 → 允许,反序保存禁止允许
O3撤销 → 撤销,反序保存禁止禁止
O4撤销后的允许没有被接受禁止禁止
O5反序,并缺少一个接受序号允许未知
O6反序,两个接受序号重复允许未知

O1 展示了开头的翻转,O2 则说明影响也可能朝相反方向发展:一次后来的允许,被错误解释成先前已被撤销。问题不只是“多放行”,也可能是错误地保持禁止。

O3 是必要反例。两次都是撤销,交换前后,结果仍然不变。因此,记录乱序不等于业务决定一定错误,还要看操作是否对顺序敏感。

O4 又拆开了“收到”和“接受”:后来的允许虽然出现在记录中,但没有被正式接受。两种读法都会先排除它,不能让它仅凭位置靠后就改变状态。

O5、O6 则检查顺序证据本身。如果接受序号缺失,或者不同输入拥有重复序号,这份记录就无法支持唯一可靠的接受顺序。我们的读取程序返回“未知”,而不是偷偷拿文件位置补造历史。

“未知”首先表示证据不足,不是现实系统所有场景都必须采用同一处置。尤其不能把它写成 Codex 的实现:本地实验对无效序号返回未知;Codex 对没有接受元数据的旧记录保留记录顺序。两者的对象和规则不同。

4. 排序正确,也不能把未来放进过去

顺序之外,还有一个独立问题:恢复的是哪个时点的上下文?

如果系统依次接受“允许”和“撤销”,而我们要检查的是“刚接受第一条输入时知道什么”,那么只能读到允许。撤销后来确实发生了,却不能提前影响那个时点的判断。

因此,同一组实验还设置了“只使用接受序号不大于 1 的记录”这一截止点。在 O0、O1 中,无论最终文件怎样排列,这个截止点都只得到首次允许,不会把后来的撤销带进来。

排序回答哪条在前;截止点回答截至所选边界,哪些输入已经可以进入判断。

在本实验中,截止点以接受序号定义,并不是对任意真实系统的时间戳、证据可见性或访问权限做了完整验证。但它提醒我们:找对先后关系,与选对恢复边界,是两件都需要明确的事。

5. CodeFlowMu 已有的命令保护,回答的是另一个问题

CodeFlowMu 是我们正在开发的本地多智能体协作系统。它通过 FCoP 文件型协作协议维护任务、报告与角色责任,由运行系统执行明确的技术动作。正式任务不是简单依靠聊天记录中“最后一句说了什么”来裁决。

本轮固定产品提交为 c008d9db91a21136fc61a4f60314e22db395d5d2。其中,任务命令统一核验入口 TaskCommandKernel 检查任务和线程身份、任务版本(revision)、执行轮次(round)、角色或范围授权,以及幂等回执——用于识别重复命令并复用已完成结果的记录。

相关命令与角色测试共 31 项,运行两轮,每轮均为 31 通过、0 失败、0 跳过。这不是 62 项不同测试。对本题有意义的,是其中具体保护了什么:

既有检查被验证的边界
陈旧任务版本返回 stale_task_revision(任务版本已过期),底层动作调用次数为 0
陈旧执行轮次旧轮次请求不能据此改变当前任务
同一幂等标识、不同语义内容拒绝冲突,不能冒充原命令
已完成命令的回执重放复用结果,不再次执行动作

接受序号问:“用户先提出哪条要求?”任务版本检查问:“这条命令现在仍然针对当前任务状态吗?”两者不能互相替代。

例如,历史记录即使准确恢复了“曾经允许操作版本 5”,也不能让这条旧许可自动作用于当前版本 6。反过来,正确拒绝旧版本,也不能证明会话保存与恢复没有重排输入。

源码中的 Codex 输入追加适配 steer() 还传递预期的对话回合标识和可选用户消息标识。但字段存在,不等于已经证明它们能让接受顺序穿过存储、上下文压缩和恢复全过程。

这里的会话回合,与正式任务的执行轮次也不是一个概念。前者组织会话交互,后者约束任务执行;都不能只凭一个相近的名字互相替代。

我们的机制实验没有证实 CodeFlowMu 存在真实会话排序缺陷;现有命令测试通过,也不能代证会话上下文恢复正确。

6. 值得研究的是三个交接点,不是立即再造组件

这个区别,决定了外部改动怎样成为自己的工程研究,而不是自动变成一个开发任务。

第一,谁在什么时刻确认输入已经被接受? 请求到达、排队成功、目标会话接受、当前回合真正使用,可能是不同事件。负责上下文的系统需要说明采用哪一个,不能事后用文件写入时间反推。

第二,这个接受事实怎样穿过保存与恢复? 序号在哪个范围内有效,怎样保持唯一,缺失或重复时如何处理,压缩后是否还在,回滚依据什么边界,旧格式怎样兼容,都需要具体实现和证据。不能给当前文件重新编号,就宣称找回了历史接受顺序。

第三,恢复后由谁验证当前执行资格? 顺序准确,只表示历史被正确解释;当前角色、任务版本、执行轮次、授权是否仍有效、动作是否已经发生,还要由各自的执行规则检查。

一份会议记录可以证明谁先发言、谁后发言,却不能仅凭顺序证明谁有权批准付款。对智能体也是如此:接受顺序不是授权,过去允许过也不等于现在仍然允许。

这三个交接点的研究价值,在长时间运行的智能体上尤其明显。会话越常经历排队、人工回答、压缩、重启和回滚,恢复的就越不只是一个文字列表,而是一段有先后、有边界的历史。模型更聪明,并不会自动替系统保存这些关系。

因此,我们没有据此要求 CodeFlowMu 新增一套接受序号模块。下一步应检查真实会话的输入—接受—保存—压缩—恢复链,明确宿主已有能力与本地职责,再判断是否存在需要开发的缺口。

7. 记录完整,不自动意味着语义完整

本轮研究证明,在固定、顺序敏感的最小模型中,用保存顺序替代接受顺序,确实能够改变恢复结果。反向翻转、相同操作、未接受输入、无效序号和截止点,分别限定了结论适用的条件。

它没有测量自然竞态的发生概率,没有证明真实智能体越权,也没有测试跨用户权限竞争、执行中动作的撤销或完整上下文压缩链。我们没有运行 Codex 的 Rust 测试;CodeFlowMu 既有回执测试中,名为“进程重启”的案例使用对象重建与回执依赖,不能被包装成又一次真实宿主崩溃恢复。

本轮也没有形成新的产品开发授权。

回到开头,两条指令都保存了,为什么意思仍可能反过来?因为对于顺序敏感的上下文,保存了内容,还不一定保存了这些内容原本如何组成历史。

可靠恢复不仅要找回记录,还要保留解释记录所需的顺序与边界;恢复出过去的意思,也不等于获得现在的执行许可。

证据与复核

随稿证据说明包含两轮脱敏重放记录、可独立运行的顺序探针、正式命令测试摘要及固定源码哈希。

证据检查脚本只验证导出观测的一致性与文件完整性,不重新执行产品代码,不证明检测准确率、生产可靠性或独立验收通过。本次文字修订没有新增实验,正文数字仍对应 2026 年 9 月 5 日的固定基线。

Last updated: