我把 Claude Code 当作主力开发工具已经大约 9 个月了,我最终磨合出的工作流,跟大多数人用 AI 编程工具的方式截然不同。大多数开发者的套路是:输入提示词,偶尔用一下方案模式(plan mode),修修报错,然后循环往复。那些深度冲浪的人(terminally online,指深度沉浸于在线社区的人)则忙着拼凑各种 ralph loops、MCP、gas towns(这些都是 AI 编程社区中曾流行的工具链组合方式,还记得吗?)之类的东西。两种做法的结果都是一团糟——稍微碰到点复杂需求就彻底崩溃。

我要介绍的工作流只有一条核心原则:在你审阅并批准书面方案之前,绝不让 Claude 写代码。这种规划与执行的严格分离,是我做的最重要的一件事。它杜绝了无谓的返工,让我始终掌控架构决策,并且以更少的 token 消耗产出远优于直接上手写代码的结果。

graph LR
    A[调研] --> B[规划]
    B --> C[注释]
    C -->|重复 1-6 次| C
    C --> D[任务清单]
    D --> E[实现]
    E --> F[反馈与迭代]
    F -->|继续| E

第一阶段:调研

每个有意义的任务都始于一条深度阅读指令。我要求 Claude 在做任何事之前,先彻底理解代码库的相关部分。而且我总是要求将发现写入一个持久化的 markdown 文件——绝不接受聊天里的口头总结。

read this folder in depth, understand how it works deeply, what it does and all its specificities. when that’s done, write a detailed report of your learnings and findings in research.md
深入阅读这个文件夹,深度理解它的工作原理、功能以及所有细节特性。完成后,将你的学习成果和发现写成一份详尽的报告,保存到 research.md

study the notification system in great details, understand the intricacies of it and write a detailed research.md document with everything there is to know about how notifications work
详细研究通知系统,理解它的每一个精妙之处,然后写一份详尽的 research.md 文档,涵盖通知机制的方方面面

go through the task scheduling flow, understand it deeply and look for potential bugs. there definitely are bugs in the system as it sometimes runs tasks that should have been cancelled. keep researching the flow until you find all the bugs, don’t stop until all the bugs are found. when you’re done, write a detailed report of your findings in research.md
逐步走查任务调度流程,深入理解并寻找潜在 bug。系统里肯定有 bug,因为它有时会执行本该被取消的任务。持续研究这个流程直到找出所有 bug,找不完不许停。完成后,将你的发现写成一份详尽的报告,保存到 research.md

注意措辞:“deeply”“in great details”“intricacies”“go through everything”。这些不是废话。没有这些词,Claude 就会走马观花——读一个文件,看看函数签名就知道它干嘛的,然后就跳过了。你必须明确告诉它:浅尝辄止是不可接受的。

写成文件的产物(research.md)至关重要。这不是让 Claude 做作业。这是我的审查界面。我可以阅读它,验证 Claude 是否真正理解了系统,并在任何规划发生之前纠正误解。如果调研就是错的,方案就会错,实现更会错。垃圾进,垃圾出。

AI 辅助编程中代价最高的失败模式,不是语法错误或逻辑缺陷,而是那种孤立来看能跑、但会搞坏周边系统的实现。一个函数无视了已有的缓存层;一次数据库迁移没考虑 ORM 的约定;一个 API 端点重复实现了别处已有的逻辑。调研阶段就是为了杜绝这一切。

第二阶段:规划

审阅完调研之后,我会让 Claude 在单独的 markdown 文件里写一份详细的实现方案。

I want to build a new feature <name and description> that extends the system to perform <business outcome>. write a detailed plan.md document outlining how to implement this. include code snippets
我想构建一个新功能〈名称和描述〉,扩展系统以实现〈业务目标〉。写一份详细的 plan.md 文档,说明如何实现。包含代码片段

the list endpoint should support cursor-based pagination instead of offset. write a detailed plan.md for how to achieve this. read source files before suggesting changes, base the plan on the actual codebase
列表接口应该支持基于游标的分页而不是偏移量分页。写一份详细的 plan.md 说明如何实现。在提出修改建议之前先阅读源文件,方案要基于实际代码库

生成的方案总是包含:方法的详细说明、展示具体修改的代码片段、将被修改的文件路径,以及注意事项和权衡取舍。

我使用自己的 .md 方案文件,而不是 Claude Code 内置的方案模式(plan mode)。内置的方案模式太烂了。我的 markdown 文件让我拥有完全的掌控力。我可以在编辑器里编辑它、添加行内注释,而且它作为一个真正的产物持久保存在项目中。

我经常用的一个技巧: 对于那些边界明确的功能,如果我在某个开源项目中见过好的实现,我会把那段代码作为参考和方案请求一起发给 Claude。比如我想添加可排序 ID,我就把某个项目中做得好的 ID 生成代码贴过去,然后说”这是他们实现可排序 ID 的方式,写一个 plan.md 说明我们如何采用类似的方案。“当 Claude 有一个具体的参考实现可以依据时,效果比让它从零设计要好得多。

但方案文档本身并不是最有意思的部分。真正有意思的是接下来发生的事。

