On Ownership TokensHolder 不是锁 · 是一枚责任牌
有一次两个 AI 同时改了同一份任务记录, 我事后翻日志才看明白这单事故。
那是一份记录某个问题来龙去脉的文件: 症状是什么, 根因查到哪, 改了什么, 验过没有。Claude 那边判定这件事已经验证通过, 写下了结论; 几乎同一时间, Codex 那边还在按它读到的旧状态往下做, 觉得这事仍然没解决。git 层面没冲突 —— 两个改动落在文件的不同段落, 合得很干净。但合出来的那份记录自相矛盾: 一段说已收尾, 另一段说还在排查。几周后回头复盘, 没人说得清哪句是事实, 哪句是当时的猜测, 哪句只是没来得及划掉的待办。
这件事之后我对"锁"的理解变了。大家一听到锁, 想到的都是"别人不能动"。但跨 AI 协作真正缺的不是这个。真正缺的是: 此刻这件事到底归谁。所以我后来不叫它锁, 叫它责任牌。
锁住的不是文件, 是叙事权
一个仓库里有很多文件, 也可以有很多个 agent 在跑。理论上它们能同时干活, 只要别改同一行。多数普通源码文件确实如此。
但有一类文件不普通。比如那种记录"某件事进行到哪一步"的状态文件, 比如交接用的说明, 比如一张正在被回写的表格。它们的内容不是重点, 它们承载的是一段叙事: 这件事现在处于哪个阶段, 谁已经做完了什么, 哪些证据成立, 下一步该谁接。
两个 agent 同时碰这类文件, 出事的地方往往不在 git。git 能合的冲突是小冲突。真正贵的是叙事冲突: 一个认为任务已经验证, 另一个认为还卡着; 一个写完了结果, 另一个还在拿旧状态往下推。开头那单就是这么塌的。
责任牌要锁的, 就是这个叙事权 —— 同一时刻, 只有一个人有资格改写这件事的当前说法。
没提交的改动是现场, 不是垃圾
以前我看到工作区里一堆没提交的改动, 第一反应是清掉, 嫌它脏。后来在跨 agent 的活里, 我改成把它当事故现场看。
一个没提交的文件, 可能是用户自己手改的, 可能是 Claude 上一阶段留下还没收的, 可能是 Codex 刚生成但没验证的, 也可能是某个自动脚本动的。它不是噪音, 它是归属信号 —— 每一处改动背后都有个"这是谁的"。
所以跨 agent 接手时, 第一件事不是动手整理, 是先认领归属:
这些没提交的改动, 属于我这次要做的事吗?
交接说明里列的"已改文件"包含它们吗?
它是不是踩进了另一个 agent 的责任范围?
它只是本地的临时噪声吗?
要不要拆开提交, 或者干脆排除掉?
这一步很慢, 慢到让人想跳过。但它挡掉的是一个更大的错: 把别人没做完的活当成自己的上下文接着跑, 或者把自己的改动混进别人那一摊里一起提交。前者让你基于一个不属于你的半成品做决策, 后者让那次提交再也说不清是谁的责任。
一件事的全程只能有一个负责人
我们立过一条规矩我很认: 一件事从开个记录、到最后验证通过, 全程由同一个 agent 持有。
它表面上限制了并行, 实际上保住的是可追溯。一份事故记录里会写症状、根因、修复、验证、对应的提交、最终结果。它不是给多人轮流涂的白板, 它是一份档案。
如果根因是 A 写的, 修复是 B 写的, 验证是 C 写的, 中间又没有清楚的交接, 这份记录最后会变成一张拼贴画。每一段单看都通顺, 拼在一起没有一个连贯的人在为它负责。复盘的时候你分不清: 这句是查证过的事实, 那句是当时的推断, 还有一句其实只是没删掉的待办。三个作者, 零个负责人。
责任牌的价值, 是让这份档案有一个明确的作者。不是为了记功, 是为了那条责任链不断。
交班必须先提交, 再带上一份状态说明
跨 agent 换手, 不能靠一句"你接着弄一下"。
人交人尚且要交接单, AI 交 AI 更要。因为接手的 agent 没有上一段对话的体感: 它不知道哪些讨论方向已经被推翻了, 哪些测试只跑了一半, 哪些结论只是上一个 agent 在热乎的上下文里冒出来的、其实没验证过的自信。这种自信幻觉是最坑的, 因为它读起来和真结论一模一样。
所以一次靠谱的换手, 至少要凑齐三样东西。
一是提交。 让代码状态有一个能被拉下来的锚点, 接手的人面对的是一个确定的起点, 不是一团还在变的工作区。
二是一份状态说明。 写清楚哪些做完了, 哪些还没做, 卡在哪, 怎么恢复现场, 以及接手方第一步该干什么。
三是责任牌本身的转移。 让那块牌明确地从一个 agent 手里, 交到另一个手里 —— 旧的人松手, 新的人接过, 中间没有真空, 也没有两个人同时以为牌在自己这。
缺任何一样, 下一个 agent 都只能靠猜。而它猜错的成本, 通常比当初老老实实交接贵得多。
会变的信息, 写"待核"比写一个假精确的值更诚实
状态说明里我还学到一个很微妙的点, 是被真实事故教会的: 会漂的信息, 别假装它精确。
哪些信息会漂?那个提交的哈希值, 工作区里没提交的文件还剩几个, 一张表还有多少行没处理完, 某个东西部署了没有。这些写下交接说明那一刻可能是真的, 但等下一个 agent 真去接手, 中间隔了一段时间, 老会话可能又提交了, 文件可能又被处理掉了一批, 它们大概率已经变了。
我见过一次实际翻车就是这样: 交接说明里写着"还剩四行待处理", 接手方信了这个数去干, 实际早不止四行 —— 写说明的那个会话后来又动过, 这个数字当场就过期了。
最诚实的写法, 不是硬填一个当时的值, 而是标成"待核", 再附上一条能查到最新状态的命令。它传达的意思是: 我知道这个数会变, 所以别信我写的, 你到现场自己重新测一遍。听起来比给个确切数字弱, 其实更可靠。工程里有些不确定性消不掉, 只能老实标出来 —— 假装它确定, 等于把一颗会过期的数据当成决策依据埋进去。
所以接手方的纪律应该是: 先把最新代码拉下来, 再用那条命令验一遍交接说明写时的状态现在还成不成立, 然后才动手。凡是会漂的元信息, 一律以现场实测为准, 不拿交接说明里的快照当真。
责任牌是值班牌
把整个项目想成一艘船。这块责任牌, 就像挂在控制台旁边的值班牌。
它不是说只有这个人能碰按钮。它是说: 警报一响, 大家知道先找谁。要换班, 得先把航行日志写完, 把仪表状态交代清楚, 再把牌子递过去 —— 不是随口喊一声"我下了"。
多 agent 系统真正怕的, 从来不是没人干活。怕的是每个 agent 都在干一点, 但没有任何一个明确为"当前这摊到底是什么状态"负责。每个人都以为别人盯着, 结果谁都没盯。
责任牌把这个隐患摆到台面上。它把"现在归谁"从聊天里的默契, 变成一行所有 agent 都能读到的事实。默契会因为换了个 agent 就断, 写下来的事实不会。
这套摩擦让协作变慢, 但让返工变少
责任牌、强制提交、状态说明、接手前先认领归属 —— 这些都让协作变慢。每一步都像在给流程上沙子。我也烦过, 想绕。
但我现在越来越愿意要这点沙子。因为没有摩擦的多 agent 协作不是没有代价, 只是把代价推到了后面, 而且后面那笔账更贵: 找不到是谁改的, 看不懂当前状态, 同一个问题被重复修, 经验记到了错的地方, 别人没提交的改动被一起裹进了提交。开头那份自相矛盾的记录, 就是省掉这点摩擦换来的。
所以这套东西的目的不是让流程好看。是让事故能往回查。能往回查, 协作才真的成立 —— 否则只是几个 agent 各跑各的, 凑在一个仓库里互相覆盖而已。
「换班之前, 先把航行日志写完。」
BASTION NOTE · 016