看板上明明还有工作,队友为什么都在等?
为了回答“main.py 的本次输出是否符合预期”,Lead 登记了三项工作:读源码、读 expected.txt,以及依赖前两项的运行核对。
reader 做完一项,问“接下来做什么”;reviewer 也在等新指令。Lead 只好再看一遍任务表,逐个分配。任务已经写在共享看板里,为什么还要把同一份安排重新讲一次?
这一课把发现下一份工作的职责交给宿主:队友空闲时检查看板,成功认领一项,再交给自己的 Agent 循环处理。 这是本课所说的自主工作(Autonomous Agents),不要求模型每隔几秒问一次“还有事吗”。
源码和预期可以先查,核对输出依赖这两项。两个队友都会检查同一看板,不需要Lead分别指定下一项。
- Lead登记工作,不逐项派发:源码和预期可以先查,核对输出依赖这两项。两个队友都会检查同一看板,不需要Lead分别指定下一项。
- reviewer先认领预期:这里演示一次可能的时序:reviewer在锁内读取最新看板,成功保存owner与in_progress,再离开锁开始工作。
- reader重新检查,拿到另一项:reader即使刚才也看见expected,此时也必须重读。它发现预期已被认领,转而取得source,不覆盖reviewer的负责人。
- 只完成源码,还不能做核对:reader保存真实读取证据后完成source。expected还在进行中,verify仍被阻塞;没有可认领项,不代表全部工作完成。
- 两项证据齐了,verify才进入候选:reviewer完成预期读取后,后续检查能发现verify。完成前置只解锁任务,不会立即运行程序。
- 再次认领后,仍要经过执行许可:reader在下一次检查中取得verify,再交给原Agent循环。工具入口继续核对负责人和宿主许可,自动取任务不会扩大权限。
- 实际输出核对通过,才完成任务:本次程序真实输出42,与读取的预期一致,宿主才保存completed。随后空闲检查可以结束,关闭仍走单独协议。
- Lead登记工作,不逐项派发:源码和预期可以先查,核对输出依赖这两项。两个队友都会检查同一看板,不需要Lead分别指定下一项。
- reviewer先认领预期:这里演示一次可能的时序:reviewer在锁内读取最新看板,成功保存owner与in_progress,再离开锁开始工作。
- reader重新检查,拿到另一项:reader即使刚才也看见expected,此时也必须重读。它发现预期已被认领,转而取得source,不覆盖reviewer的负责人。
- 只完成源码,还不能做核对:reader保存真实读取证据后完成source。expected还在进行中,verify仍被阻塞;没有可认领项,不代表全部工作完成。
- 两项证据齐了,verify才进入候选:reviewer完成预期读取后,后续检查能发现verify。完成前置只解锁任务,不会立即运行程序。
- 再次认领后,仍要经过执行许可:reader在下一次检查中取得verify,再交给原Agent循环。工具入口继续核对负责人和宿主许可,自动取任务不会扩大权限。
- 运行被拒绝,保留未决任务:先前读取仍已完成,verify保留owner与in_progress,交回宿主处理。不会换个队友再试,也不会把模型答完当成任务完成。
图中以 reviewer 先拿到预期任务为例;真实并发运行时,谁先拿到哪项可以不同。我们关心的是负责人和状态始终一致,而不是复刻某一份终端输出顺序。
看见同一张卡,不等于拿到了同一项工作
假设两人同时扫描,都发现 expected 可以开始。如果各自直接沿旧列表执行,就可能把同一个文件重复读两次,还都认为自己是负责人。
因此要分开两个动作:扫描回答“这个快照里有什么可做”,认领回答“现在能不能把它交给我”。扫描只返回候选;真正认领时,宿主在同一把锁内重新读取、复查并保存负责人。只有成功返回 claimed,才能开始工作。
本例同进程里的所有任务写入共用一把 RLock。reader 认领时若发现 expected 已归 reviewer,就取另一项,或者交回空闲结果。旧快照没有授予执行资格。
这把锁覆盖短小的读改写。模型请求、文件工具和程序运行放在锁外,否则一个慢工具会让其他队友连更新进度都做不到。
有依赖,为什么后来又能认领?
可认领需要三个事实同时成立:任务是 pending,没有负责人,所有依赖均已 completed。有依赖不是问题,仍有未完成依赖才会阻塞。
source 完成而 expected 还在进行中时,verify 继续等待。两项都完成以后,下一次扫描才把 verify 加入候选。没有某个额外的“现在派发给 reader”动作,也没有因为前置完成就立即运行程序。
这和第十二课的任务图是同一条依赖规则。新增的是队友空闲时会主动检查,并把最新认领结果交给自己的工作轮次。
空列表为什么不能翻译成“全部完成”?
看板没有可认领项,可能是所有工作都完成了,也可能是其他队友正在处理前置,或者有任务仍被依赖挡住。
所以本课的空闲结果只说明“这次没有拿到工作”。宿主可以释放锁,短暂等待,再检查一次;等待期间其他线程可以完成任务,也可以发来关闭请求。
示例最多检查三次,两次检查之间用 Event.wait 等待 0.05 秒。次数用完返回 idle_timeout,交回控制权。它没有证明整个目标完成,也不等于走完了上一课的关闭握手。
这只是便于立即运行的有限实验。检查次数和等待间隔属于宿主调度;一轮最多问模型几次、一个成员最多接几轮,是另外两层预算。
任务和关闭请求同时出现,先做哪一个?
如果队友已经被请求结束,却先不断取新任务,关闭就可能一直等不到空闲边界。
本例在每次空闲检查中先看自己的实际关闭协议,再看任务。关闭确认保存成功后,成员变为 closed,这次不再认领;Lead 随后匹配回复,完成自己的请求状态。确认保存失败也不能绕过去继续拿工作。
这个优先级发生在检查边界。它不会强制中断已经开始的工具;工作期间收到请求,仍等当前轮次结束,再由同一个成员线程处理。普通消息则保留到下一次真实工作时接入历史,不单独启动一轮模型来等待。
自己取到任务,是否也能自己允许执行?
不能。这里自动选择的是宿主已经登记的固定步骤,工具能力和执行许可仍然独立。
verify 被认领以后,run_main 依然需要宿主允许。拒绝时,source 和 expected 的完成记录保留,verify 仍是 in_progress,负责人也保留,交回宿主处理。系统不会把它退回队列,再换一个成员反复尝试。
即使模型正常回答,也不立即完成任务。宿主要看到成功的工具结果,并确认本次程序输出与读取的预期一致,才保存 completed。把预期改成 43 后,程序仍输出 42,任务就不能被误标为通过。
自主工作减少了逐项派发,没有消除执行边界或失败处理。实践篇展开扫描、认领和空闲检查三个函数,并让两条真实线程竞争同一份看板。
社区课程 Autonomous Agents提供了空闲时查板与自主认领的学习方向;Claude Code 的官方任务协作文档也描述共享任务、依赖和自认领。本文的同进程锁、三次检查与有限交付是自己的教学设计,不把它们写成产品默认机制。