数据截至 (上游 commit e2d772072efa)
从模型输出到文件 diff:构建与应用流水线
30 秒导读: 规划阶段(见 01-tell-loop)里,模型已经吐出了「这个文件要怎么改」的一段带占位符的代码片段。本章讲的是下一步:这段话怎么被可靠地落成真实文件的精确 diff。核心是一条四级容错流水线——先用 tree-sitter 直接把片段拼进原文件,拼不干净就多路竞速找补,还不行就让模型整文件重写,最后统一转成
git diff存库。
1. 这是什么(零基础也能懂)
1.1 先分清「规划」和「构建」两件事
Plandex 把「改代码」拆成了两个独立阶段,别混:
| 阶段 | 干什么 | 产物 | 本章 |
|---|---|---|---|
| Plan / Tell(规划) | 模型读上下文,决定改哪些文件、每个文件改成什么样 | 一段带占位符的代码片段 + 一句描述(desc) | 不讲(见 01) |
| Build(构建) | 把那段片段精确落到真实文件上,算出 diff | 一组 Replacement(旧文本→新文本) | 就是本章 |
为什么要分开?因为让模型「一字不差地重写整个大文件」既慢又贵还容易漏行。Plandex 让模型只写改动的那几段,中间用占位符 // ... existing code ... 代表「这里保持原样」,然后由服务端机械地把占位符展开、把改动拼回去。这个「拼回去」的过程,就是 build。
1.2 模型到底给 了什么
想象你让 AI 改一个 200 行的文件,它不会重抄 200 行,而是给你这样一段(proposedContent):
// ... existing code ...
func Add(a, b int) int {
return a + b + 1 // 改了这里
}
// ... existing code ...
外加一句描述(desc),形如 Type: replace / Replace: lines 10-14。
服务端的任务:把这段东西和原文件对齐,搞清楚那两个 ... existing code ... 各自代表原文件的哪些行,Add 函数替换掉原来的哪一段,最后产出一个真实、完整、语法正确的新文件。
1.3 难在哪(为什么不是简单的字符串替换)
模型是不可靠的。它给的片段常常有这些毛病:
- 占位符位置模糊——一个
... existing code ...到底吃掉原文件多少行? - 缩进/空白和原文件对不齐;
- 想「替换」却不小心删掉了不该删的代码;
- 把某段代码重复贴了两次;
- 落点有歧义——同样一行
}在文件里出现 20 次,拼哪一个?
所以 build 不是 strings.Replace 那么简单,而是一套带校验、带兜底的流水线:每一级都假设「上一级可能拼错了」,并准备好下一级去补救。
1.4 一句话直觉
把它想成装修工照着草图砌墙:模型给的是草图(哪几块墙要改),
... existing code ...是草图上「此处保持原样」的省略号。装修工(build 流水线)先按草图快速砌(tree-sitter 直接应用);砌歪了就叫来三个师傅同时返工谁快用谁(竞速);全砌坏了就干脆整面墙推倒重砌(整文件兜底);最后拍照对比出「改了哪几块」(git diff)交工。