注释循环

这是我工作流中最与众不同的环节,也是我个人价值发挥最大的地方。

graph TD
    A[Claude 撰写 plan.md] --> B[我在编辑器中审阅]
    B --> C[我添加行内注释]
    C --> D[让 Claude 回到文档]
    D --> E[Claude 更新方案]
    E --> F{满意了吗?}
    F -->|否| B
    F -->|是| G[生成任务清单]

Claude 写好方案后,我会在编辑器里打开它,直接在文档中添加行内注释。这些注释用来纠正假设、否决方案、添加约束条件,或者提供 Claude 不具备的领域知识。

注释的长度差异极大。有时一条注释就两个词:在 Claude 标记为可选的参数旁边写上”not optional(非可选)“。有时则是一整段话,解释某个业务约束,或者贴一段代码片段展示我期望的数据结构。

以下是我会添加的一些真实注释示例:

  • “use drizzle:generate for migrations, not raw SQL” —— Claude 不具备的领域知识
  • “no — this should be a PATCH, not a PUT” —— 纠正错误假设
  • “remove this section entirely, we don’t need caching here” —— 否决提议的方案
  • “the queue consumer already handles retries, so this retry logic is redundant. remove it and just let it fail” —— 解释为什么需要改动
  • “this is wrong, the visibility field needs to be on the list itself, not on individual items. when a list is public, all items are public. restructure the schema section accordingly” —— 重新定向方案的整个章节

然后我把 Claude 引导回文档:

I added a few notes to the document, address all the notes and update the document accordingly. don’t implement yet
我在文档里添加了一些注释,逐一处理所有注释并相应更新文档。先不要实现

这个循环会重复 1 到 6 次。 明确写出 “don’t implement yet”(先不要实现) 这道护栏至关重要。没有它,Claude 一觉得方案差不多了就会直接开始写代码。差不多可不行——我说行才行。

为什么这套方法如此有效

markdown 文件充当了我和 Claude 之间的共享可变状态(shared mutable state)。我可以按自己的节奏思考,精确标注出哪里有问题,然后重新介入而不丢失上下文。我不需要在聊天消息里解释所有东西。我是直接指向文档中的确切位置,把修正意见写在那里。

这跟试图通过聊天消息来引导实现有本质区别。方案是一份结构化的、完整的规格说明,我可以整体审阅。聊天对话则需要我翻来翻去才能还原决策过程。方案完胜,每一次。

三轮”我加了注释,更新方案”就能把一份泛泛的实现方案打磨成与现有系统完美契合的方案。Claude 擅长理解代码、提出解决方案、编写实现。但它不了解我的产品优先级、用户痛点,也不清楚我愿意做出哪些工程取舍。注释循环(annotation cycle)就是我注入这些判断力的通道。

任务清单

在开始实现之前,我总是要求一份细粒度的任务拆解:

add a detailed todo list to the plan, with all the phases and individual tasks necessary to complete the plan - don’t implement yet
在方案中添加一份详细的任务清单,列出完成方案所需的所有阶段和各项任务——先不要实现

这会生成一份检查清单,在实现过程中充当进度追踪器。Claude 在推进时会逐项勾选完成状态,所以我随时瞄一眼方案就能知道进展到哪了。在持续数小时的会话中尤其有用。

第三阶段:实现

方案就绪后,我发出实现指令。这条提示词我已经打磨成标准模板,跨会话复用:

implement it all. when you’re done with a task or phase, mark it as completed in the plan document. do not stop until all tasks and phases are completed. do not add unnecessary comments or jsdocs, do not use any or unknown types. continuously run typecheck to make sure you’re not introducing new issues.
全部实现。每完成一个任务或阶段,在方案文档中标记为已完成。所有任务和阶段全部完成之前不要停。不要添加不必要的注释或 JSDoc,不要使用 any 或 unknown 类型。持续运行类型检查,确保不引入新问题。

这一条提示词编码了所有关键要求:

  • “implement it all”:执行方案中的全部内容,不要挑着来
  • “mark it as completed in the plan document”:方案是进度的唯一真实来源
  • “do not stop until all tasks and phases are completed”:流程中途不要暂停等确认
  • “do not add unnecessary comments or jsdocs”:保持代码干净
  • “do not use any or unknown types”:维持严格类型
  • “continuously run typecheck”:尽早发现问题,不要攒到最后

几乎每次实现会话我都用这套原话(只做微调)。等我说出”implement it all”的时候,所有决策都已经做完并验证过了。实现变成了机械操作而非创造性工作。这是刻意为之的。我就是要让实现变得无聊。 创造性的工作已经在注释循环中完成了。方案一旦对了,执行就该是波澜不惊的。

没有规划阶段的话,通常会发生这种事:Claude 在早期做了一个看似合理但实际错误的假设,然后在上面构建了 15 分钟,最后我不得不回滚一连串的改动。“don’t implement yet”这道护栏彻底消除了这个问题。

一旦 Claude 开始执行方案,我的角色就从架构师变为监工。我的提示词变得极其简短。

