Francis Du.

💻Data Engineer | 🦀 Rustacean | 📷 Photographer | 🤖Vibe Coder

12 2026年9月

wcode v0.6.1:`parallel_tools` 不再按层等

本文目录9 个章节

v0.6 开始在 agent_context 里标出可以并行的工作。接着我去看 Runtime 本身,发现 parallel_tools 虽然已经有依赖图,执行时还保留着按层推进的做法。

例如:

A ─→ C

B ─────────→ D

假设 A 100ms 完成,B 要 5s,C 只依赖 A。

按“层”执行时,很容易变成:

第一层:A + B
        ↓ 等两者都结束
第二层:C + D

C 明明在 100ms 时已经 Ready,却因为一个和自己无关的 B,被迫多等几秒。

所以 v0.6.1 我把调度器改成了 completion-driven。

wcode TUI

Ready 的任务不应该等同层慢分支#

现在 Scheduler 只看一个问题:

这个任务自己的前置依赖是不是已经完成?

满足就进入 Ready Queue。

实际任务图通常不整齐。一个慢测试、一个大文件读取、一个外部命令,不该顺手把无关分支也拖住。

失败也只应该污染依赖它的分支#

同样的原则也用在失败上。

如果:

A → C
B → D

A 失败,那么 C 应该被 Skip,因为它的前置不成立;但 B 和 D 不应该跟着一起失败。

所以运行时会区分依赖失败导致的 Skip、当前任务自己的运行失败,以及完全独立、仍然可以继续的分支。

这对批量读取、搜索、验证尤其重要。Agent 不应该因为一个不存在的可选文件,就失去其他已经能确定的结果。

Partial 不能假装 Complete#

这轮我把批处理结果的语义也重新收紧了。

批量读、创建、编辑、移动会明确报告:

complete
partial
failed

并保留逐项结果。

如果一个批次只完成了一部分,MCP Result 会保守地带错误标记,依赖整个批次的后续任务不能把它当作完整输入。独立分支仍然继续。

重试也不应该重放整个批次。先核对状态,只重试失败项。这对写操作尤其重要,因为“请求失败”不等于“所有副作用都没发生”。

并行写入最怕错误合并#

为了减少 Tool Call,wcode 会在安全条件满足时合并部分文件编辑。

这里我宁愿少合并一点。

同一个文件、同一个 SHA 的 Edit,如果中间隔着一个依赖 Read、Move 或其他会改变语义的操作,就不能跨过去合并。否则 Scheduler 会把原本有先后关系的工作偷偷变成一个事务。

合并前也会检查既有的 128 项编辑上限,不能因为优化路径就绕过原来的安全边界。

如果一次优化改掉了原本的先后关系,那就已经不是调度优化了。

Cancel 也必须真的往下传#

异步系统里还有一个很烦的问题:外层任务取消了,不代表里面已经排队的工作自动消失。

如果父请求断开,而子任务还在队列里,最糟的情况是用户以为“已经取消”,几秒后某个写操作才突然开始。

v0.6.1 把取消传播继续往下压:父任务取消会取消仍在排队的子任务;持久 MCP Task 被取消或 TTL 过期,也会取消它拥有的执行任务。

已经开始的阻塞文件操作不会假装回滚。这条边界也要说清楚。

并发许可要跟真实工作走#

以前还有一种容易让面板数据看起来比实际更漂亮的情况:外层 Future 被取消以后,如果并发许可提前释放,但底层阻塞工作其实还在跑,就会出现“系统看起来有空位,实际上旧工作没结束”。

现在已经启动的阻塞工作会继续持有对应许可,直到结束或异常退出。排队工作取消则会释放预留。

我更愿意让数字难看一点,也不想让 Scheduler 对自己的真实资源状态撒谎。

Context 也继续往目标优先收紧#

顺手还改了一轮 agent_context 的候选排序:精确定义优先于相似辅助函数;直接目标文件优先于按字母排在前面的 Design 映射;并行建议开始结合当前 Scope、活动 Worklist Lane 和运行时并发上限,而不是固定最多四路。

Lane 数只用来给 Agent 提示,并不能证明两件事真的独立。最后仍然由真实资源和依赖决定能不能一起跑。

Observatory 不再把“有映射”当“已验证”#

Project Observatory 这轮还修了一个我很在意的表达问题。

以前“某个 Requirement 有 Verification 映射”和“这个 Revision 上真的执行并通过了验证”在视觉上太容易靠近。

现在会明确区分:

verification mapped
executed
passed
fresh proof

因为有测试文件,不等于测试跑过;测试跑过,也不等于它属于现在这份代码。

这版主要把无意义等待拿掉#

v0.6.1 基本都在修执行语义:Ready 就进队列,失败只截断依赖分支,Partial 明确报告 Partial,Cancel 继续往子任务传,许可跟着真实工作释放。

它不会把本来串行的任务凭空变快,但长任务里少掉几次无关等待,体感很明显。

再往后到 v0.6.2,我又继续拆了一个误区:外层 SLOTS 很高,不代表真实吞吐就高。