Agentic Engineering 基础:45 分钟速成课
8 个概念,覆盖真实使用中的 80%
前置要求:Agentic Coding 速成课。 那一页教的是 tools:Claude Code、OpenCode、plan mode、
CLAUDE.md、skills、MCP、hooks。本页教的是你使用这些工具时需要的 discipline。两者互补:有工具但没有纪律,会产出 vibe code;有纪律但没有工具,只是理论。
"Code is not cheap. Bad code is the most expensive it has ever been." Matt Pocock
"Vibe coding is about raising the floor for everyone in terms of what they can do in software. Agentic engineering is about preserving the quality bar of what existed before in professional software." Andrej Karpathy
行业里有一种叙事正在流行:AI 是新的范式,所以旧的工程规则不再适用;specifications 是新的 source code;model 是 compiler;只要程序表现正确,diff 不重要。这个说法很安慰人,也很错。
本章的 thesis,也是本书每一个 Digital FTE 的主线,正好相反。AI 时代的软件基本功,比过去更重要。 原因不是情怀,而是机制。你设计的 interface,就是 agent 学习的 interface;你选择的 names,就是 agent 会复用的 names;你画出的 boundaries,就是 agent 会尊重的 boundaries。同一个 agent,在干净、测试良好的 codebase 中,产出的代码质量会比在混乱 codebase 中高出好几档。Architecture 不再只是代码的属性;它也是 agent 的输入。坏代码会产出坏 agents;好代码会让 agents 看起来惊人地 competent。
本章教的 workflow,就是让这种 competence 可重复:一条七阶段 pipeline(idea → grilling → PRD → issues → implementation → review → QA),通过小而可组合的 Skills 实现,并且在 Claude Code 和 OpenCode 中以相同方式运行。写给其中一个的 Skills、specs 和 architectural patterns,可以原封不动落到另一个里。方法是常量,工具是变量。
读完本章,你应该能够:
- 判断自己位于 vibe coding ↔ agentic engineering 光谱的哪个位置,并为工作风险选择相应纪律。
- 诊断 AI coding 的六种失败模式,并知道每一种对应的修复方式。
- 在 Claude Code 或 OpenCode 中跑完整的 grill → PRD → vertical-slice issues → AFK implementation 循环。
- 写一个只在需要时加载、而不是每一轮都消耗 tokens 的
SKILL.md。 - 把 codebase 从 shallow modules 重构为 deep modules,让 AI feedback loops 真正起作用。
- 熟练使用工作词汇:smart zone、dumb zone、clearing、compaction、handoff、AFK、tracer bullet、design concept、grilling、jagged intelligence。
Pipeline 总览
先看操作形状,再看理论。七个阶段,五个 Skills,一条流向。后面的每节,要么解释表中的一行,要么用代码展示它。
| # | Stage | 发生什么 | Input → Output | Skill | Section |
|---|---|---|---|---|---|
| 1 | Idea → aligned concept | agent 用苏格拉底式访谈追问,直到设计被共同理解 | wish → design concept | grill-me | §6.1 |
| 2 | Concept → destination | 把对话综合成 PRD | conversation → PRD | to-prd | §6.2 |
| 3 | PRD → backlog | 把 PRD 拆成 vertical-slice tickets | PRD → tracer-bullet issues | to-issues | §6.3 |
| 4 | Issue → slice | 对一个 slice 做 test-first 实现 | issue → reviewable diff | tdd | §6.4 |
| 5 | Slices → drained backlog | AFK loop 在 sandbox 中清空队列 | issues → PRs | orchestrator | §6.5 |
| 6 | Diff → decision | 人读 diff,跑 QA | PR → merge 或 new issue | taste,不自动化 | §6.6 |
| 7 | Codebase health | 找 shallow modules,提出 deepenings | codebase → RFC | improve-codebase-architecture | §7.4 |
阶段 1–3 是 day shift:human in the loop。阶段 4–5 是 night shift:agent 在 sandbox 中 AFK 运行。阶段 6 回到 day shift。阶段 7 每周跑一次,并把新 issues 喂回阶段 3。整条 pipeline 在 Claude Code 和 OpenCode 中相同。
刚接触编程?先读这个。
本章默认你写过代码,用过
git,运行过 test suite,并打开过 pull request。如果这些熟悉,跳过这个框继续。如果还不熟,本章仍然可以作为概念地图阅读。你会得到:workflow 形状、理解 AI-coding 对话所需的词汇、常见失败的诊断目录,以及让 agents 在真实 codebase 中表现良好的 architecture philosophy。你暂时还不能跑全部示例代码;那需要先补几周编程基础。诚实路径是:先读一遍拿到地图,学习 prerequisites,再回来跟着代码走。
1. 从 Vibe Coding 到 Agentic Engineering
两件事连续发生。第一件让第二件成为必要。
1.1 Software 3.0:新的计算范式
Andrej Karpathy 把 software 分成三个时代。Software 1.0 是多数工程师职业生涯中写的东西:显式代码,由 CPU 执行,处理结构化数据。Software 2.0 是 learned weights 的时代:通过整理数据集和训练 neural networks 来编程,而不是手写 branching logic。Software 3.0 是我们现在所在的时代:通过 prompting 编程,LLM 像一种可编程计算机,你放进 context window 的内容,就是你撬动它的杠杆。
时代之间变化的是 artifact。1.0 的 artifact 是 executable code。3.0 的 artifact 越来越多地是写给 agent 的一段文本。OpenCode 发布 installer 时,发出的不是 bash script,而是一段自然语言,供用户粘贴到 coding agent 中。agent 会阅读环境、在循环中 debugging,并完成可工作的安装。installer 不再是传统程序,而是 Skill。
这会泛化。写给人的文档(「去这个 URL,点击 Settings……」)会变成写给 agents 的文档(「把这段交给你的 coding agent,它会配置项目」)。UI 不再是唯一 interface;agent 成为你构建和依赖的每个系统的第二类用户。Agent-native infrastructure(优先为 agents 设计的 APIs、docs、tooling 和 deployment pipelines)是下一层平台。
本章讨论如何在 Software 3.0 中操作。Skills(§5)是 3.0 artifacts。PRDs 和 tickets(§6)是 3.0 artifacts。AGENTS.md 和 CONTEXT.md(§3,Failure 2)也是 3.0 artifacts。代码本身越来越多地处在这些 artifact 的下游。
1.2 Vibe Coding 提高地板;Agentic Engineering 保住天花板
Karpathy 还提出了 vibe coding:让 agent 写代码,不读 diff,只按程序是否运行来判断。vibe coding 真实、有用,并且会长期存在。它让非程序员可以在一个周末交付有用工具;它也是 Karpathy 描述自己 side project MenuGen 的方式。vibe coding 提高了个人能构建的软件下限,这个下限提升有很大的经济后果,并且大体是好事。
但它之上正在出现第二种纪律:agentic engineering。vibe coding 提高地板,agentic engineering 保住天花板:专业软件的质量标准。agent 做大部分 typing;你仍然负责 security、data integrity、maintainability、contracts 和 user experience。vibe coding 本身不会引入漏洞;不谨慎使用它的 engineer 会。打字的人变了,不代表标准可以下降。
| Vibe coding | Agentic engineering | |
|---|---|---|
| Goal | 提高可构建内容的下限 | 保住专业软件的上限 |
| Reviewer | 经常没有;看能不能跑 | 人读 diff;上面叠加 automated review |
| Architecture | agent 输出什么就是什么 | engineer 设计,agent 实现 |
| Tests | 可选 | 不可谈判;TDD 在关键路径上 |
| Codebase health | 接受漂移 | 定期 refactor;加深 modules |
| Failure handling | 「我这里能跑」 | 可复现、可测试、可解释 |
| Right setting | side projects、prototypes、throwaway tools | production systems、regulated work、任何 multi-user 系统 |
本章原则和 workflows 是 agentic engineering 的纪律,不是 vibe coding 的自由。当你构建一个组织会信任它处理 payroll、customer escalations 或 financial reconciliation 的 Digital FTE 时,vibe coding 就是 malpractice。你需要地板和天花板:吞吐量提高,质量标准保留。
2. 每个 Coding Agent 继承的三个约束
coding agent 不是魔法工程师;它是一个 model,被包在 harness 里。这个组合有三个属性,会塑造所有 workflow:有限 attention budget、没有 persistent state、以及 jagged capability profile。
2.1 Smart Zone 和 Dumb Zone
当 model 预测下一个 token 时,它会权衡 context window 中已经存在的其他 tokens。每个 token 都有有限的 attention budget。窗口越大,竞争关系越多。
后果很硬。session 早期,agent 处在 smart zone:清醒、聚焦、recall 好。随着 session 变长,每个 token 的信号被越来越多竞争者稀释。agent 漂入 dumb zone:忘掉你一开始粘贴的 schema,发明 type file 中不存在的字段,把两个同名变量绑定错,甚至和自己前面的 reasoning 矛盾。同一个 model,同样参数;只是上下文太大。
当前 frontier models 在 coding work 上的实践上限,通常远低于营销里写的 200k 或 1M window。经验报告大致把 100k tokens 看成漂移开始显现的水线。具体数字没那么重要,形状才重要:超过某个比例后,你得到的不是更多能力,而是更多花钱购买的 dumb zone。大窗口有利于长文档 retrieval,但不会同等倍数延长 code reasoning horizon。
Token usage: 0k ────────── 50k ────── 100k ────── 200k ────── 1M
Quality: ████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░
↑ ↑
smart zone dumb zone begins
真实 session 中,转折大致是这样:
turn 5 → you paste users.ts schema (8 fields: id, email, name, ...)
turn 9 → agent uses User.email correctly
turn 23 → agent builds a route, refers to User.id, all good
turn 47 → context is now ~80k tokens
turn 52 → agent writes user.emailAddress ← field doesn't exist
turn 55 → agent invents user.preferences ← also not in the schema
⇒ smart zone exited.
⇒ /clear, re-paste schema in a fresh session, continue.
修复方法不是硬撑。把每个工作单元切到能放进 smart zone 的大小;一个单元完成后,丢掉 session,开新的。
2.2 Memento Problem
Models 是 stateless 的。session 内连续性,是 harness 每轮把 context 重新喂给 model;跨 session 的连续性,来自 memory system 写到磁盘并在下一次加载。
这是 feature。agent 最可靠的一点是:clearing context 会把它带回已知良好状态。刚刚 40 轮漂进 dumb zone 的 agent,在 /clear 之后 5 秒钟,会用全新的 attention budget 阅读你的新 prompt,并产出优秀工作。
session 膨胀后有两种恢复方式:
- Clearing:结束 session,开新 session。彻底 reset。
- Compaction:总结上个 session,用 summary seed 新 session。有损。
大多数 developers 先想 compaction,因为它感觉没那么破坏性。要警惕这个直觉:compaction 会保存一部分把你带入麻烦的 dumb-zone reasoning。clearing 加上小而明确的 handoff artifact(PRD、ticket、AGENTS.md),能让下一个 session 每次从同一状态出发。可预测的开始,产出可预测的结束。
工作原则。 把 agent 当成 Memento 主角来对待。围绕它会忘记这件事来规划。让所有重要事实存在于 environment 中(
AGENTS.md、CONTEXT.md、Skill、ticket),不要存在 chat history 中。
2.3 Jagged Intelligence
前两个约束是 agent 能注意多少。第三个约束是它擅长什么,而且最容易让 engineers 措手不及。
LLMs 是 jagged 的。它们不是均匀聪明;在一些 domains 上陡然很强,在另一些 domains 上停滞,而且与人类觉得任务难不难几乎没有稳定相关性。同一个 state-of-the-art model,可以 refactor 十万行 codebase,或发现 zero-day vulnerability,同时 又建议你步行去 50 米外的 car wash 而不是开车。两种能力之间的联系,主要取决于 labs 是否在相应 RL environments 上训练过。
frontier models 在输出可验证的任务上被大量 reinforcement learning:数学题、可编译并通过 tests 的代码、formal proofs。reward signal 干净,模型就在这些 circuits 中学得很好。离开这些 circuits,就回到 pre-training intuition,没有同等反馈去磨尖它。
capability
│
│ ╱╲ ╱╲
│ ╱ ╲ ╱╲ ╱ ╲
│ ╱ ╲ ╱ ╲ ╱ ╲ ╱╲
│ ╱ ╲╱ ╲╱ ╲ ╱ ╲
│ ╱ ╲ ╱ ╲___
└────────────────────────────────────────► task
code refactor math car-wash common-sense
walking physical reasoning
这个约束有四个操作含义。
第一,code 是幸运 domain。 你工作在整个能力表面最深的 peaks 之一。这不是因为 coding 天生更容易,而是 labs 经济上优先训练它。把它当作好运,不要当作模型「真的智能」的证据。
第二,feedback loops 让你留在 verifiable circuits 里。 static types、automated tests、lints、compile errors,是模型训练时最熟悉的 reward shape。agent 跑 tests 并看到失败时,正处在它训练出最强行为的反馈形状里。没有这些信号,它就回到无校正的 pre-training intuition。这就是 Failure 3 和 tdd Skill 背后的 deeper why。
第三,你必须知道自己在哪个 circuit。 当 agent 做出一个 junior engineer 都不会做的选择,往往不是它「笨」,而是你把它带离了 peak。Karpathy 在 MenuGen 中看到 agent 用 email 而不是 explicit user_id 做 cross-reference,问题不在 prompt,而在 identity modelling 这个区域没有足够强的训练电路。修复方法是人给出明确 architecture guidance。
第四,从零开始时,选择能落在 peak 里的 stack。 jagged map 在语言和 frameworks 上并不对称。Boris Cherny 解释 Claude Code 为什么用 TypeScript 和 React:它们在模型分布上很常见。其他约束允许时,优先 mainstream:Python、TypeScript、Postgres、流行 frameworks。你选的不是一个人独写时最爱的技术,而是你的 agent workforce 写得好的技术。
3. AI Coding 的六种失败模式
三个约束会产生可预测失败。下面六种足够常见,可以当作闭合目录来处理。表格是诊断;后面的段落把每一行展开为 symptom、root cause 和 cure。
| # | Symptom | Root cause | Cure | Skill | Where |
|---|---|---|---|---|---|
| 1 | 「agent 没做我想要的事」 | 你和 agent 之间没有 shared design concept | 写任何 asset 之前,通过 Socratic interview 强制对齐 | grill-me | §5, §6.1 |
| 2 | 「agent 太啰嗦」 | 没有 ubiquitous language;你和 agent 给同一件事起了不同名字 | 每个 session 加载 CONTEXT.md 中的 domain terms | grill-with-docs | §5, §6.1 |
| 3 | 「代码不能工作」 | feedback loops 弱;agent 盲写代码 | 响亮环境(types、tests、lints)+ TDD red-green-refactor | tdd | §5, §6.4 |
| 4 | 「我们造出了一团泥」 | shallow modules;agents 产出浅模块的速度比人清理更快 | 每天投资 module design;定期 deepening pass | improve-codebase-architecture | §7 |
| 5 | 「我的脑子跟不上」 | 你以 5 倍速度读每一行 | gray-box 原则:设计 interfaces,delegate implementations | architectural habit | §7.3 |
| 6 | 「我 review 的代码比我写的还多」 | 吞吐量把瓶颈转移到 review | 把 review 分成 automated + human layers;vertical slices 保持 diff 小 | automated-review recipe | §6.5, §7 |
Failure 1:「agent 没做我想要的事」
通常不是 agent 不听话,而是你没有给它和你共同持有的 design concept。愿望不是 spec。grilling 的作用,是在任何 PRD 或代码之前,把模糊愿望变成共同设计。
Failure 2:「agent 太啰嗦」
啰嗦常常来自 vocabulary 不一致。agent 不知道你们把某个 domain concept 叫什么,于是每次都绕着解释。CONTEXT.md 和 ADRs 的作用,是把 domain language 固化进 environment,让每个 fresh session 都从同一语言开始。
Failure 3:「代码不能工作」
agent 需要可验证反馈。types、tests、lints 和 compile errors 不是额外负担,而是 agent 能力峰值所在的电路。tdd Skill 把 red-green-refactor 变成操作流程:先写一个失败 test,再写刚好通过的实现,再 refactor。
Failure 4:「我们造出了一团泥」
agent 会很快制造 shallow modules:小函数很多、文件很多、调用者要知道太多内部细节。deep modules 则相反:small interface、large internal implementation。定期 deepening pass 是 codebase health 的维护,而不是事后美化。
Failure 5:「我的脑子跟不上」
如果你试图读 agent 写的每一行,吞吐量会把你压垮。senior engineer 的杠杆在于读 interfaces、contracts 和 invariants;implementation details 交给 agent 和 tests。你保持 architectural map,不保持每一行代码。
Failure 6:「我 review 的代码比我写的还多」
当 implementation 加速,review 成为瓶颈。解决方法不是少 review,而是分层:automated review 抓机械问题,human review 抓 contracts、security、domain constraints 和 UX。vertical slices 让每个 diff 小到人能读。
4. End-to-End Workflow
workflow 的核心不是「让 agent 写更多代码」,而是让每个阶段都有合适 artifact、合适 session 和合适 review boundary。
4.1 Day Shift / Night Shift Model
day shift 是人和 agent 一起决定方向:grill idea、写 PRD、拆 issues。night shift 是 agent 在 sandbox 中执行:拿一个 issue,跑 TDD,打开 PR。然后回到 day shift:人读 diff、跑 QA、决定 merge 或开新 issue。
flowchart LR
A[Idea] --> B[Grilling]
B --> C[PRD]
C --> D[Vertical-slice issues]
D --> E[Implementation Loop<br/>TDD per slice]
E --> F[Automated Review<br/>separate session]
F --> G[Human Review<br/>read the diff]
G --> H[QA]
H --> I[Merge]
这个模型解决 smart-zone 问题。每个 stage 都足够小,可以在 fresh session 中完成。handoff 通过 artifact,而不是通过长聊天历史。
4.2 "Specs-to-Code" 的限制
「写好 spec,然后让 AI 生成代码」只解决了一半问题。spec 可能不代表真实 design concept;也可能把工作拆成 horizontal phases,等到最后才发现集成问题。好的 pipeline 不只是 specs-to-code,而是 concept-to-slices-to-feedback。
4.3 Vertical Slices 和 Tracer Bullets
vertical slice 是一条薄路径,穿过系统每一层。tracer bullet 的价值在于尽早碰到 integration feedback。horizontal slicing(先 schema、再 API、再 UI)会把最重要的反馈推迟到最后;vertical slicing(一个 user story 从 UI 到 data)会让系统早早发声。
flowchart TB
subgraph H["Horizontal slicing - bad<br/>(no integrated feedback until phase 3)"]
HS[Schema] --> HA[API] --> HU[UI]
end
subgraph V["Vertical slicing - good"]
V1[Slice 1<br/>F→A→D] ~~~ V2[Slice 2<br/>F→A→D] ~~~ V3[Slice 3<br/>F→A→D]
end
5. Skills as Encoded Process
每一种 cure 都需要编码为可复用、agent 可加载的 artifact。这个 artifact 就是 Skill。
Principle vs. instance。 pipeline 中有五个原则:grilling、PRD-synthesis、vertical-slicing、TDD、deepening。每个原则目前都有一个 best-in-class Skill 实现。实现会进化,原则不会。社区 Skills registry 是 skills.sh;Matt Pocock 的 pack 在 skills.sh/mattpocock。
5.1 Skill 是什么,不是什么
Skill(名词): 打包成一个单元的可教能力,包含完成某项任务的 instructions 和 resources,保存在 environment 中,只在相关时加载到 context window。
Skill 是 agent 读取 的东西;Tool 是 agent 调用 的东西。Skill 可能写着「当用户要求 deploy 时,运行 bash deploy.sh,再用 gh 验证」:Skill 是 prose;bash 和 gh 是 tools。
Skill 也是 on-demand。AGENTS.md 每轮加载,每个 model provider request 都付 token 成本;Skill 只有在 agent 判断相关时才加载。不需要每轮都在 context 中的东西,应该放进 Skill,而不是 AGENTS.md。这就是 progressive disclosure。
Skill 还是 portable。同一个 SKILL.md 在 Claude Code 和 OpenCode 中可不改运行。纪律随文件移动,harness 可替换。
5.2 Skills 放在哪里
两个 harness 都会在 session start 扫描约定目录,读取每个 SKILL.md 的 YAML frontmatter,并把名称和 descriptions 暴露给 agent。body 只有在 agent 判断 Skill 相关时才加载。
skills CLI 会把 community pack 安装到 .agents/skills/,这是跨工具的标准位置。安装后的目录大致如下:
project/
└── .agents/
└── skills/
└── grill-me/
└── SKILL.md
同一个 SKILL.md 格式在两个 harness 中都有效。不同的是扫描目录,这只影响安装步骤。
Claude Code 2.1.141 扫描 .claude/skills/<name>/SKILL.md(以及全局 ~/.claude/skills/),不扫描 .agents/skills/。skills CLI 会安装到 .agents/skills/,但只有 .claude/skills/ 已存在时才会 link 进去。所以先创建目录,再安装:
mkdir -p .claude/skills
npx skills@latest add mattpocock/skills
目录先存在时,每个 skill 都会被 link 到 .claude/skills/,Claude Code 才能发现 pack。可以用自然语言调用 Skill,也可以显式输入 /grill-me。
一个格式,两个 harness,无需翻译步骤。install path 是唯一差异,而且只差一个 mkdir。
5.3 SKILL.md 的结构
SKILL.md 有两部分:YAML frontmatter(harness 扫描的 metadata)和 markdown body(agent 加载后阅读的 instructions)。
Matt Pocock pack 中 star 最多的 Skill 是 grill-me,body 只有七行:
---
name: grill-me
description: Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to stress-test a plan, get grilled on their design, or mentions "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 between decisions one-by-one. For each question, provide your recommended answer.
Ask the questions one at a time.
If a question can be answered by exploring the codebase, explore the codebase instead.
三个观察可以泛化:
- Skill 不需要很长才有影响力。 这一个本质上只有三句话,却改变了 planning conversation。
- frontmatter 在做真实工作。 harness 给 agent 看的是
description,不是 body,所以 description 必须具体到让 agent 在正确时刻加载它。 - body 用第二人称直接对 agent 说话。 「Interview me relentlessly」「Ask the questions one at a time」。直接、声明式、不含糊。
更复杂的 Skills(to-prd、to-issues、tdd、improve-codebase-architecture)只是把同一形状扩展成 numbered steps、template 和其他 Skills 的指针。原则不变:encode the process; do not encode the answer.
5.4 五个日常原则(以及今天每个原则最好的 Skills)
| Stage | Skill | 做什么 |
|---|---|---|
| Idea → aligned design concept | grill-me | 苏格拉底式访谈,直到 alignment 达成 |
| Aligned concept → destination doc | to-prd | 把对话综合成 PRD,包含 user stories、implementation decisions 和 touched modules |
| PRD → backlog of issues | to-issues | 把 PRD 拆成有 blocking relationships 的 vertical-slice tickets |
| Issue → implemented slice | tdd | 对一个 slice 做 red-green-refactor |
| Codebase health | improve-codebase-architecture | 找 shallow modules,提出 deepenings,打开 RFC issue |
运行前的 bootstrap。 Matt 的 pack 期望每个 repo 先跑一次
setup-matt-pocock-skills,用于 scaffolding issue-tracker config、AGENTS.md/CLAUDE.md中的## Agent skillsblock,以及docs/agents/目录。
三个性质贯穿全部 Skills:
description决定加载时机。它要告诉 agent 什么时候 加载,而不是只说 Skill 关于什么。- Skills 会命名 boundaries。
to-prd不重新访谈;improve-codebase-architecture不改代码。这些 negative clauses 让 Skills 能组合而不互踩。 - Skills 会命名 pairings。
tdd和它实现的 issue 配对;to-issues和它拆分的 PRD 配对。pipeline 是 Skills 的链条,每个都把 artifact 交给下一个。
这条 pipeline 的 architecture(Skills、vertical slices、deep modules、sandboxes)与模型无关。它的 operational reliability 不是。frontier-class instruction follower(Claude Sonnet/Opus、GPT-5-class、Gemini 2.5 Pro)通常能按 description match 加载正确 Skill,按顺序执行 multi-step Skill body,并在 grilling alignment 达成时自行结束。economy 或 local model 上,这些行为会下降:Skill trigger 漏掉、多步 sequencing 滑动、literal-output contracts 被破坏。弱模型上要 scaffold 更硬:显式按名称调用 Skill,保持 Skill body 短而声明式,并写清楚模型不要做什么。
grill-with-docs 关闭 Failure 2(verbose agent / no shared vocabulary)。它和 grill-me 一样做 Socratic interview,但会在决策 crystallise 的同时更新 CONTEXT.md 和 docs/adr/ 中的 Architecture Decision Records。greenfield design conversation 用 grill-me;已有 repo 且希望 CONTEXT.md 和 ADRs 保持最新时,用 grill-with-docs。
先构建自己的 Skills,再使用别人的 pack。 最好的 Skill,是捕捉你团队真实流程的 Skill。fork
mattpocock/skills是很好的起点。拥有 stack,能读每个加载的 Skill,才让你在出错时有 observability。
6. Pipeline 实战
本节用一个 worked example 端到端跑 workflow:给 course platform 添加 gamification service。同一个例子用 Python 和 TypeScript 各构建一次;每一步都可在 Claude Code 和 OpenCode 中运行。重点不是例子,而是 shape。掌握形状后,语言和 harness 都是细节。
6.1 Stage 1:Grilling the Idea
stakeholder 发来一条 Slack 消息:
"Our retention numbers aren't great. Students sign up, do a few lessons, then drop off. I'd love to add some gamification to the platform: points, streaks, levels."
这不是 spec,而是 wish。直接把它交给 agent 说「build it」,会得到一个不匹配 stakeholder 心智模型的东西,因为你们都还不知道他们真正想要什么。调用 grill-me。
$ claude
> /grill-me
> Read the Slack message in client-brief.md and grill me on adding gamification.
agent 会阅读 brief,探索 codebase 中已有模型(Lesson、Quiz、Enrollment),然后一次一个问题地追问,并给出 recommended answer:
Q1. What earns points? My recommendation: lesson completion + quiz pass.
Skip video-watch events (too noisy, gameable).
Q2. Are points retroactive for existing lesson_progress records?
My recommendation: yes, backfill once on migration, then live going forward.
Q3. Streak granularity? My recommendation: daily, with a 1-day grace period.
Q4. Level thresholds: linear, quadratic, or hand-tuned?
My recommendation: quadratic, capped at level 50.
...
session 可能停在 15 到 100 个问题之间。结束条件是 agent 报告没有 unresolved decisions,并且你们拥有稳定的 design concept。不写代码,不写 PRD。 grilling 的输出是一段 chat history;chat history 是 design concept 的显式化。
6.2 Stage 2:从 Conversation 到 PRD
design concept 稳定后,调用 to-prd。这个 Skill 不会重新采访你;它会把你们已经说过的内容综合成 Product Requirements Document。
> /to-prd
输出是固定模板的 markdown 文档:
# PRD: Course Platform Gamification
## Problem Statement
Students drop off after a handful of lessons. Retention metrics
indicate completion rates ... [synthesised from the brief]
## Solution
Add a points/streaks/levels gamification layer ...
## User Stories
1. As a student, I earn 10 points when I complete a lesson.
2. As a student, I earn 25 points when I pass a quiz.
3. As a student, I see my current streak on the dashboard.
4. As a student, I see my level on my profile.
5. As an admin, I can see aggregate engagement metrics.
## Modules Touched
- NEW: gamification_service (deep module, owns points + streaks + levels)
- MODIFIED: lesson_progress_service (emits events on completion)
- MODIFIED: dashboard route (reads from gamification_service)
- NEW DB: point_events table, streak_state table
## Implementation Decisions
- Level formula: floor(sqrt(total_points / 50))
- Streak grace: 1 missed day allowed
- Backfill: one-time job at deploy
## Out of Scope
- Leaderboards (separate PRD)
- Push notifications (separate PRD)
批准 PRD 前读什么。 skim for drift,不要逐字 proofread。 你和 agent 已经通过 grilling 共享了 design concept,agent 很擅长 summarisation。把注意力放在四个可能漂移的位置:user stories 是否遗漏或发明;modules touched 是否仍符合边界;implementation decisions 是否匹配 grilling 中的决定;out of scope 是否 creep。
6.3 Stage 3:从 PRD 到 Vertical-Slice Issues
PRD 描述目的地;to-issues 描述旅程:如何把 PRD 拆成 independently grabbable issues,按 vertical slices 切分,并写清 blocking relationships。
gamification PRD 会产出一个小 Kanban board:
┌────────────────────────────────────────────────────────────┐
│ Issue #1 - Award points for lesson completion (E2E) │
│ blocked by: nothing. Type: AFK. │
│ Touches: schema, service, lesson route, dashboard widget │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ Issue #2 - Award points for quiz pass (E2E) │
│ blocked by: #1. Type: AFK. │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ Issue #3 - Show streak on dashboard (E2E) │
│ blocked by: #1. Type: AFK. │
└────────────────────────────────────────────────────────────┘
每个 issue 必须是一条 tracer bullet:小、端到端、可 review、可独立失败。不要拆成「database phase」「backend phase」「frontend phase」。那会把 feedback 推迟到最晚。
6.4 Stage 4:Implementation:对一个 Slice 做 TDD
tdd Skill 的工作方式是严格的 red-green-refactor。它先写 failing test,然后写刚好通过的 implementation,再 refactor。tests 应落在 module interface,而不是 internal helpers。
- Python
- TypeScript
# gamification/service.py - the deep module's interface
from dataclasses import dataclass
from datetime import date
@dataclass
class PointAward:
points: int
reason: str
new_total: int
class GamificationService:
def award_lesson_completion(self, student_id: str, lesson_id: str) -> PointAward:
...
def total_points(self, student_id: str) -> int:
...
def current_streak(self, student_id: str) -> int:
...
# gamification/test_service.py - written FIRST
def test_awards_points_for_lesson_completion(service):
award = service.award_lesson_completion("student-1", "lesson-1")
assert award.points == 10
assert service.total_points("student-1") == 10
// gamification/service.ts - the deep module's interface
export interface PointAward {
points: number;
reason: string;
newTotal: number;
}
export class GamificationService {
awardLessonCompletion(studentId: string, lessonId: string): PointAward {
throw new Error("not implemented");
}
totalPoints(studentId: string): number {
throw new Error("not implemented");
}
currentStreak(studentId: string): number {
throw new Error("not implemented");
}
}
// gamification/service.test.ts - written FIRST
it("awards points for lesson completion", () => {
const service = new GamificationService();
const award = service.awardLessonCompletion("student-1", "lesson-1");
expect(award.points).toBe(10);
expect(service.totalPoints("student-1")).toBe(10);
});
slice 足够小,agent 可以在 smart zone 中完成;test 足够明确,agent 可以留在 verifiable circuit 中;interface 足够窄,人可以 review。
第二个 slice 不应该重写第一个 slice,而是在同一 interface 上新增最小行为:
- Python
- TypeScript
# gamification/service.py - interface gains ONE method or behaviour
def test_awards_points_for_quiz_pass(service):
award = service.award_quiz_pass("student-1", "quiz-1")
assert award.points == 25
// gamification/service.test.ts - existing tests untouched; one new test added
it("awards points for quiz pass", () => {
const service = new GamificationService();
const award = service.awardQuizPass("student-1", "quiz-1");
expect(award.points).toBe(25);
});
重点是:每个 slice 都有一个可 review 的 diff,一个 failing test,一个最小 pass,一个 refactor step。agent 的速度来自 repetition;质量来自边界。
6.5 Stage 5:AFK Loop
AFK loop 会从 issue queue 中拿最高优先级、未被 blocked 的 issue,把它放进 fresh sandbox,运行 implementation session,提交 branch,然后继续。它不替代 human review;它只是把可安全自动化的 typing 和 test-loop 移到 night shift。
6.5.1 Minimal AFK loop(bash)
# ralph.sh - the simplest AFK loop. Works with either harness.
# Loops over /issues/*.md, picks the highest-priority AFK issue,
# implements it inside a sandbox, commits, repeats until done.
set -euo pipefail
AGENT_CMD="${AGENT_CMD:-claude}"
AGENT_PERM_FLAG="${AGENT_PERM_FLAG:---dangerously-skip-permissions}"
while true; do
ISSUE="$(ls issues/*.md | head -n 1 || true)"
[ -z "$ISSUE" ] && echo "NO_MORE_TASKS" && exit 0
git checkout -b "afk/$(basename "$ISSUE" .md)"
"$AGENT_CMD" "$AGENT_PERM_FLAG" < prompts/implement.md
git add .
git commit -m "Implement $(basename "$ISSUE" .md)"
done
真实版本会处理 worktrees、timeouts、failed tests、branch naming、artifact upload 和 review queues。原则不变:每次 issue 都是 fresh context、isolated sandbox、small diff。
6.5.2 Parallel AFK orchestrator(TypeScript)
type Issue = {
id: string;
path: string;
blockedBy: string[];
type: "AFK" | "HUMAN";
};
async function loadIssues(dir: string): Promise<Issue[]> {
// read issue metadata from markdown files
return [];
}
function unblocked(issue: Issue, done: Set<string>): boolean {
return issue.blockedBy.every((id) => done.has(id));
}
async function runInSandbox(issue: Issue): Promise<{ ok: boolean; branch: string }> {
// create worktree/container, run agent, run tests, commit branch
return { ok: true, branch: `afk/${issue.id}` };
}
parallelism 只在 issues 互不 blocked 时安全。queue discipline 比 raw concurrency 更重要。一个 agent 写 schema,另一个 agent 同时写依赖该 schema 的 UI,除非 blocking graph 表达清楚,否则就是制造冲突。
6.5.3 Persistent Loops 和 Ambient Agents
AFK loop 可以从手动脚本升级成 persistent routine:cron、本地 daemon、GitHub Action、server-side routine。每次 tick 都是 stateless fresh session;persist 的不是 chat memory,而是 role、prompt、issue queue 和 artifacts。
# crontab -e
# every 30 minutes, run the PR-janitor agent in the project
*/30 * * * * cd ~/work/project && ./agents/pr-janitor.sh
ambient agent 不是一个一直醒着的长 conversation。它是一组按 schedule 启动的短 session,每次读取同一 environment,并在 artifacts 中留下状态。这样它不会老化进 dumb zone。
6.6 Stage 6:Human Review 和 QA
人类 reviewer 读的是 diff,不是 agent summary。summary 可以帮助定位,但不能替代阅读。review 的问题:
- interface 是否正确?
- tests 是否覆盖行为,而不是绑死 implementation?
- 是否违反 domain constraint?
- 是否泄露 secret、扩大 permission 或破坏 data invariant?
- diff 是否仍然是一条 vertical slice?
如果答案是否定的,不要在 review session 里让 agent 大修。开新 issue,让 fresh session 修复。reviewer session 和 implementer session 分开,避免同一个 dumb-zone trajectory 同时犯错又为自己辩护。
7. 面向 AI-Friendly Codebases 的 Architecture Principles
7.1 Deep Modules 胜过 Shallow Modules
deep module 的 interface 小,内部实现大。调用者只需要知道少量方法;复杂性藏在模块内部。shallow module 则把小函数、helper 和 sequencing 暴露给调用者,让每个调用者都必须知道太多。
flowchart LR
subgraph Shallow
S1[small function] --> S2[small function] --> S3[small function]
SLABEL["many small pieces<br/>callers thread through<br/>implicit dependencies"]
end
subgraph Deep
DI["small interface<br/>━━━━━━━━━━━"]
DBODY["large internal<br/>implementation<br/>(hidden from callers)"]
DI --> DBODY
end
gamification service 的 bad shape 是让调用者自己调用 validateAntiCheat、recordPointEvent、updateStreak、calculateLevel。good shape 是一个窄 interface:
export class GamificationService {
awardLessonCompletion(studentId: string): PointAward; // does ALL of the above internally
totalPoints(studentId: string): number;
currentStreak(studentId: string): number;
// streak recording, anti-cheat, level calc, point amounts → all hidden
}
三个 methods。内部仍有九个 concerns,但它们不是 interface。调用者不会忘记调用 validateAntiCheat,因为调用者根本不能调用它。tests 落在三个 methods 上,不是九个。
Heuristic。 如果 IDE Outline view 中一个 module 的公开内容比它的 public interface 长很多,这个 module 多半是 shallow。加深它。
7.2 Test at the Interface
Tests 应落在 module interfaces 上,而不是 internal functions 上。 internal function 上的 test 会钉死 implementation;即使外部行为正确,内部 refactor 也会破坏 test。interface 上的 test 钉住的是 behaviour;只要 contract 保持,内部可自由变化。
这正是 tdd Skill 默认强制的:tests target interface;agent 在 green steps 之间 refactor internals;小 surface area 提供足够 coverage。
7.3 Design the Interface, Delegate the Implementation
这是 senior engineer 与 agents 工作时最重要的习惯。
你决定 module 暴露什么:contract、names、invariants。这些决定影响每个 caller,塑造 architecture,需要 taste 和 whole-system view。
agent 决定 contract 如何被满足:internal data structures、helper placement、operation order。这些只影响一个 module 的内部;错误可恢复;不需要完整 architectural map。
这就是 gray box 原则。从外部看,module 完全被指定:interface 可见,internals 按设计不可见。从内部看,agent 可以自由做出优秀实现,只受 interface contract 约束。senior engineer 能在脑中持有百万行 codebase 的 architecture map,因为 map 只包含 interfaces。
7.4 improve-codebase-architecture Skill
codebases 会随着时间漂向 shallow,尤其是有 agents 参与时。修复方式是周期性 deepening pass。
---
name: improve-codebase-architecture
description: Find shallow-module candidates in the codebase and propose deepenings. Run weekly, or after a burst of feature work.
---
You are an architecture reviewer. Walk the codebase and find places
where understanding one concept requires bouncing between many small
files; where pure functions have been extracted only for testability,
not behaviour; where modules are tightly coupled at the seams.
Surface a numbered list of deepening candidates. For each, briefly:
- which existing files would collapse into the new deep module
- what the new interface would be (3-5 method signatures, no more)
- what behaviour would move inside, freeing callers from knowing it
Do NOT make changes. Open a markdown RFC describing the highest-value
candidate as an issue, blocked by nothing, type AFK.
每周运行一次会产生一个 deepening RFC。它进入和 feature work 同一个 Kanban board,再通过同一个 TDD-on-vertical-slices loop 实现。codebase 是按 schedule 变健康,不是靠偶然。
8. Working Vocabulary
精确词汇会加速推理。完整参考是 Dictionary of AI Coding;下面是读写本书其余部分所需的最小集合。
| Term | Meaning |
|---|---|
| Model | 参数本身。stateless。做 next-token prediction,除此之外什么也不做。 |
| Harness | model 周围把它变成 agent 的一切:tools、system prompt、context-window management、permissions。Claude Code 和 OpenCode 都是 harness。 |
| Agent | model + harness,在 context window 中使用 tools 运行。你实际对话的对象。 |
| Context window | 每次 request 中 model 能看到的固定大小视图。有限,是 model 感知世界的唯一表面。 |
| Smart zone / dumb zone | session 早期 attention 清晰的区域 / session 后期 attention 被竞争 tokens 稀释的区域。 |
| Hallucination | 自信但错误的输出。factuality hallucinations 来自 parametric knowledge 缺口;faithfulness hallucinations 来自 dumb zone 漂移。修复不同。 |
| Clearing | 结束 session 并开新 session。hard reset,让 agent 回到已知状态。 |
| Compaction | 把 session 总结进 memory 以 seed 新 session。有损,会保留部分 dumb-zone reasoning。 |
| Handoff | 通过 artifact(PRD、ticket、CONTEXT.md)把 context 从一个 session 转到另一个 session。 |
| AFK | Away from keyboard。用户启动 session,让它在 sandbox 中无人看守地跑。 |
| Skill | 以 SKILL.md 文件打包的可教能力。按需加载,是 progressive disclosure 的单元。 |
| Tracer bullet / vertical slice | 一条薄 issue,端到端穿过系统每一层。 |
| Deep module | interface 小、内部实现大的 module。让 AI codebases 可扩展的形状。 |
| Design concept | 用户和 agent 共同持有的、关于要构建什么的临时想法。不是 asset。 |
| Grilling | 形成 design concept 的技巧:agent 用苏格拉底式问题逐个解决设计决定。 |
| Vibe coding | 不做人类 review 而接受 agent code。这个词命名 review stance,不是输出质量。 |
| Agentic engineering | 在 production work 中使用 agents,同时保留专业软件质量标准的纪律。 |
| Jagged intelligence | LLM capability 在可验证 RL 训练过的任务上陡然很强,在其他 circuits 中停滞。 |
| On distribution | 在模型训练数据中充分出现,因此模型处理得好的性质。 |
| Loop / Routine | persistent ambient agent:按 schedule 调用 fresh session 完成小型 standing job。 |
一个熟练 coder 应能自然说出:「我要先 clear,然后对下一个 unblocked vertical slice 跑 tdd」或「这是 faithfulness hallucination;docs 还在 context 中,只是它在第 40 轮左右停止读了」。
9. Practical Drills
三个练习,按顺序做。每个 30 分钟到 2 小时。
Drill 1:安装并在真实 idea 上运行 grill-me。 选择一个你一直拖着没 scope 的 feature。在干净 repo 中按 §5.2 安装 skill pack(Claude Code 读者先 mkdir -p .claude/skills,再 npx skills@latest add mattpocock/skills)。打开 Claude Code 或 OpenCode,调用 /grill-me,回答问题直到 agent 停止。不要 shortcut。数一数问题数量,记录哪些决定是你自己不会主动浮现的。
好的样子。 非 trivial feature 的 grilling session 通常会有 15–40 个问题,花 30–90 分钟 才报告 alignment。低于 10 个问题通常说明 idea 太小或你回答太宽;超过 60 个问题通常说明 agent 在 fishing,要打断并要求它每题给 recommendation。结束时,你应能复述至少三个之前没考虑到的决定。
Drill 2:把一个 vertical slice 写成 tracer bullet。 从 codebase 中拿一个未完成 feature。写一条最小 end-to-end user story。用 tdd Skill 实现。注意 slice 有多短,也注意 integration bugs 比 horizontal slicing 更早浮现。
好的样子。 slice 在一个 session 内落地,并在同一个 PR 中包含 test、implementation 和 reviewable diff。如果做不到,slice 太厚,拆掉。练习价值就在 during slice 暴露的 integration friction;把它捕捉成 new issues,不要扩大当前 slice。
Drill 3:加深一个 module。 在你熟悉的 codebase 上运行 improve-codebase-architecture。选最高价值 candidate。先不要实现,在纸上 sketch 新 interface(3–5 个 method signatures)。比较新 interface surface area 与旧 surface area(会被合并的文件中 public symbols 总数)。这个 ratio 是 codebase 变 shallow 的具体度量。
每日工作 checklist:
- 今天开始 session 前
/clear了吗? - 对任何 non-trivial change 使用
grill-me了吗? - issues 是 vertical slices,而不是 horizontal phases 吗?
- 每个 implementation slice 都通过
tdd吗? - AFK runs 是否在 sandbox 中?
- reviewer 是否和 implementer 是独立 session?
- 我读的是 diff,而不是 summary 吗?
10. Closing:Strategic Programmer
带走这幅图:
你的 agent 是优秀的战术程序员:一个地面 sergeant,能在任何语言、任何 framework、中半夜拿下任何规格明确的 hill,早上带回可工作的 slice。你不需要教它怎么写函数或 test。harness、model 和 tools 已经解决了这件事。
这个 sergeant 不能决定 哪座 hill。它不能告诉你正在构建的系统是否是业务真正需要的系统;不能告诉你第三个即将请求的 module 是否应该作为单独 module 存在,还是应折叠进已有 deep module;不能告诉你请求的代码违反了某个尚未写下来的 domain constraint。它无法跨数月数年保持系统 architecture map;它没有数月数年,只有当前 session 和磁盘上的几个文件。
sergeant 之上的所有事情,都是 strategic programmer 的角色,也就是你的角色。与 stakeholder 对齐。形成 design concept。选择 slice。设计 interface。阅读 diff。持有 map。每天投资系统设计。Kent Beck 30 年前写给人类的原则,现在适用于人类工程师与 Digital FTEs 混合 workforce。
本章描述的是 strategic programmer 的工具:pipeline(§4)、六种失败及其 cures(§3)、编码 cures 的 Skills(§5)、让 agent 表现良好的 architecture(§7)、让你能推理这一切的 vocabulary(§8)。无论 Claude Code 还是 OpenCode,纪律相同;无论 Python 还是 TypeScript,纪律相同;无论 5 年后是什么 model 和 harness,纪律仍会相同。
开头那种「AI 替代软件基本功」的叙事错在混淆了 谁在写代码 和 什么是好代码。作者变了,标准没有变。对人类好的 codebase,对 agents 也好。对人类坏的 codebase,对 agents 更坏,因为 agents 会放大这种坏。
读老书。The Pragmatic Programmer、A Philosophy of Software Design、Domain-Driven Design、Extreme Programming Explained、The Design of Design。每一页都早于这项技术,也都比当年更尖锐地适用。它们教 strategic programmer 如何在 sergeant 无法到达的时间尺度上思考。
Karpathy 有一句话值得带走:"You can outsource your thinking, but you can't outsource your understanding." agent 会做 typing、searching、boilerplate、API-detail recall、tedious refactor。它也会越来越多地做 thinking:生成选项、权衡方案、起草解决方案、运行实验。真正剩下给你的,是 understanding:为什么构建这个系统,它为了谁,谁依赖它,它绝不能做什么。understanding 让你能指挥 agent。没有它,agent 没有目的地;没有目的地的高速 agent,只是昂贵的迷路方式。
Boris Cherny 的 corollary 是:当 coding 被解决,domain knowledge 成为瓶颈时,最适合写软件的人,是最理解 domain 的人,而不一定是历史上写软件的人。最好的 accounting software 作者,可能是非常优秀的 accountant。未来一代人里,building software 会成为各领域专业人士的日常能力;而「engineer」会变得更窄、更深:设计底层 substrate,让其余 workforce 在上面构建的人。
这就是本书关注的 workforce shape。后续章节中你会制造的 Digital FTE,是 domain expert 的工具:由 agentic engineer 构建,但由 accountant、underwriter、analyst、case manager 这些真正 owning the work 的人来 specify、govern 和使用。本章的 principles 和 workflows,是让这些 Digital FTEs 足够可信、值得交给他们 ownership 的 contract。
这就是工作。这就是本章。
Further Reading
- Matt Pocock, Software Fundamentals Matter More Than Ever:本章 thesis 的 keynote 来源。
- Matt Pocock, Full Walkthrough: Workflow for AI Coding:§4 和 §5 pipeline 的两小时 live walkthrough。
- Matt Pocock, 5 Claude Code Skills I Use Every Single Day:daily-Skills 参考。
- Matt Pocock, Dictionary of AI Coding:canonical glossary,也是 §8 的来源。
- Matt Pocock, Skills for Real Engineers:全章使用的 installable skill pack。
- Andrej Karpathy, From Vibe Coding to Agentic Engineering:命名这套 discipline,并提出 Software 1.0/2.0/3.0 framing、jagged intelligence 等视角。
- Boris Cherny (Anthropic), Why Coding Is Solved, and What Comes Next:Claude Code 创建者谈个人 workflow、stack choice、persistent loops 和 printing-press analogy。
- John Ousterhout, A Philosophy of Software Design:deep modules、shallow modules。
- David Thomas & Andrew Hunt, The Pragmatic Programmer:tracer bullets、headlights。
- Eric Evans, Domain-Driven Design:ubiquitous language。
- Kent Beck, Extreme Programming Explained:每天投资设计。
- Frederick P. Brooks, The Design of Design:design tree、design concept。
Companion Skills(本章)
本章 pipeline 使用 Matt Pocock pack 中的六个 Skills:
grill-me:产生 design concept 的 Socratic interview。grill-with-docs:同时写CONTEXT.md和 ADRs 的 grilling。to-prd:把 conversation 综合成 PRD。to-issues:把 PRD 拆成 tracer-bullet tickets。tdd:一次一个 slice 的 red-green-refactor。improve-codebase-architecture:找 shallow modules,提出 deepenings,打开 RFC。
一次性 bootstrap Skill setup-matt-pocock-skills 应在每个 repo 先运行,用来 scaffolding issue-tracker config 和 engineering skills 依赖的 docs/agents/ layout。
Matt 的 pack 总共包含 14 个 skills(full repo)。除七阶段 pipeline 和 setup 外,还包括 diagnose、triage、zoom-out、prototype、write-a-skill、handoff 和 caveman。它们不在七阶段主链里,但可以与之组合,并且在 Claude Code 和 OpenCode 中以相同方式运行。