跳转到内容

指挥后台工作进程

本指南介绍如何以指挥者而不是工作进程的身份运行一段对话:会话负责读取和验证,后台智能体负责编辑。

有两件事,其中只有第一件由机制强制保证:

  1. 会话自身的工具降级为只读,另外还剩五个工作进程动词。它影响仓库的唯一途径是通过工作进程,而它了解发生了什么的唯一途径是读取工作进程动过的文件。
  2. 它被告知要通过读取来验证,而不是靠相信。 工作进程的报告只是关于它做了什么的一种声称,而不是它确实做成了的证据。

第一件才是关键。一个仍能 grep、仍能编辑的指挥者,在压力之下就会亲自动手去做这些工作,而这正是这套机制存在的目的——避免这种失败模式。

/vibe migrate the auth module to the new session API

工作进程从未见过你的对话,以后也永远不会看到。简报就是它的全部上下文。

这正是这套模式保持低成本的原因——二十个工作进程各自持有指挥者的历史,代价会是指挥者上下文的二十倍——也正是这一点让简报难以撰写。“顺便把另一个也做了”,对指挥者读起来是一条完整的指令,对一段全新的会话则完全等于什么都没说。

一份好的简报会点明文件、命令以及“完成”的定义:

在 lib/features/auth/ 中,把对 SessionStore.read(key) 的每一处调用替换为 SessionStore.get(key)。新方法返回 Future<String?>,而旧方法返回 String?,因此调用方需要 await。完成后运行 fvm flutter analyze lib/features/auth,并报告所有你无法修复的错误。

动词 作用
vibe_spawn 依据一份简报启动一个工作进程。立即返回。
vibe_list 所有人的层级、状态、已用时间和最近一次结果
vibe_send 为已结束回合的工作进程追加一个后续回合
vibe_wait 阻塞,直到某个工作进程结束
vibe_kill 停止某一个工作进程

启动工作进程在设计上就是异步的。每次启动都阻塞的指挥者,等于一次只跑一个工作进程,这不过是用更慢的方式做它本来就在自己做的事。只有当你确实缺了某个具体答案就无法继续时,才使用 vibe_wait。

层级 适用场景
fast 规格明确的机械性工作——编辑、重命名、草拟、运行命令
good 设计、判断,或审查一个 fast 工作进程的产出

一种常见的做法是把 fast 工作进程扇出到相互独立的文件上,然后再启动一个 good 工作进程,审查它们共同的产出。

这一部分决定了这套模式到底有没有价值。

vibe_list
→ w1 [fast] auth-migrate — done (48s): Edited lib/features/auth/session.dart …
w2 [fast] tests — running (12s)

然后读取它提到的那些文件。指挥者拥有 read、search、lsp 和 ast_grep;保留这些工具正是全部意义所在。把报告照单全收的指挥者,只是在替其他智能体的乐观说辞做摘要。

在一轮工作进程结束后执行 lsp(action: "diagnostics", file: "*"),通常是最快的单项检查。

终止它,重新写一份简报。一份全新且经过修正的简报比一场争论更便宜,而且 vibe_send 只对已经结束回合的工作进程有效。

vibe_kill(worker_id: "w2")
vibe_spawn(brief: "…corrected…", label: "tests", tier: "fast")
  • 最多八个并发工作进程。 这是花费上的上限,而不是技术限制:每一个都是完整的模型会话,而扇出二十个工作进程的指挥者,已经不再清楚它们都在做什么了。
  • 没有工作进程能比这个模式活得更久。 运行结束时,它们每一个都会被停止,转录中会说明一共多少个。对话已经继续往下走了,后台智能体却还在编辑文件——这是绝对不能出现的一种失败。
  • 工作进程本质上就是普通的子智能体。 相同的深度上限、相同的护栏策略、相同的运行日志子项。vibe 改变的是由谁驱动它们,而不是它们被允许做什么——因此工作进程的 write 和 exec 调用仍会弹出批准提示。

vibe 模式适用于能拆解成一份份独立简报的工作。如果下一步依赖上一步的产出,你描述的其实是流水线或编排,这两者都能以正确的方式表达依赖关系,而不必让指挥者用 vibe_wait 去模拟它们。