CHAPTER 13 · 驾驭
驾驭 Coding Agent
前面十二章给了你心智模型和词汇。本章把它们组装成一套可重复的工作流:怎样把模糊的意图变成 Agent 能准确执行的规格,怎样在关键节点介入,怎样高效地审查产出。目标是让你始终掌握方向和节奏,而不是被 Agent 的输出推着走。
- 按“探索 → 规格 → 计划 → 实现 → 验证 → 审查”的流程推进一个功能,并知道在哪几个节点必须由你决定。
- 用六要素模板写出一份任务说明。
- 把一个模糊的现象描述(“页面卡”“数据不对”)翻译成准确的技术表达。
- 用一份清单在 10 分钟内审查一个 Agent 生成的 PR。
- 识别“Agent 在绕圈子”的信号,并知道此时该怎么做。
开场:两个开发者,同一个功能
A 和 B 用同一个 Agent 给 LinkNote 加“按标签筛选”。A 输入“加个标签筛选功能”,然后花了两个小时来回修改:Agent 先用 useState 实现,A 说刷新后筛选丢了;Agent 改用 localStorage,A 说分享链接时别人看不到筛选;Agent 改成 URL 参数,但顺手重构了列表组件,把分页弄坏了……B 先花 15 分钟写了一份说明,Agent 一次完成,测试全部通过。B 做对了什么?
答案方向:A 在用“试错”的方式让 Agent 猜自己的需求,每轮只暴露一条隐含的要求;B 在动手之前,把隐含的要求都说了出来:筛选状态放 URL(可分享、可刷新)、不要改动分页、完成标准是什么。Agent 执行能力很强,但它无法读出你没说出来的要求。B 那 15 分钟不是“写文档”,而是设计——这正是你在 Agent 时代的核心工作。
工作流全景
① 探索:先让 Agent 调查,别急着动手
对于不熟悉的代码或复杂的改动,第一条指令应该是“调查并报告”,而不是“实现”。例如:“列表页的数据是怎么加载的?筛选和分页的状态分别存在哪里?只读代码,不要修改,给我一份简短的报告。”这一步便宜,而且能暴露你自己的错误假设。
② 规格:你的核心产出
见下一节的六要素模板。
③ 计划:在最便宜的时候否决错误方向
让 Agent 在写代码前给出计划(很多工具有专门的“计划模式”)。审查计划比审查代码便宜十倍。看计划时问:
- 它打算修改的文件,和我预期的一致吗?有没有超出范围的改动?
- 有没有数据模型变化、新依赖、数据库迁移?这些需要我特别确认。
- 安全相关的部分(鉴权、校验)有没有考虑?
- 测试计划是什么?怎么证明它做完了?
④ 实现:小步、可验证、可提交
把工作切成纵向的薄片:每一片都是端到端可运行的最小功能(例如“先让 URL 参数能过滤列表,暂不做界面”),而不是“先写完所有数据库代码,再写所有接口,再写所有界面”。每一片完成后运行检查并提交。出问题时只需要回退一小步。
⑤ 验证:让机器先把关
第 10 章的完成定义在这里发挥作用:类型检查、Lint、测试全部通过,Agent 才能说“完成”。涉及界面时,打开预览链接亲手点一遍——这是任何自动化都替代不了的。
⑥ 审查 → ⑦ 合并 → ⑧ 沉淀
审查方法见后文。合并后,花一分钟问自己:这次有什么是我不得不反复告诉 Agent 的?把它写进 AGENTS.md 或变成测试 / Lint 规则。每一次纠正都应该只发生一次。
任务说明的六要素
| 要素 | 回答的问题 | 缺失时的典型后果 |
|---|---|---|
| 1. 目标与背景 | 为什么做?给谁用? | 技术上正确但解决的不是真正的问题 |
| 2. 范围 | 做什么,明确不做什么 | Agent 顺手“优化”了无关代码 |
| 3. 约束 | 必须用 / 不许用的技术、模式、依赖 | 引入新库、换了状态管理方式、关掉了严格检查 |
| 4. 接口与数据 | 数据长什么样、存在哪、接口签名 | 数据模型每次都不一样,前后端对不上 |
| 5. 验收标准 | 怎样算完成?(可执行、可观察) | “看起来能用”,边界情况全漏 |
| 6. 交付物 | 要交回什么:代码、测试、说明、截图 | 不知道改了什么、怎么验证 |
写这样一份说明需要 10~15 分钟。它迫使你自己先想清楚:状态放哪里、在哪一层过滤、边界情况有哪些。这些决策如果留给 Agent 隐式地做,就会出现开场问题中 A 的两小时。
写不出验收标准,往往说明你自己还没想清楚要什么。这时可以反过来让 Agent 帮你:“我想做标签筛选。请向我提问,帮我澄清需求,每次只问一个问题,最后整理成任务说明。”这是用 Agent 做需求分析,而不是直接让它猜。
精确表达:从现象到术语
你观察到的往往是“现象”,而 Agent 需要的是“诊断方向”。下表把常见的模糊描述映射到前面章节中的精确表达。熟练使用这些词,是驾驭 Agent 最直接的杠杆:
| 你看到的现象 | 可能的精确表达 | 章节 |
|---|---|---|
| 页面一直在重复请求接口 | useEffect 依赖了不稳定的引用,形成“渲染 → Effect → setState”循环 | 06 |
| 改了数据,界面没变 | 直接修改了 state 对象(mutation),引用未变;应使用不可变更新 | 03 / 06 |
| 刷新后筛选 / 分页丢了 | 该状态应该放在 URL 查询参数中,而不是组件局部状态 | 06 |
| 搜索结果和输入框对不上 | 请求竞态:旧请求晚于新请求返回;需要取消或按 key 丢弃过期结果 | 06 |
| 同一个数据在两个地方显示不一致 | 存了派生状态 / 缺少单一事实来源;或者缓存没有失效(invalidate) | 06 / 08 |
| 页面第一次打开很慢 | 首屏 JS 体积过大 / 请求瀑布 / 应改为服务端渲染或流式渲染 | 07 |
| 页面先显示一种内容,又闪成另一种 | 水合不匹配 / 客户端二次获取数据 | 07 |
| 别人能看到或删除我的数据 | 缺少授权检查(IDOR);授权条件应写入查询 | 08 |
| 接口在浏览器报错,curl 正常 | CORS:需声明允许的来源和 credentials,或改为同源 | 05 |
| 部署后偶尔丢数据或计数不准 | 在 serverless 实例内存中保存了共享状态 | 09 |
| 高峰期数据库报连接过多 | serverless 下连接数爆炸;需要连接池代理或 HTTP 驱动 | 08 |
| 批量处理“提前结束” | forEach(async) 未等待;或漂浮的 Promise | 03 |
| AI 回答要等很久才出来 | 未使用流式输出;首 token 时间(TTFT)过长 | 11 |
| AI 返回的数据格式时对时错 | 缺少结构化输出与 schema 校验 | 11 |
| Agent 越改越乱、反复犯错 | 上下文过长或被污染;应写入进度文件后开新会话 | 12 |
注意“可能的”三个字。这些表达是假设,不是结论。好的做法是把现象和你的假设一起告诉 Agent,并要求它先验证:“我怀疑是请求竞态,请先加日志确认请求的发出和返回顺序,再修复。”
审查 Agent 的产出
审查设计方案
当 Agent 给出设计文档或技术方案时,重点不是文字是否漂亮,而是:
- 需求覆盖:每条验收标准都有对应的实现方式吗?
- 数据模型:新增的表 / 字段是否合理?将来要改是否很痛苦?
- 失败模式:网络失败、LLM 超时、重复提交、并发修改时会怎样?
- 备选方案:它考虑过哪些其他做法?为什么不选?——如果没有,就追问:“给我两个备选方案和取舍。”
- 过度设计:是否为假想的未来需求引入了抽象层、插件系统、通用框架?
审查代码:10 分钟清单
不要从第一个文件开始逐行读。按信息密度从高到低的顺序:
- 看改动范围:修改的文件列表是否符合预期?有没有碰了说明里“不做”的部分?
- 看数据结构:schema、类型定义、Zod schema、数据库迁移。这些决定了其余代码的形状。
- 看测试:测试是否覆盖了验收标准?已有测试有没有被修改(第 10 章)?
- 看边界:外部输入有没有校验?授权条件在不在?密钥有没有进入客户端代码?
- 搜危险信号:
any、as、!、@ts-ignore、eslint-disable、空的catch、新增的依赖、useEffect。 - 最后看核心逻辑:此时你已经知道它应该长什么样,读起来会快得多。
可以开一个新的会话(或子 Agent),只给它任务说明和 diff,让它按上面的清单找问题。它没有被实现过程的上下文“说服”,常常能发现写代码的那个会话看不到的问题。但最终判断仍由你做。
掌控节奏
什么时候介入
- 同一个问题尝试了 3 次仍未解决:停下来。不要说“再试一次”。要求 Agent 列出假设和证据,或者你亲自看一眼报错。继续让它猜,只会让上下文越来越乱。
- 它开始修改说明范围之外的东西:立即指出,并要求回退。
- 它提出要关闭检查、跳过测试、加依赖:这些都需要你的明确批准。
- diff 大到你不想读:说明任务切得太大了。回退,切小再来。
调试时的协作方式
关键点:给证据,要假设,先验证后修改。这把 Agent 从“猜一个修复方案”转变为“做一次小型的科学实验”。
什么时候自己动手
一行就能改好的配置、你已经清楚知道怎么修的小 bug、需要审美判断的界面微调——自己改往往比描述给 Agent 更快。Agent 不是必须用于每一件事。
并行
熟练之后,可以同时运行多个 Agent 处理相互独立的任务(例如一个写功能、一个补测试、一个调查性能问题),每个任务使用独立的 git worktree 或分支。前提是任务之间真的独立,并且你有精力审查所有产出——并行的瓶颈永远是你的审查能力。
AGENTS.md 的进阶写法
- 短而具体:它在每次会话中都会占用上下文。写“用 pnpm”,而不是一段关于包管理器的论述。
- 写 Agent 猜不到的东西:项目特有的约定、踩过的坑、禁止事项。框架的通用知识不需要写。
- 指向而非复制:“数据库约定见 docs/db.md”,让 Agent 需要时再读。
- 分层:根目录放全局约定;子目录(如
apps/api/AGENTS.md)放局部约定。 - 持续维护:它是一份活文档。每次发现自己重复纠正,就更新它;发现某条过时了,就删掉。
工具之间的差异 知道
Claude Code、Codex CLI、pi、Cursor、各类 IDE Agent 的底层原理相同(第 12 章),本章的方法对它们都适用。差异主要在 Harness 的设计取向:有的提供丰富的内置能力(计划模式、子 Agent、Hooks、插件市场、云端运行),有的刻意极简、让你用扩展自行组装。选择时关注:它是否支持你的模型、项目说明文件的约定、权限控制粒度、能否无人值守地运行(用于 CI 或批量任务)、以及你是否喜欢它的交互方式。不必追逐每一个新工具——工作流和表达能力才是可迁移的资产。
反模式
| 反模式 | 为什么有害 | 替代做法 |
|---|---|---|
| 不读代码,只看效果 | 安全漏洞、数据模型问题在界面上看不出来 | 至少按清单审查数据结构、测试和边界 |
| “修复所有报错” | Agent 会用最快的方式让报错消失(any、as、ignore) | 加约束:不许用哪些逃生舱;先解释再修 |
| 一个会话做一整天 | 上下文腐化,后期质量下降 | 一个任务一个会话,进度写入文件 |
| 一次性给出巨大需求 | 计划模糊,diff 巨大,无法审查 | 纵向切片,每片可验证 |
| 让 Agent 默默做架构决策 | 状态放哪、在哪层过滤、用什么库——这些决定会长期影响项目 | 在规格里写明,或在计划阶段审批 |
| 先搭完美的工具链再开始做产品 | 把时间花在准备上而不是交付上 | 先做出最小可用版本并上线,遇到真实问题再补工具 |
这个问题在 2026 年的面试中非常常见。好的回答不是“我用 X 工具,效率提高了多少”,而是展示你的工作方法和判断力:
- 先写规格和验收标准,再让 Agent 实现;复杂任务先审查计划。
- 用类型检查、测试和 CI 作为自动验证网,而不是逐行阅读。
- 审查的重点:数据模型、授权与校验、测试是否被修改、新增依赖。
- 举一个你发现 Agent 犯了隐蔽错误的例子(例如 IDOR 或 Effect 循环),说明你是怎么发现的。
- 说明你把重复出现的纠正沉淀为项目说明、Hook 或 Lint 规则。
自检
1. 把下面这句需求改写成符合六要素的任务说明(可以简写):“给 LinkNote 加个导出功能。”
参考要点:目标(用户想备份或迁移收藏);范围(导出当前用户全部收藏为 JSON 和 Markdown;不做导入、不做定时导出);约束(服务器端生成,流式下载避免大数据量内存问题;不新增依赖);数据(包含 url、title、summary、tags、createdAt,不包含内部 id 和 userId);验收(1000 条收藏导出不超时;只能导出自己的数据;文件名包含日期;有测试);交付(先给计划)。
重点不在于答案完全一致,而在于你是否主动想到了“不做什么”、授权、数据量和验证方式。
2. Agent 已经三次尝试修复一个“列表偶尔显示旧数据”的 bug,每次都说“已修复”,但问题仍会出现。你下一条消息应该怎么写?
停止让它继续尝试修复。可以这样写:“先不要修改代码。请列出至少三个可能导致列表显示旧数据的原因(例如缓存未失效、请求竞态、服务器缓存),说明每个原因如何用日志或测试验证。然后添加日志,给我复现步骤,我们根据证据确定原因后再修。”如果会话已经很长,先让它把目前的发现写入文件,再开新会话。
3. Agent 提交的 PR 修改了 23 个文件,其中 15 个是“顺便做的代码风格统一”。你怎么处理?
要求拆分:把风格调整移出这个 PR(或直接撤销),只保留与功能相关的修改。混在一起的 diff 会掩盖真正的逻辑改动,让审查变得困难,也会增加冲突和回滚的成本。然后在 AGENTS.md 里加一条:“不要修改任务范围以外的文件;格式化交给格式化工具。”