文章目录
- 一、引言
- 二、所有设计都绕不开的底层约束:Smart Zone 与 Dumb Zone
- 三、对齐阶段:用 Grill Me 把模糊需求逼出真相
-
- 1. 不要进 Plan Mode,要进 Interview Mode
- 2. 一次像样的 Grilling 长什么样
- 3. Grilling 是「人在回路」的硬约束
- 四、从对齐到目的地:PRD 该怎么用,又不该怎么用
- 五、垂直切片 vs 水平分层:Tracer Bullet 不是新概念,却是 AI 时代的救命稻草
-
- 1. 切片要满足的硬性条件
- 2. HITL 切片 vs AFK 切片
- 3. 看板用本地 Markdown,而不是某个 SaaS
- 六、夜班:Ralph 循环把 agent 变成自走的工程师
-
- 1. 实施提示词里写了什么
- 2. 实施沙箱:每个 agent 都关进 Docker
- 3. 实施用 Sonnet,评审用 Opus,而且必须在新会话里
- 4. Push 与 Pull:把规则放在它该在的地方
- 七、TDD 不是仪式感,是 AI 时代的质量杠杆
- 八、Deep Modules:agent 喜欢的代码长什么样
- 九、Sand Castle:把夜班从单线升级成多线
- 十、夜班结束之后:代码评审、QA、文档保鲜
-
- 1. AI 越能写,人类越要会审
- 2. QA 反哺看板,形成闭环
- 3. 文档腐烂(Doc Rot)是隐藏炸弹
- 十一、完整流水线总览与可复用模板
- 十二、未解决的张力:这套方法没说出来的限制
- 十三、给工程师的几句具体建议
- 十四、写在最后:工程基本功才是这一波的真护城河

