🛠️ 第5章 第一个可复用工作流:在 emotional_chat 项目中稳定复用
📄 一句话概括

一次最小变更四个动作:写成两行需求、先出计划、改完当场验、留痕两段。 计划的价值不是让你看懂,是把「不动的地方」变成明文承诺。 Demo 里不出计划那版动了三个文件十二行,出计划那版只动一行。

📝 本章和前面几章的关系

前面两篇把前提准备好了:能跑、能验。这一篇走一遍完整流程。 为什么强调「最小变更」?因为流程的价值要在小事上看清。 大事上变量太多,你分不清哪一步起了作用。 Demo 用同一个需求做了两遍:一遍不出计划直接改,一遍先出计划。 两遍的代码改动量、文件数、提交内容都摆出来对比。

一、选一个真需求

真需求的意思是:它真的需要改代码,而且改完有办法判断对不对。 「重构一下这个模块」不是真需求——它没有终点。 把需求写成两行:目标一行,验收一行。 只有目标那一行的时候,「返回一句默认话」也算合法实现。 Demo 里那两行是: 目标「空消息不该回话」,验收「handle 拿到空串或纯空格时返回空串,且不调用 reply」。 第二行把「不该回话」这个含糊的说法变成了可执行的判断。 一个自查方法:把验收那行交给别人,他能不看代码就判断对错吗? 不能,就还不够具体。

二、让 Agent 先出计划

计划要包含四样:会改哪、不动哪、怎么验、大概几步。 最容易漏的是「不动哪」——而它恰恰是计划里最值钱的一项。 为什么?因为 Agent 的默认行为是「顺手」。 它看到等级表里 2、1、0 这三个数,会觉得「改成 3、2、1 更整齐」; 它看到 README 写得乱,会觉得「顺便整理一下」。 这些都不在你的需求里,但它觉得这是做好事。 Demo 里不出计划那版就是这么歪的:需求只值一行,实际动了三个文件、加两行删十二行。 多出来的两处,全是「顺手」。 写了「不动 emo.py」,它就不动。 这不是它更听话了,是你把边界说出来了——没说出来的边界,在它看来不存在。

三、改完当场验

「当场」的意思是:不等提交、不等别人 review、不等明天。 改完立刻跑那条一键验证。 为什么强调当场?因为失败的信息是有时效的。 改完马上去验,失败了你还能想起刚才动了什么; 隔一天再验,你只能重新读一遍 diff。 还有一层:验证要跑在「你信的那条命令」上。 不要临时拼一条 python -c "..." 来验——临时命令验过了,下次没人能重现。 把它写成文件(哪怕八行),才算验过。

四、留痕

留痕就是提交信息,两段:改了什么、为什么这么改加怎么验的。

段 写什么 给谁看
第一段 改了什么,一句话 扫 log 的人
第二段 为什么、怎么验的 半年后的接手人

为什么第二段值得写? 因为半年后你会看到一个「莫名其妙」的改动,然后花二十分钟搞清它为什么存在。 而当时写清楚只花一分钟。 顺手记一件事:验证的输出不用全贴进提交信息,写「通过 3 / 失败 0」就够。 贴一大段日志的结果是没人读。

五、动手 Demo:一次最小变更的四步:计划、改、验、留痕

同一个需求做两遍。 第一遍不出计划,直接改——它会不会顺手改别处?看 diff。 第二遍先出计划,再改——看改动量差多少。 两遍用的仓库、需求、验收完全一样,只有「有没有先出计划」这一个变量不同。

plan = [
    (u"会改", u"main.py 的 handle:空串与纯空格直接返回空串"),
    (u"不动", u"emo.py 的判定逻辑与 LEVEL 表"),
    (u"不动", u"README、tasks.py、config.py"),
    (u"怎么验", u"三条断言:空串、纯空格、正常消息"),
]
for a, b in plan:
    P(u"    %s  %s" % (pad(a, 8), b))

实跑输出:

--------------------------------------------------------------------
一次最小变更的四步:计划、改、验、留痕
--------------------------------------------------------------------


  ① 需求先写成两行:目标与验收
  --------------------------------------------------------------------
  目标:空消息不该回话
  验收:handle 拿到空串或纯空格时返回空串,且不调用 reply
  两行都有,才叫一个需求。只有第一行的时候,它做出来「返回一句默认话」也算合法。

  ② 不出计划,直接改
  --------------------------------------------------------------------
  README.md | 10 ----------
   emo.py    |  2 +-
   main.py   |  4 ++--
   3 files changed, 3 insertions(+), 13 deletions(-)
  合计:加 3 行、删 13 行、涉及 3 个文件
  需求只值一行,实际动了三个文件。多出来的两处是「顺手」:调了等级表、把 README 砍成一行。
  ! 顺手改是 Agent 最危险的习惯之一。
  它不觉得自己在越界,它觉得「顺便把这里也理顺了」——而你没让它这么做。

  ③ 出计划,再改
  --------------------------------------------------------------------
  计划:
    会改      main.py 的 handle:空串与纯空格直接返回空串
    不动      emo.py 的判定逻辑与 LEVEL 表
    不动      README、tasks.py、config.py
    怎么验    三条断言:空串、纯空格、正常消息
  这时仓库状态:干净,还没动手
  验证:通过 3 / 失败 0
  改动:1  1   main.py
  只动了 main.py 一行。没出计划的那一版动了三个文件,其中两处是顺手。
  ! 计划的用处不是让你看懂,是让「不动的地方」变成明文承诺。你写了「不动 emo.py」,它就不动;
  没写,它就会「顺便理顺」。

  ④ 留痕:提交信息写两段
  --------------------------------------------------------------------
  [ok ] (无输出)
  0bd7276 feat: 空消息不回话
   check_empty.py | 8 ++++++++
   main.py        | 2 +-
   2 files changed, 9 insertions(+), 1 deletion(-)
  ! 两段的意思:第一段说改了什么,第二段说为什么这么改、怎么验的。半年后接手的人读第二段就够了。

  ⑤ 四步各自拦住什么
  --------------------------------------------------------------------
| 步骤 | 拦住的问题 | 不做会怎样 |
|---|---|---|
| 目标加验收 | 「做完了」没有标准 | 它交什么你都得收 |
| 先出计划 | 顺手改别处 | diff 里混进两处无关改动 |
| 当场验 | 改完其实不通 | 提交之后才发现 |
| 留痕两段 | 半年后看不懂 | 得翻代码猜意图 |

第一遍:三个文件、加两行删十二行。 需求只值一行,多出来的两处是「顺手」——调了等级表,把 README 砍成一行。 第二遍:一个文件、加一行删一行。 1 1 main.py 这一行 numstat 就是「没越界」的证据。 注意第二遍的验证是在改完之后立刻跑的,三个断言全过,退出码零。 这一轮不省——省掉它,你只有一句「改好了」。 最后那个提交有两行 stat:check_empty.py 和 main.py。 验证脚本也跟着进仓库了,这是好事:下次同类需求,这条断言可以直接复用。

30 秒实验

  1. 拿一个你真要做的小需求,先写两行。 写完发现验收那行写不出来,就说明这个需求还没想清。
  2. 下一次让它干活,先要一份计划,只要四行。 看它写的「不动」那行跟你想的一样不一样。
  3. 翻一下你上一个提交的第二段。 如果只有一句话,试着补一句「怎么验的」。

常见误区

  1. 「先出计划太慢,直接改快。」 Demo 里不出计划那版多了两个文件的改动。 revert 那两处花的时间,比写四行计划长。
  2. 「顺手改的那些其实改得挺好。」 可能。但它没在你的需求里,也没在你的验收里。 「改得好」和「该改」是两件事。
  3. 「验过了就行,不用写下来。」 下次没人能重现你怎么验的。 写成八行文件,成本很低,收益是「可重复」。
自测三问(点开对答案) 1. 计划里最值钱的是哪一项?为什么? —— **「不动哪」这一项。** **因为 Agent 的默认行为是顺手改**——**没说出来的边界,在它看来不存在。** 2. 为什么验证要「当场」跑? —— **因为失败的信息有时效。** **当场跑,你还记得刚才动了什么;隔一天跑,你得重读 diff。** 3. 提交信息第二段写什么?给谁看? —— **写「为什么这么改」和「怎么验的」,给半年后的接手人看**——**那个人通常就是你自己。**

下一篇 5.4 收这一章:把这次闭环变成可复用的东西,顺便把成本拆开算一遍。

相关笔记