graph TD
    A[Claude 执行实现] --> B[我审阅 / 测试]
    B --> C{正确吗?}
    C -->|否| D[简短纠正]
    D --> A
    C -->|是| E{还有任务吗?}
    E -->|是| A
    E -->|否| F[完成]

规划阶段的注释可能是一整段话,而实现阶段的纠正往往就一句话:

  • “You didn’t implement the deduplicateByTitle function.” —— 你没实现 deduplicateByTitle 函数。
  • “You built the settings page in the main app when it should be in the admin app, move it.” —— 你把设置页面建在了主应用里,应该在管理后台,挪过去。

Claude 已经拥有方案的完整上下文和当前会话的所有信息,所以简短的纠正就足够了。

前端工作是迭代最频繁的部分。我在浏览器中测试,然后快速甩出修正指令:

  • “wider” —— 再宽点
  • “still cropped” —— 还是被裁了
  • “there’s a 2px gap” —— 有 2px 间隙

遇到视觉问题,我有时会直接贴截图。一张表格对不齐的截图,比文字描述传达问题快得多。

我还会不断引用已有代码:

  • “this table should look exactly like the users table, same header, same pagination, same row density.” —— 这个表格应该跟用户表一模一样,同样的表头、同样的分页、同样的行密度。

这比从零描述一个设计精确得多。成熟代码库中的大多数功能都是已有模式的变体。新的设置页面应该长得跟现有的设置页面一样。指向参考就传达了所有隐含的需求,不用逐条列出。Claude 通常会在做修正之前先阅读参考文件。

当事情走歪了,我不会试图修补。我直接回滚,然后重新界定范围,丢弃 git 变更:

  • “I reverted everything. Now all I want is to make the list view more minimal — nothing else.” —— 我全部回滚了。现在我只想让列表视图更简洁——别的什么都不做。

回滚之后收窄范围,几乎总是比试图渐进式修复一个走偏的方案效果更好。

始终掌握主导权

虽然我把执行交给了 Claude,但我从不给它完全的自主权来决定构建什么。绝大部分主动引导都发生在 plan.md 文档中。

这很重要,因为 Claude 有时会提出技术上正确但对项目来说是错误的方案。也许方案过度工程化了,或者它改了一个公共 API 签名而系统其他部分依赖它,或者明明有更简单的选择它偏偏挑了更复杂的。我掌握着 Claude 没有的更宏观的上下文——系统全局、产品方向和工程文化。

graph TD
    A[Claude 提出修改建议] --> B[我逐项评估]
    B --> C[照单全收]
    B --> D[调整方案]
    B --> E[跳过 / 删除]
    B --> F[覆盖技术选型]
    C --> G[精炼后的实现范围]
    D --> G
    E --> G
    F --> G

从建议中精挑细选: 当 Claude 识别出多个问题时,我会逐个过一遍:“第一个,直接用 Promise.all 就行,别搞那么复杂;第三个,提取成单独的函数提高可读性;第四和第五个忽略,不值得增加复杂度。” 我根据自己对当前优先级的了解逐项做决定。

砍掉范围: 当方案里包含了锦上添花的功能时,我会主动砍掉。“把下载功能从方案里去掉,我现在不想做这个。” 这能防止范围蔓延(scope creep)。

保护已有接口: 当我知道某些东西不该动时,我会设定硬性约束:“这三个函数的签名不能变,应该是调用方去适配,而不是库来改。”

覆盖技术选型: 有时我有特定的偏好是 Claude 不可能知道的:“用这个模型替代那个” 或者 “用这个库的内置方法,别手写一个。” 快速、直接的覆盖。

Claude 负责机械执行,我来做判断决策。方案在前期锁定了重大决策,而选择性的指导则处理实现过程中浮现的细节问题。

单次长会话

我把调研、规划和实现放在同一个长会话中完成,而不是拆分到多个会话里。一次会话可能从深度阅读一个文件夹开始,经过三轮方案注释,然后执行完整的实现——全部在一次连续对话中完成。

我倒没碰到大家说的上下文窗口(context window)用到 50% 之后性能下降的问题。实际上,等我说出”implement it all”的时候,Claude 已经花了整个会话在构建理解:调研阶段阅读文件,注释循环中打磨心智模型,吸收我的领域知识纠正。

当上下文窗口满了,Claude 的自动压缩(auto-compaction)会保留足够的上下文继续推进。而方案文档——那个持久化的产物——能完整地保留下来,不受压缩影响。我随时可以把 Claude 指回去。

一句话总结工作流

深入阅读,撰写方案,反复注释直到方案正确,然后让 Claude 一口气执行到底,期间持续做类型检查。

就这样。没有神奇的提示词,没有精心设计的系统指令,没有聪明的 hack。只是一套有纪律的流水线,把思考和打字分离开来。调研阶段防止 Claude 做出无知的改动。方案阶段防止它做出错误的改动。注释循环注入我的判断力。而实现指令让它在所有决策完成后不间断地执行。

试试我的工作流吧,你会想不通以前没有一份标注过的方案文档、你到底是怎么用 AI 智能体(AI Agent)写出能交付的代码的。

我还在做 nominal.dev,因为 2026 年了,不该有人还在值班(on-call)。

相关笔记