把含糊的需求变成 agent 可执行的计划,把 agent 关进 Docker,把 TDD 当作质量杠杆——这是一份关于「如何让自主编码 agent 真正交付生产代码」的工程化指南。
一、引言
2026 年 4 月底,Matt Pocock 在 AI Engineer 大会上完成了一场 96 分钟的工作坊。两周时间,视频播放量越过六十五万次,GitHub 上的配套 skills 仓库突破九万颗星。这种热度的背后,并不是又一次「vibe coding」式的炫技,而是一位长期做 TypeScript 教育、做过 Vercel DevRel、又重新投入 AI 工程的工程师,把过去几十年软件工程的硬功夫,重新映射到 LLM 时代后给出的完整流水线。
这场分享真正值钱的地方有两点。
- 第一,它讨论的不是「该用哪个模型」「该买哪家 IDE 插件」,而是把 idea → PRD → issues → 看板 → Ralph 循环 → 人工 QA 这一整条链路全部摆到桌面上,每一段都给出可复现的提示词、技能脚本和组织约束。
- 第二,它对 LLM 的底层假设非常清醒:上下文越长,推理越蠢;每个会话都是失忆症患者;agent 天生喜欢写浅模块、横向分层、过度详尽——所有这些缺陷决定了工作流的形态,而不是反过来。
这篇文章会沿着 Matt Pocock 在工作坊中的主线一路推进:先解释「smart zone / dumb zone」这条最底层的约束,再依次展开对齐、规划、实施、评审四个阶段,最后落到代码架构、并行化、文档保鲜与团队协作这些容易被忽视的工程问题。读完之后,你应该可以拿着自己的 .claude 目录,直接动手改造一条属于自己的 AFK 流水线。
二、所有设计都绕不开的底层约束:Smart Zone 与 Dumb Zone
HumanLayer 的创始人 Dex Horthy 提出过一个特别朴素的概念:smart zone 和 dumb zone。Pocock 在工作坊中用一个足球联赛的比喻把它解释得很到位——每往 LLM 的上下文里塞一个 token,它和其他 token 之间产生的注意力关系不是线性增长,而是接近二次方的扩张。就像一支球队加入联赛,它要与所有现存球队两两比赛,赛程随队伍数量平方放大。token 越多,注意力网络越拥挤,推理质量越差。
这条规律决定了一个非常反直觉的结论:厂商宣传的「百万 token 上下文」并不等于「百万 token 可用上下文」。真正能维持高质量推理的窗口,大约在十万 token 上下;再往上,就是 Pocock 所说的「shipping more dumb zone」——卖给你更多的笨区。
| Smart Zone | 推理清晰、约束遵循好、输出稳定 | ~100K token,与厂商标称的最大窗口无关 |
| Dumb Zone | 出现「弱智决策」、丢失先前结论、风格漂移 | 超过 100K 后逐步劣化,即便理论窗口达到 1M+ |
这里需要做一个澄清:超长上下文窗口并不是没用,只是它的最佳场景是检索类任务——把五本《战争与和平》塞进去,问其中某个角色叫什么名字,模型完全胜任。但写代码不是检索,它要求模型在一段连续推理中维持复杂状态、做出权衡决策、对照规则与约束。这种工作,只有 smart zone 撑得住。
围绕这条约束,Pocock 还提出了另一个值得记下来的隐喻——Memento(记忆碎片)模型。每一次 /clear 都会把 agent 重置到系统提示词的初始状态,先前会话彻底清零。社区里流行的「compact」(把会话压缩成短摘要继续使用)在他看来是反模式:行为不再确定,问题难复现,远不如从干净状态重启来得清爽。他宁可丢掉部分中间结论,也要保住「行为可重复」这个工程属性。
所有后面要讲的工作流——为什么任务必须切薄、为什么 reviewer 必须在新会话里启动、为什么 Ralph 循环每一轮都要重新加载——都是这条 smart/dumb zone 约束在不同位置的具体应用。
三、对齐阶段:用 Grill Me 把模糊需求逼出真相
大多数 AI 编码失败都不是技术失败,而是沟通失败。需求看起来很清楚,但你和 agent 对「清楚」的理解是错位的。这一点在传统软件团队里就已经成立——Pragmatic Programmer 早就写下那句名言:「没人真正知道自己想要什么」。换成 LLM 之后,问题只会更尖锐,因为 agent 不会像人类同事那样在咖啡机旁追问你三遍。
1. 不要进 Plan Mode,要进 Interview Mode
Claude Code 自带的 plan mode 看似贴心:你给一句话,它生成一份漂亮的实施计划。但 Pocock 直白地评价过这种做法——它生成的是一种「热切但偏离」的方案,因为它根本没有质问过你。真正需要的不是计划,是「同频」。
所以他干脆写了一个极短的技能,放在仓库的 .claude/skills/grill-me/ 下,核心提示词只有两段话:
Interview me relentlessly about every aspect of this plan
until we reach a shared understanding.
Walk down each branch of the design tree,
resolving dependencies one by one.
For each question, provide your recommended answer.
Ask the questions one at a time.
短到不像一个产品,却几乎重塑了对齐流程。它逼 agent 做三件事:一次只问一个问题、遍历设计树的每一条分支、对每个问题先给出自己的推荐答案。最后那一点尤其关键——它把 agent 从「被动问询」变成「主动方案者」,你只需要在「同意/修正/反驳」三档之间做选择,而不是从零开始构造答案,沟通速度因此提升一个量级。
2. 一次像样的 Grilling 长什么样
以工作坊中演示的「为在线课程平台加一个游戏化系统」为例,grilling session 会从这种问题开始:
- 哪些行为获得积分?每种行为各多少?
- 历史数据要不要回填积分?如果回填,以哪天为切点?
- 连续学习(streak)算积分吗?中断后是衰减还是清零?
- 游戏化的 UI 放在仪表盘、课程页,还是单独一个 profile 面板?
- 是否需要排行榜?排行榜的可见范围是按课程、按团队,还是全局?
一次完整 grilling 通常会问到 40-80 道题,大概消耗 25K token 上下文——还稳稳落在 smart zone 内。Pocock 给的一个非常实用的小技巧是用语音听写代替键盘输入,因为这一阶段你需要的是流畅地讲清楚自己的判断,而不是反复推敲字句。
更深层的依据来自 Frederick Brooks 的 The Design of Design:一支团队真正共享的,从来不是某份文档,而是**「设计概念」(design concept)** 这件存在于多个大脑里的同一幅图。grilling 的产物不是会话日志、不是 markdown 文件,而是「你和这个 agent 现在处在同一张设计图上」这件不可见、却决定后续一切产出质量的东西。
3. Grilling 是「人在回路」的硬约束
这一阶段是整条流水线里唯一无法 AFK 的环节。它依赖产品判断、领域经验、对用户的直觉——这些都还不属于 LLM 的可靠能力圈。Pocock 在工作坊里反复强调:不要妄想把对齐也外包给 agent,否则你只是把一份糟糕的需求加速成了一份糟糕的代码。
四、从对齐到目的地:PRD 该怎么用,又不该怎么用
grilling 结束,接下来是 /to-prd 或 /write-a-prd——把刚才那场对话整合成一份产品需求文档。和很多团队对 PRD 的理解不同,Pocock 把它定位成一份**「目的地文档」(destination document)**:它不是用来反复阅读的合同,而是把 design concept 序列化下来,喂给下游的工具链。
一份典型 PRD 至少包括下面几块:
- 问题陈述(Problem statement):为什么要做这个东西。
- 解决方案概述(Solution description):整体形状。
- 用户故事(User stories):游戏化案例里大约写出 18 条。
- 实施决策(Implementation decisions):等级阈值、积分经济、回填策略等具体数字。
- 测试决策(Testing decisions):哪些行为必须有自动化覆盖。
- 不做的事(Out of scope):这一节往往比「要做的事」更值钱。
值得注意的是,Pocock 公开承认自己几乎不通读 PRD:「LLM 擅长总结,我已经通过 grilling 和它同频了,我没必要再花半小时核对它的复述。」这种态度听起来鲁莽,但背后的逻辑严密——他真正要验证的不是「PRD 文字是否准确」,而是「下一阶段的输出是否符合设计概念」。PRD 只是一个中转站,质量验收点在后面。
这里他特意把自己的流派和**「Specs-to-Code」(规格驱动编码)做了切割。所谓 specs-to-code,就是先写一份极其详尽的规格,把它丢给 agent,人类不再触碰代码——这条路线在社区里相当流行,但他亲身实验后给出的判断很直接:「it sucks」。原因不是规格不重要,而是代码本身才是战场**。脱离了对代码结构的持续感知,你最终拿到的只是一个无法演化、无法调试、无法重构的黑盒。
五、垂直切片 vs 水平分层:Tracer Bullet 不是新概念,却是 AI 时代的救命稻草
拿到 PRD,下一步是把它拆成可执行的 issue。这里又出现了一个非常典型的 agent 失败模式:它天生喜欢横向分层。如果不加约束,agent 会按这种顺序铺工作量——
这套做法对人类团队也常常出问题,在 agent 主导的世界里更是灾难:直到第三阶段你才有任何可演示、可验证的东西,前面所有产出都没有 end-to-end 反馈,任何一处认知偏差都要等到最后才被发现。
Pocock 重新祭出 Pragmatic Programmer 里的老术语——Tracer Bullet(曳光弹):与其打一发只在一层留下痕迹的子弹,不如打一发能穿透 schema、service、API、UI、test 所有层的曳光弹,看着它划出完整的弹道。每一颗曳光弹对应一个可独立 demo、可独立验证的功能切片。
#mermaid-svg-j536HUGTt4nWkphm{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-j536HUGTt4nWkphm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-j536HUGTt4nWkphm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-j536HUGTt4nWkphm .error-icon{fill:#552222;}#mermaid-svg-j536HUGTt4nWkphm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-j536HUGTt4nWkphm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-j536HUGTt4nWkphm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-j536HUGTt4nWkphm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-j536HUGTt4nWkphm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-j536HUGTt4nWkphm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-j536HUGTt4nWkphm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-j536HUGTt4nWkphm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-j536HUGTt4nWkphm .marker.cross{stroke:#333333;}#mermaid-svg-j536HUGTt4nWkphm svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-j536HUGTt4nWkphm p{margin:0;}#mermaid-svg-j536HUGTt4nWkphm .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-j536HUGTt4nWkphm .cluster-label text{fill:#333;}#mermaid-svg-j536HUGTt4nWkphm .cluster-label span{color:#333;}#mermaid-svg-j536HUGTt4nWkphm .cluster-label span p{background-color:transparent;}#mermaid-svg-j536HUGTt4nWkphm .label text,#mermaid-svg-j536HUGTt4nWkphm span{fill:#333;color:#333;}#mermaid-svg-j536HUGTt4nWkphm .node rect,#mermaid-svg-j536HUGTt4nWkphm .node circle,#mermaid-svg-j536HUGTt4nWkphm .node ellipse,#mermaid-svg-j536HUGTt4nWkphm .node polygon,#mermaid-svg-j536HUGTt4nWkphm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-j536HUGTt4nWkphm .rough-node .label text,#mermaid-svg-j536HUGTt4nWkphm .node .label text,#mermaid-svg-j536HUGTt4nWkphm .image-shape .label,#mermaid-svg-j536HUGTt4nWkphm .icon-shape .label{text-anchor:middle;}#mermaid-svg-j536HUGTt4nWkphm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-j536HUGTt4nWkphm .rough-node .label,#mermaid-svg-j536HUGTt4nWkphm .node .label,#mermaid-svg-j536HUGTt4nWkphm .image-shape .label,#mermaid-svg-j536HUGTt4nWkphm .icon-shape .label{text-align:center;}#mermaid-svg-j536HUGTt4nWkphm .node.clickable{cursor:pointer;}#mermaid-svg-j536HUGTt4nWkphm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-j536HUGTt4nWkphm .arrowheadPath{fill:#333333;}#mermaid-svg-j536HUGTt4nWkphm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-j536HUGTt4nWkphm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-j536HUGTt4nWkphm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-j536HUGTt4nWkphm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-j536HUGTt4nWkphm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-j536HUGTt4nWkphm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-j536HUGTt4nWkphm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-j536HUGTt4nWkphm .cluster text{fill:#333;}#mermaid-svg-j536HUGTt4nWkphm .cluster span{color:#333;}#mermaid-svg-j536HUGTt4nWkphm div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-j536HUGTt4nWkphm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-j536HUGTt4nWkphm rect.text{fill:none;stroke-width:0;}#mermaid-svg-j536HUGTt4nWkphm .icon-shape,#mermaid-svg-j536HUGTt4nWkphm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-j536HUGTt4nWkphm .icon-shape p,#mermaid-svg-j536HUGTt4nWkphm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-j536HUGTt4nWkphm .icon-shape .label rect,#mermaid-svg-j536HUGTt4nWkphm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-j536HUGTt4nWkphm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-j536HUGTt4nWkphm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-j536HUGTt4nWkphm :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
纵向切片(推荐)
Issue 1:完成一节课时奖励积分,并在仪表盘可见
Issue 2:连续学习 streak 跟踪
Issue 3:排行榜上线
横向分层(反模式)
阶段 1:全部 Schema
阶段 2:全部 API
阶段 3:全部前端
落到具体例子上,游戏化系统的第一颗曳光弹不是「建好 gamification 服务的 schema」,而是「完成一节课时给用户加积分,并在仪表盘上把积分显示出来」。这一颗子弹同时触及数据库、业务逻辑、API、前端、测试,但每一层都只切了最薄的一片。第一颗弹道一旦走完,后面所有切片都站在一个端到端可演示的基线之上。
1. 切片要满足的硬性条件
Pocock 在 to-issues 技能里把规则写得非常具体:
- 每个切片必须穿越所有集成层,而不是停留在某一层。
- 切片完成后必须可演示、可验证——不能是「这一段函数写完了但没人能看到效果」。
- 优先切得多而薄,而不是少而厚。哪怕拆出 12 个切片,只要每一个都能独立合并,就比 3 个大切片要好。
2. HITL 切片 vs AFK 切片
切片再分两种:
| HITL(Human in the Loop) | 必须人类介入 | 涉及架构决策、UI 视觉评审、不可逆数据迁移 |
| AFK(Away From Keyboard) | agent 可独立完成并合并 | 纯粹的功能实现、按既有架构的扩展、CRUD 类工作 |
默认优先选 AFK,只在确实必须人类介入的时候才标 HITL。这条原则会直接影响后面的并行度——AFK 切片越多,夜班调度器(Ralph + Sand Castle)能跑满的并发就越高。
3. 看板用本地 Markdown,而不是某个 SaaS
切完之后,所有 issue 会被组织成一个看板。Pocock 选择用本地 markdown 文件 + 阻塞关系字段来表达这个看板,而不是 Linear、Jira 或 GitHub Projects。原因有三:
- agent 读 markdown 比读各种 API 更便宜、更可靠。
- 阻塞关系直接写在文件里,Ralph 循环能轻松解析。
- 版本控制天然就是看板的审计日志——谁在什么时候动过哪个切片,git log 一目了然。
一份典型的本地看板大概长这样:
Issue 1: Schema + gamification service (AFK, blocked by: none)
Issue 2: Streak tracking (AFK, blocked by: 1)
Issue 3: 把积分/streak 接入课时与小测完成事件 (AFK, blocked by: 1, 2)
Issue 4: 历史数据回填积分 (AFK, blocked by: 1)
Issue 5: Polish & review (AFK, blocked by: 1, 2, 3, 4)
这种结构让 issue 4 和 issue 2/3 可以同时被两个 agent 各自挑走——并行化的基础在这一步就已经埋下。
六、夜班:Ralph 循环把 agent 变成自走的工程师
看板就位之后,真正的「不在场实施」开始了。Pocock 把这一阶段称作night shift——夜班,使用的核心机制是一个改良过的 Ralph 循环(名字来自《辛普森一家》里那个永远傻笑的 Ralph Wiggum,寓意是「在一个不确定的世界里持续地、笨笨地、不知疲倦地推进」)。
Ralph 循环最早由 Geoffrey Huntley 提出,它的核心哲学只有一句话——「Sit on the loop, not in it」(坐在循环之上,而不是循环之内)。开发者不再去手动驱动每一步,而是写一份提示词,让 agent 自己反复跑:读看板 → 挑下一条任务 → 实现 → 跑反馈 → 提交 → 回到看板。每一轮都从全新上下文开始,因此每一轮都稳稳在 smart zone 内。
1. 实施提示词里写了什么
Ralph 实施循环的提示词,经过工作坊精简后大约长这样:
1. 从看板里挑一条尚未完成、未被阻塞的 issue。
2. 优先级:critical bug fixes > developer infrastructure > tracer bullets > polishing/quick wins > refactors。
3. 用 TDD 实现:先写一个失败的测试,然后让它通过,再 refactor。
4. 在标记完成前必须跑过所有反馈回路(type check、tests、lint)。
5. 如果所有 AFK 任务都做完,输出「no more tasks」并退出。
这里需要单独强调的几点:
- 优先级顺序经过深思:线上 bug 永远第一,然后是让流水线本身更稳的「开发者基础设施」,再是新功能,接着才是小优化,最后才是 refactor。这条顺序避免了 agent 一开心就把整个仓库重写一遍的风险。
- 强制 TDD让 agent 在每条切片里都必须先写一个会失败的测试,然后再让它绿掉——这条规则一旦写进提示词,几乎能杜绝「测试是凑出来的」这种最常见的偷懒模式。
- 强制跑完所有反馈循环:类型检查、单测、lint 都必须绿,否则不能 commit。这是 agent 自检的硬底线。
- 退出条件清晰:循环不是无限跑,而是看板见底就停。这一点对 Sand Castle 调度器至关重要。
2. 实施沙箱:每个 agent 都关进 Docker
夜班最容易翻车的地方是 agent 误改文件系统、误调外部 API、误花一张 token 巨账单。Pocock 的做法是把每个实施 agent 都丢进一个 Docker 容器 + git worktree 的隔离环境里:每条切片对应一个独立分支,容器是即抛即用的,出问题最多损失这一支分支的工作量。
这套隔离策略和 smart/dumb zone 模型形成了一个意外契合——既然 agent 在某一轮可能犯傻,我就要确保它的犯傻不会越过沙箱的边界。容器化是工程上廉价、有效、可复制的隔离手段。
3. 实施用 Sonnet,评审用 Opus,而且必须在新会话里
模型选择上,Pocock 给出了一个非常实用的分工——
| Implementer | Claude Sonnet | 速度快、成本低,适合大量重复编码 |
| Reviewer | Claude Opus | 推理深度高,适合在新会话里冷启动评审 |
这里有一条容易被忽视、但极其关键的规则:reviewer 永远在新会话里启动,而不是和 implementer 共享上下文。逻辑很简单——如果 reviewer 看着 implementer 在同一份长上下文里产出的代码,它就已经在 dumb zone 里了,它会比被评审的对象更蠢。只有强制清空上下文,让 reviewer 以纯净的 smart zone 状态重新打开仓库,评审才有意义。
4. Push 与 Pull:把规则放在它该在的地方
工作坊里有一段对话很有启发:同样一份「编码规范」,该塞给 implementer 还是塞给 reviewer?Pocock 的判断是——
- Implementer 用 pull:它在需要的时候自己去拉规范,避免上下文里塞满未用到的规则。
- Reviewer 用 push:把规范主动推到 reviewer 的会话里,确保它一开始就照规则审。
用他自己的话讲:「I would push the coding standards in the implement, I would allow it to pull.」——只在评审端用 push,实现端用 pull。这条原则同样源自 smart zone 的容量管理:能省的 token 一定要省。
七、TDD 不是仪式感,是 AI 时代的质量杠杆
传统团队对 TDD 的接受度一直不高——很多人觉得它仪式感太重、节奏太慢。但在 agent 主导的世界里,TDD 突然变成了一根非常硬的杠杆。它解决了几个让 AI 编码一直翻车的老问题:
| agent 写出来的测试什么都没测 | 每个测试都必须先于实现存在并失败,空测试在 red 阶段就会暴露 |
| agent 写的测试碰巧通过(实质作弊) | 当测试在「待实现代码」之上落地时,作弊难度显著上升 |
| 代码库缺少测试覆盖 | TDD 本身就是顺带积累覆盖率的过程 |
| agent 在前端代码上「看不见」自己的产出 | 测试提供一种无需人类目视检查的反馈回路 |
Pocock 在演示里跑完游戏化系统之后,测试套件累积到 284 个。他对代码评审的态度也因此发生了变化——第一步不是看实现,而是先看测试:先确认这些测试在「测有意义的事情」,再去检查实现是否合理。这种顺序背后的假设很直接:测试是 agent 自己定义的合同,合同本身先要靠谱,合同的执行才有意义。
值得单独点出来的是前端测试这个老大难。模型「看不见」UI,直接让它写完前端再去测,基本是盲飞。Pocock 给出的折衷方案是原型法(prototype 技能)——
给我做三个可在同一条 throwaway route 下切换的 UI 原型,
我点完之后告诉你选哪个,你再把这个版本接到主流程里。
这把「视觉判断」这件 agent 不擅长的事情交还给人类,但把「构造可选方案」这件 agent 擅长的事情留给 agent。两边都做了自己最有比较优势的工作。
八、Deep Modules:agent 喜欢的代码长什么样
这是整场分享里最容易被低估、但回报最高的一段。agent 输出的质量上限,本质上由你的代码结构决定。
Pocock 直接引用了 John Ousterhout 的《A Philosophy of Software Design》中那个老结论——好模块是「深」的,坏模块是「浅」的。
| 模块尺寸 | 大量极小文件 | 数量更少、单个更大 |
| 接口 | 暴露众多导出 | 接口窄、签名小 |
| 内部复杂度 | 几乎为零,逻辑被切得太碎 | 内部承担显著的业务复杂度 |
| 测试边界 | 难定——到底测哪一层? | 易定——围着模块边界包一圈测试就行 |
| Agent 可导航性 | 差——必须沿着依赖图反复跳转 | 好——理解了模块形状就够用 |
这里有一个非常微妙的现象:agent 如果不加约束,天然会写出浅模块——它倾向于一文件一函数,每个文件都极薄,因为它在生成时只关心眼前那个具体的指令,不会自发地考虑「这个文件和旁边几个文件其实应该合并」。
这种倾向有两个后果:
应对策略也很直接——在提示词、issue 描述、ADR、Skill 文件里反复明示「优先做深模块」,并定期跑 improve-codebase-architecture 这类技能去识别耦合度高的浅模块簇,把它们合并成单个深模块,在模块边界外面包一圈端到端测试。
Pocock 在自己那套 video editor 项目里就这么做过:把前端到后端的一整条管线压成一个深模块,外层端到端测试覆盖。结果是——agent 改动这块时,既能看清整体形状,又不需要把所有依赖文件都拉进上下文,smart zone 利用率直接上去。
这套方法还有一个对人类的红利:开发者只需要知道模块的「外形与接口」,而不需要随时记住内部实现——把模块当作灰盒看待。代码库再大,大脑的工作负载也能被压住。
九、Sand Castle:把夜班从单线升级成多线
单 agent 的 Ralph 循环已经能跑通完整流水线,但产线再往上走一档,就需要并行。Pocock 为此写了一个叫 Sand Castle 的 TypeScript 库,负责调度多个 AFK agent 同时干活。
Sand Castle 的内部分工是这样的:
#mermaid-svg-o6XQDi6iwR9Qch1L{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-o6XQDi6iwR9Qch1L .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-o6XQDi6iwR9Qch1L .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-o6XQDi6iwR9Qch1L .error-icon{fill:#552222;}#mermaid-svg-o6XQDi6iwR9Qch1L .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-o6XQDi6iwR9Qch1L .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-o6XQDi6iwR9Qch1L .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-o6XQDi6iwR9Qch1L .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-o6XQDi6iwR9Qch1L .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-o6XQDi6iwR9Qch1L .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-o6XQDi6iwR9Qch1L .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-o6XQDi6iwR9Qch1L .marker{fill:#333333;stroke:#333333;}#mermaid-svg-o6XQDi6iwR9Qch1L .marker.cross{stroke:#333333;}#mermaid-svg-o6XQDi6iwR9Qch1L svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-o6XQDi6iwR9Qch1L p{margin:0;}#mermaid-svg-o6XQDi6iwR9Qch1L .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-o6XQDi6iwR9Qch1L .cluster-label text{fill:#333;}#mermaid-svg-o6XQDi6iwR9Qch1L .cluster-label span{color:#333;}#mermaid-svg-o6XQDi6iwR9Qch1L .cluster-label span p{background-color:transparent;}#mermaid-svg-o6XQDi6iwR9Qch1L .label text,#mermaid-svg-o6XQDi6iwR9Qch1L span{fill:#333;color:#333;}#mermaid-svg-o6XQDi6iwR9Qch1L .node rect,#mermaid-svg-o6XQDi6iwR9Qch1L .node circle,#mermaid-svg-o6XQDi6iwR9Qch1L .node ellipse,#mermaid-svg-o6XQDi6iwR9Qch1L .node polygon,#mermaid-svg-o6XQDi6iwR9Qch1L .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-o6XQDi6iwR9Qch1L .rough-node .label text,#mermaid-svg-o6XQDi6iwR9Qch1L .node .label text,#mermaid-svg-o6XQDi6iwR9Qch1L .image-shape .label,#mermaid-svg-o6XQDi6iwR9Qch1L .icon-shape .label{text-anchor:middle;}#mermaid-svg-o6XQDi6iwR9Qch1L .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-o6XQDi6iwR9Qch1L .rough-node .label,#mermaid-svg-o6XQDi6iwR9Qch1L .node .label,#mermaid-svg-o6XQDi6iwR9Qch1L .image-shape .label,#mermaid-svg-o6XQDi6iwR9Qch1L .icon-shape .label{text-align:center;}#mermaid-svg-o6XQDi6iwR9Qch1L .node.clickable{cursor:pointer;}#mermaid-svg-o6XQDi6iwR9Qch1L .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-o6XQDi6iwR9Qch1L .arrowheadPath{fill:#333333;}#mermaid-svg-o6XQDi6iwR9Qch1L .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-o6XQDi6iwR9Qch1L .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-o6XQDi6iwR9Qch1L .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o6XQDi6iwR9Qch1L .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-o6XQDi6iwR9Qch1L .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o6XQDi6iwR9Qch1L .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-o6XQDi6iwR9Qch1L .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-o6XQDi6iwR9Qch1L .cluster text{fill:#333;}#mermaid-svg-o6XQDi6iwR9Qch1L .cluster span{color:#333;}#mermaid-svg-o6XQDi6iwR9Qch1L div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-o6XQDi6iwR9Qch1L .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-o6XQDi6iwR9Qch1L rect.text{fill:none;stroke-width:0;}#mermaid-svg-o6XQDi6iwR9Qch1L .icon-shape,#mermaid-svg-o6XQDi6iwR9Qch1L .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o6XQDi6iwR9Qch1L .icon-shape p,#mermaid-svg-o6XQDi6iwR9Qch1L .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-o6XQDi6iwR9Qch1L .icon-shape .label rect,#mermaid-svg-o6XQDi6iwR9Qch1L .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o6XQDi6iwR9Qch1L .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-o6XQDi6iwR9Qch1L .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-o6XQDi6iwR9Qch1L :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Planner Agent读全量看板,挑可并行切片
Implementer #1Sonnet + Docker
Implementer #2Sonnet + Docker
Implementer #3Sonnet + Docker
ReviewerOpus + 新会话
ReviewerOpus + 新会话
ReviewerOpus + 新会话
Merger Agent合分支、解冲突
每个角色的职责清晰可分:
- Planner:读完整个看板,根据阻塞关系算出当前可并行启动哪些切片。
- Implementer:每个都跑在自己的 Docker 容器和 git worktree 上,独立分支,互不打扰。
- Reviewer:每个 reviewer 在全新会话里启动,审查对应 implementer 的产出。
- Merger:负责把通过评审的分支合回主干,顺手处理类型冲突、测试冲突、lint 冲突——这些「合并阶段才会暴露」的小麻烦,过去靠人类工程师在 PR 上修,现在交给 merger agent 去搞。
这套结构带来三个工程红利:
Pocock 把它公开成开源库 Sandcastle,核心理念依旧是:让 agent 干 agent 擅长的事(写代码、跑测试、解机械冲突),让人类干人类擅长的事(对齐、设计、视觉判断、最终决策)。
十、夜班结束之后:代码评审、QA、文档保鲜
这套流水线最后,还有几个被很多介绍文章忽略,但 Pocock 在工作坊里非常坦白地展开的问题。
1. AI 越能写,人类越要会审
工作坊现场,他抛出过两个让全场举手的问题:
觉得自己用了 AI 之后比以前更累的,请举手。 觉得自己对自家代码库的熟悉程度比以前下降的,请举手。
两次几乎全场举手。这是一个让人警醒的信号:agent 把「编码」这件事的边际成本压低之后,代码评审反而成为新的瓶颈。「小而独立的 PR」这条行业惯例,撞上「一个 Ralph 循环连续合并 4 个 issue」的现实,产生了非常具体的痛点——评审者打开 PR,看到的不是一次干净的提交,而是 agent 一晚上的全部产出。
Pocock 没有给出干净的解决方案,他自己的话是:「we just need to be ready to do more code review」。但他在工作流里加了一个缓冲:自动 reviewer(在新会话里运行)先把一遍,把明显的烂代码、违规、未覆盖路径标出来,然后人类才介入。自动评审不能替代人审,但能把人审的负担压到「值得人审的部分」。
2. QA 反哺看板,形成闭环
QA 阶段发现的 bug 不会直接修——它们会被回写到看板里,变成新的 issue,等待下一轮 Ralph 循环挑走。整条系统因此变成一个永不收敛的回路:plan → implement → QA → re-plan。这种结构表面上反直觉(为什么 bug 不立刻修?),但和「smart zone + 干净会话」的整体哲学完全一致——临时跳出循环去补丁,会污染当前会话;把它变成一条标准 issue,下一轮干净上下文里再处理,更稳。
3. 文档腐烂(Doc Rot)是隐藏炸弹
PRD 和实施计划在项目里要不要保留?这是工作坊里一个引发了较多讨论的细节。Pocock 的立场偏激进:实施完成后,planning 文档应当被丢弃。理由是文件名、代码结构、需求口径都会随时间漂移,如果未来某个 agent 翻到一份过时 PRD 并把它当成权威,它会基于错误事实生成新代码。
他的折衷方案是把 PRD 落地为GitHub issue 并标记为 closed:agent 依然能访问历史信息,但 closed 状态像一个明显的视觉标记,提醒它「这是已完成、可能过时的设计」。这套做法不一定适合所有团队,但它指出了一个非常实在的风险——长期保留的过时文档,会反过来污染 agent 行为,值得每个团队都认真对待。
十一、完整流水线总览与可复用模板
把前面所有阶段串起来,整套工作流大约长这样:
#mermaid-svg-OfIsc1o1zD6F9J3B{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OfIsc1o1zD6F9J3B .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OfIsc1o1zD6F9J3B .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OfIsc1o1zD6F9J3B .error-icon{fill:#552222;}#mermaid-svg-OfIsc1o1zD6F9J3B .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OfIsc1o1zD6F9J3B .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OfIsc1o1zD6F9J3B .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OfIsc1o1zD6F9J3B .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OfIsc1o1zD6F9J3B .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OfIsc1o1zD6F9J3B .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OfIsc1o1zD6F9J3B .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OfIsc1o1zD6F9J3B .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OfIsc1o1zD6F9J3B .marker.cross{stroke:#333333;}#mermaid-svg-OfIsc1o1zD6F9J3B svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OfIsc1o1zD6F9J3B p{margin:0;}#mermaid-svg-OfIsc1o1zD6F9J3B .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-OfIsc1o1zD6F9J3B .cluster-label text{fill:#333;}#mermaid-svg-OfIsc1o1zD6F9J3B .cluster-label span{color:#333;}#mermaid-svg-OfIsc1o1zD6F9J3B .cluster-label span p{background-color:transparent;}#mermaid-svg-OfIsc1o1zD6F9J3B .label text,#mermaid-svg-OfIsc1o1zD6F9J3B span{fill:#333;color:#333;}#mermaid-svg-OfIsc1o1zD6F9J3B .node rect,#mermaid-svg-OfIsc1o1zD6F9J3B .node circle,#mermaid-svg-OfIsc1o1zD6F9J3B .node ellipse,#mermaid-svg-OfIsc1o1zD6F9J3B .node polygon,#mermaid-svg-OfIsc1o1zD6F9J3B .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OfIsc1o1zD6F9J3B .rough-node .label text,#mermaid-svg-OfIsc1o1zD6F9J3B .node .label text,#mermaid-svg-OfIsc1o1zD6F9J3B .image-shape .label,#mermaid-svg-OfIsc1o1zD6F9J3B .icon-shape .label{text-anchor:middle;}#mermaid-svg-OfIsc1o1zD6F9J3B .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-OfIsc1o1zD6F9J3B .rough-node .label,#mermaid-svg-OfIsc1o1zD6F9J3B .node .label,#mermaid-svg-OfIsc1o1zD6F9J3B .image-shape .label,#mermaid-svg-OfIsc1o1zD6F9J3B .icon-shape .label{text-align:center;}#mermaid-svg-OfIsc1o1zD6F9J3B .node.clickable{cursor:pointer;}#mermaid-svg-OfIsc1o1zD6F9J3B .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-OfIsc1o1zD6F9J3B .arrowheadPath{fill:#333333;}#mermaid-svg-OfIsc1o1zD6F9J3B .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OfIsc1o1zD6F9J3B .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OfIsc1o1zD6F9J3B .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OfIsc1o1zD6F9J3B .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-OfIsc1o1zD6F9J3B .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OfIsc1o1zD6F9J3B .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-OfIsc1o1zD6F9J3B .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OfIsc1o1zD6F9J3B .cluster text{fill:#333;}#mermaid-svg-OfIsc1o1zD6F9J3B .cluster span{color:#333;}#mermaid-svg-OfIsc1o1zD6F9J3B div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OfIsc1o1zD6F9J3B .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-OfIsc1o1zD6F9J3B rect.text{fill:none;stroke-width:0;}#mermaid-svg-OfIsc1o1zD6F9J3B .icon-shape,#mermaid-svg-OfIsc1o1zD6F9J3B .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OfIsc1o1zD6F9J3B .icon-shape p,#mermaid-svg-OfIsc1o1zD6F9J3B .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-OfIsc1o1zD6F9J3B .icon-shape .label rect,#mermaid-svg-OfIsc1o1zD6F9J3B .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OfIsc1o1zD6F9J3B .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-OfIsc1o1zD6F9J3B .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-OfIsc1o1zD6F9J3B :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
新 issue
原始想法
Grill Me 会话(必须人在回路)
PRD(目的地文档)
切分 Tracer Bullet本地 Markdown 看板
Ralph + Sand CastleAFK 实施 + 自动评审
人类 QA & 代码评审
如果你想直接套用,可以按下面这份「最小可行配置」起步:
这个顺序的好处是风险可控:你先在单线流水线上跑通自己的项目,等沙箱、看板、评审都顺手了,再去开多 agent 并发。一上来就堆并发,大概率会在调度与冲突管理上栽跟头。
十二、未解决的张力:这套方法没说出来的限制
这场分享最难得的一点,是 Pocock 没有把它讲成「我已经把一切都搞定」的胜利演讲,而是诚实地把目前还没解决的几个张力摆出来。
- 代码评审体量与小 PR 文化的冲突:夜班一晚跑出来的合并集,常常和「小步快走、易评审」的工程文化撞车。这是组织流程问题,不是模型能力问题,目前没有干净答案。
- 前端测试的盲点:模型看不见 UI 这件事,在视觉密集型场景里依然致命。原型法是缓解,不是治本。
- Specs-to-Code 路线之争:是否完全脱离代码、只在规格层面工作,业内分歧很大。Pocock 押注「代码是战场」,但他承认对面阵营有自己的逻辑。
- 团队场景的适配:目前的工作流是面向单人或小组的。多个产品负责人、多个领域专家、并存的 agile 流程,如何接入这一套,他没有给出系统答案。
- 文档保鲜与可追溯之间的取舍:扔掉 PRD 避免 doc rot,但也丢失了一部分历史追溯。哪种更值,要看团队的合规与审计需求。
- 角色变化的不确定性:被问到「产品经理这个岗位在 AI-augmented 开发里会怎么演化」时,他直接拒绝预测——「I’m not a pundit」。这种克制,在一个普遍喜欢预言未来的圈子里,反而更可信。
十三、给工程师的几句具体建议
如果只想从这场工作坊里带走最具操作性的几条,大致是这些:
- 把上下文当成稀缺资源管理。永远在 smart zone 内工作,该清空就清空,不要迷信百万级窗口。
- 任何一次新功能,先 grilling 再 plan。提示词只要那两句,但你需要预算 30-60 分钟,认真把设计树走完。
- PRD 不必精读,但必须存在。它的价值是给下游工具链,而不是给你自己。
- 切片永远纵向,优先 AFK。横向分层是 agent 默认的偷懒模式,要在提示词层面主动反向。
- TDD 是 agent 时代的最优策略,而不是历史包袱。它把「agent 自检」从口号变成机械的红绿循环。
- 代码架构主动做深。在评审、PRD、ADR、Skill 里反复提示「优先深模块」,定期跑架构改善。
- Reviewer 永远在新会话。这是一条不容妥协的规则,违反之后整条流水线的质量保证都会塌。
- 沙箱化你的 agent。Docker + git worktree 是最便宜的隔离方式,出问题止损在分支级别。
- 承认评审会变多。不要假装 agent 会让你工作更少;它让你的工作重心向上挪了一档。
- planning 文档要么扔,要么打 closed 标记。不要让明天的 agent 被昨天的过时文档带歪。
十四、写在最后:工程基本功才是这一波的真护城河
回到最开始那句话——这场分享真正的价值,不是它告诉你「该用哪个新工具」,而是它把过去三十年软件工程沉淀下来的硬功夫重新组合了一遍:Pragmatic Programmer 的曳光弹、Refactoring 的小步前进、Domain-Driven Design 的共享语言、A Philosophy of Software Design 的深模块、Brooks 的 design concept、TDD 的红绿循环。这些东西在 LLM 出现之前就已经是好实践,在 LLM 出现之后,它们成为让 agent 真正能跑起来的前提条件。
那些断言「软件工程过时了」的声音,某种意义上恰恰最危险:它们鼓励你用 agent 在浅模块、横向分层、无测试覆盖的环境里裸奔——结果往往是一个跑不动的 demo 加一份焦灼的 oncall 排班表。Pocock 给出的另一条路线相反:把基本功练扎实,把流水线做规范,然后让 agent 在这条干净的轨道上把生产力释放出来。
这条路线不性感、不戏剧化,但它经得起两点检验:第一,它真的把项目交付到了生产环境;第二,它没有把今天的速度建立在明天的技术债之上。对于真正要长期做工程的人来说,这才是值得押注的方向。
参考来源:Matt Pocock 在 AI Engineer 大会的分享《Full Walkthrough: Workflow for AI Coding》,以及其开源仓库 mattpocock/skills 中的相关技能定义与文档。


![[特殊字符]DeepSeek‑Harness(DSH)小白保姆教程-171主机测评](https://www.171host.com/wp-content/uploads/2026/08/20260816085112-6a817a009aabf-220x150.png)
