AI 编程真正要控制的不是代码,而是上下文
我日常使用 Claude Code 和 Codex 进行 AI 辅助开发。刚开始,我的方式更接近 Vibe Coding:给 AI 一个需求,让它先写,写错了再改,改不动了再补充解释。
这种方式在简单任务上很快,但在真实项目里很容易失控。
因为真实开发不是“生成一段代码”,而是要同时处理业务语义、项目结构、团队规范、历史包袱、权限边界、异常流程、测试验证和后续维护。
AI 写代码并不难。
真正难的是:让 AI 在正确的上下文里写正确的代码。
AI Coding 的关键不是提示词写得多漂亮,也不是模型能力有多强,而是能不能把一次随缘对话,改造成一套可控的开发流程。
这就是我理解的 Spec Coding。
AI 不是不知道怎么写代码,而是不知道你没告诉它什么
大模型单次推理本身是无状态的。Claude Code、Codex 这类工具每次请求模型时,都会重新组装上下文:系统提示词、项目规则、当前对话历史、文件内容、命令输出、错误日志,以及用户当前输入。
所以,AI 看到什么,它才基于什么推理。
你没告诉它的项目规范,在它那里默认不存在。
你没告诉它的业务边界,它只能按通用经验猜。
你没告诉它的历史决策,它可能会把必要的妥协当成坏味道重构掉。
你没告诉它不能改哪些文件,它可能为了完成任务顺手扩大改动范围。
所以,AI Coding 的第一原则不是“把需求说清楚”这么简单,而是:
你必须主动设计 AI 的工作上下文。
| 你没有提供的内容 | AI 常见表现 |
|---|---|
| 项目结构 | 自己猜目录、猜分层、猜调用关系 |
| 编码规范 | 使用通用写法,和项目风格不一致 |
| 业务语义 | 写出表面正确但业务错误的逻辑 |
| 边界条件 | 加一堆多余兼容,或者漏掉关键限制 |
| 禁止事项 | 顺手修改无关文件,引入额外风险 |
| 验收标准 | 只保证代码看起来完成,不保证需求真的完成 |
AI 不是人类同事。它不会自动继承团队里的隐性知识。
所谓提示词,本质上就是把隐性知识显性化。
Vibe Coding 的问题,是把判断权过早交给 AI
Vibe Coding 的爽点在于快。
它适合小任务、低风险、边界清晰的修改。但一旦任务复杂,它的问题也很明显:你把太多判断权提前交给了 AI。
AI 会替你判断需求边界,替你判断实现路径,替你判断是否需要重构,替你判断字段怎么设计,替你判断异常怎么兼容。
问题是,这些判断恰恰是开发中最值钱的部分。
| 开发阶段 | 不该完全交给 AI 的判断 |
|---|---|
| 需求阶段 | 这个功能到底解决什么问题 |
| 设计阶段 | 哪些边界必须处理,哪些暂时不处理 |
| 实现阶段 | 哪些文件可以改,哪些文件不能动 |
| 重构阶段 | 当前是坏设计,还是历史约束 |
| 测试阶段 | 怎样才算真的完成,而不是刚好能跑 |
| 沉淀阶段 | 哪些经验值得写入项目上下文 |
AI 适合执行明确任务,不适合替你承担所有取舍。
Spec Coding 的意义,就是在人类还掌握判断权的时候,先把需求、边界、计划和验收标准固定下来,再让 AI 进入执行阶段。
Spec Coding:先定义,再生成
我现在越来越少直接对 AI 说“帮我实现这个功能”。
我更倾向于把开发拆成几个阶段:
| 阶段 | 目标 | 产物 |
|---|---|---|
| Context | 让 AI 理解项目 | CLAUDE.md、CONTEXT.md |
| Spec | 让需求变清楚 | PRD、需求说明、边界条件 |
| Plan | 让实现路径可审查 | 实施计划、文件改动范围 |
| Execute | 让 AI 小步实现 | 代码、配置、接口、页面 |
| Review | 让结果可验证 | Review 结论、测试结果、问题清单 |
| Memory | 让经验可复用 | 更新 CONTEXT.md、沉淀 Skill |
这套流程的核心不是文档本身,而是控制权。
Spec 不是为了写文档而写文档。
Spec 是为了在 AI 写代码之前,先把“什么是正确”定义出来。
没有 Spec,AI 的目标是模糊的。
有了 Spec,AI 才有可对齐的对象。
CLAUDE.md 管规则,CONTEXT.md 管语义
我接手一个新项目后,第一步通常不是写业务代码,而是建立项目上下文。
CLAUDE.md 记录项目级规则。它告诉 AI:在这个项目里应该怎么做。
CONTEXT.md 记录业务级语义。它告诉 AI:这个项目到底是什么,哪些概念不能误解。
这两个文件不是越长越好,而是越清晰越好。
| 文件 | 关注点 | 典型内容 |
|---|---|---|
CLAUDE.md | 行为约束 | 技术栈、代码规范、命令规则、禁止事项、输出格式 |
CONTEXT.md | 业务理解 | 领域概念、状态流转、关键决策、历史原因、业务边界 |
| Skill | 工作流复用 | 诊断流程、PRD 流程、Review 流程、TDD 流程 |
| Hook | 强制执行 | 提交前检查、禁止危险命令、格式化、测试校验 |
我不会把所有东西都塞进 CLAUDE.md。
规则、语义、流程、强制检查,应该分层管理。
否则上下文会变成一个大杂烩,AI 表面上“看到了很多信息”,实际却抓不住重点。
复杂需求:先让 AI 盘问你,而不是直接服务你
复杂需求最危险的地方,不是 AI 不会写,而是你自己也没想清楚。
所以面对逻辑复杂、边界模糊、状态较多的需求,我会先使用类似 /docs-with-me 的流程,让 AI 反过来盘问我。
这一步的价值不只是让 AI 理解需求,更重要的是逼自己澄清需求。
| AI 追问的问题 | 背后的价值 |
|---|---|
| 这个功能的目标是什么 | 防止实现偏离业务目的 |
| 有哪些角色参与 | 明确权限边界 |
| 有哪些状态 | 明确流程模型 |
| 每个状态允许什么操作 | 防止按钮和接口乱飞 |
| 异常情况怎么处理 | 提前暴露隐藏分支 |
| 哪些字段必须新增 | 避免过度建模 |
| 哪些逻辑复用旧代码 | 降低无关改动 |
| 怎样算完成 | 建立验收标准 |
需求没有被问清楚之前,不要急着让 AI 写代码。
越早编码,越容易返工。
越晚澄清,代价越高。
Plan 模式的价值,是让错误发生在代码之前
我现在对复杂任务都会要求 AI 先写实施计划。
计划不是仪式感,而是一个提前纠偏的检查点。
因为 AI 真正危险的地方,不是代码写错一行,而是整体方向从一开始就错了。
| 审查计划时,我重点看什么 | 为什么重要 |
|---|---|
| 改哪些文件 | 控制影响范围 |
| 不改哪些文件 | 防止任务扩散 |
| 数据模型怎么设计 | 防止字段膨胀 |
| 是否复用已有实现 | 保持项目一致性 |
| 是否有多余兼容 | 避免过度工程 |
| 边界条件是否明确 | 防止上线后补洞 |
| 是否有验证方式 | 防止“看起来完成” |
| 是否符合现有风格 | 降低维护成本 |
一个错误计划,会制造一批错误代码。
一个清晰计划,能让 AI 的执行力真正变成生产力。
实施阶段:AI 负责推进,人负责方向
AI 写代码时,不要完全放手。
我会把 AI 当成一个执行力极强、但容易误解上下文的初级开发。它可以很快,但需要及时校准。
| AI 走偏的表现 | 我会怎么干预 |
|---|---|
| 开始改无关文件 | 明确限制改动范围 |
| 引入新抽象 | 要求优先沿用旧结构 |
| 过度兼容 | 删除当前需求不需要的分支 |
| 重写公共组件 | 限制只改当前模块 |
| 忽略现有风格 | 指定参考模块 |
| 一次改太多 | 要求暂停并重新列计划 |
AI Coding 不是把活扔给 AI。
AI Coding 是让 AI 推进,人类负责方向盘。
Review:让 AI 从实现者切换成审查者
AI 写完后,我不会直接相信它完成了。
我一般先人工测试,再让 AI Review。
人工测试看需求是否满足,AI Review 看代码是否存在隐藏问题。
| 阶段 | 关注点 |
|---|---|
| 人工测试 | 页面是否正常、流程是否符合预期、数据是否正确 |
| AI Review | Bug、漏洞、空指针、无关改动、重复代码、边界遗漏 |
| 单元测试 | 核心逻辑是否可重复验证 |
| 回归检查 | 是否影响已有功能 |
这里有一个关键点:
不要让同一个角色一直写。
开发阶段让 AI 做实现者。
审查阶段让 AI 做 Review 人。
诊断阶段让 AI 做问题分析师。
重构阶段让 AI 做架构顾问。
角色切换,本质上也是上下文切换。
多 Agent:不是并发写代码,而是分离职责
我在新模块开发时,会使用 Agent Team。
但我现在越来越谨慎地看待多 Agent。
多 Agent 的价值,不是“让一堆 AI 同时写代码”,而是把不同责任拆开,避免一个上下文窗口承担所有角色。
| Agent 角色 | 主要职责 |
|---|---|
| Lead Agent | 拆任务、控边界、汇总结果,不直接写代码 |
| 需求分析 Agent | 澄清需求、整理 PRD、发现歧义 |
| 前端 Agent | 页面、组件、交互、接口调用 |
| 后端 Agent | 接口、服务、数据模型、权限逻辑 |
| 测试 Agent | 测试用例、验证路径、边界检查 |
| Review Agent | 审查改动、发现风险、提出修正建议 |
多 Agent 最怕一件事:边界没定,大家同时开干。
所以在启动多 Agent 前,我会先明确:
| 必须先确定的东西 | 原因 |
|---|---|
| 模块边界 | 防止 Agent 互相踩范围 |
| 接口契约 | 防止前后端各写各的 |
| 数据模型 | 防止字段设计分裂 |
| 文件归属 | 防止 worktree 合并冲突 |
| 验收标准 | 防止每个 Agent 对完成的理解不同 |
Lead Agent 不应该是“最能干活的那个”。
Lead Agent 应该是“最少亲自动手、最多保持上下文干净的那个”。
复杂 Bug:不要在污染上下文里继续挣扎
有些 Bug,AI 一轮就能修好。
但如果一个 Bug 已经在同一个对话里反复修、反复错,我通常会开新对话。
这不是逃避,而是清理上下文污染。
旧对话里可能已经充满错误猜测、失败方案、临时补丁和无效结论。继续在里面分析,AI 很容易沿着旧错误继续推理。
| 旧上下文里的污染物 | 可能造成的问题 |
|---|---|
| 错误判断 | AI 继续沿错误方向修 |
| 失败方案 | 干扰新的诊断路径 |
| 临时补丁 | 掩盖真实原因 |
| 反复推翻的结论 | 降低推理稳定性 |
| 大量无关日志 | 稀释关键信息 |
复杂 Bug 更适合重新建模,而不是继续试错。
我会在新对话中重新提供:
| 信息 | 作用 |
|---|---|
| 错误现象 | 描述用户真正看到的问题 |
| 复现路径 | 建立问题触发条件 |
| 前端控制台 | 判断是否是页面或请求问题 |
| 后端日志 | 判断是否是服务端异常 |
| 接口参数 | 判断前后端契约是否一致 |
| 数据库表和字段 | 判断数据状态是否正确 |
| 最近改动 | 判断是否是回归问题 |
修 Bug 时,AI 的价值不只是“帮我改代码”,更重要的是“帮我扩大观察面”。
很多时候,真正的修复来自人类重新判断,而不是 AI 自动试错。
重构:没有测试保护的重构,就是赌博
当我觉得代码臃肿、结构混乱、AI 写的代码连自己都看不懂时,我会考虑重构。
但重构前,我会非常谨慎。
因为 AI 参与重构时,经常有一个问题:它太积极。
它会很乐意抽象、拆分、封装、重命名、迁移结构。问题是,真实项目里的很多“不优雅”,未必都是坏设计,也可能是历史约束、兼容逻辑、上线压力或团队习惯。
| 重构前要确认 | 为什么 |
|---|---|
| 当前问题是什么 | 防止为了重构而重构 |
| 哪些行为必须保持不变 | 防止破坏业务 |
| 是否有测试保护 | 防止改完无法验证 |
| 是否小步提交 | 方便定位问题 |
| 是否保留回退空间 | 降低风险 |
| 是否符合团队习惯 | 防止重构成个人风格 |
重构不是让代码看起来更高级。
重构是让下一次变化更容易发生。
任务完成后,应该主动清理上下文
我现在越来越认同一句话:
上下文不是越多越好。
一个任务完成后,如果要做另一个独立任务,我通常会开新对话。
旧上下文里有太多噪声:
| 噪声 | 影响 |
|---|---|
| 废弃方案 | 干扰后续判断 |
| 错误日志 | 稀释新任务重点 |
| 临时解释 | 让 AI 误以为仍然有效 |
| 无关文件 | 占用上下文窗口 |
| 失败尝试 | 诱导 AI 重复错误 |
| 旧任务目标 | 和新任务目标冲突 |
开新对话不是浪费上下文。
开新对话是给新任务一个干净的推理空间。
Skill:把一次经验变成可重复流程
如果一个提示词只用一次,它只是提示词。
如果一个流程会反复使用,它就应该沉淀成 Skill。
| 适合沉淀为 Skill 的流程 | 原因 |
|---|---|
| 复杂 Bug 诊断 | 步骤稳定,信息结构固定 |
| PRD 生成 | 需求澄清方式可复用 |
| 代码 Review | 审查维度相对固定 |
| TDD 流程 | 先测后改的节奏稳定 |
| 重构分析 | 需要固定的风险检查 |
| 上线前检查 | 清单化价值高 |
但 Skill 不是越多越好。
太多 Skill 会让 AI 犹豫,也会让项目上下文变得臃肿。
真正值得沉淀的,不是灵感,而是流程。
不是一句好提示词,而是一套可重复执行的判断链。
我现在对 AI Coding 的几个判断
| 判断 | 含义 |
|---|---|
| AI 不缺执行力,缺上下文 | 不要只催它写,要先让它理解 |
| Spec 不是文档,是控制权 | 先定义正确,再生成代码 |
| Plan 是代码前的刹车 | 让错误停在实现之前 |
| Review 是角色切换 | 不要让 AI 永远站在实现者视角 |
| 多 Agent 是职责分离 | 不是简单并发,不是人多力量大 |
| 新对话是上下文治理 | 不是从零开始,而是清理污染 |
| Skill 是流程资产 | 不是提示词收藏夹 |
| Hook 是规则落地 | 不要只相信模型会自觉遵守 |
| 测试是重构护栏 | 没有验证,重构只是赌博 |
| 人类负责判断,AI 负责推进 | 这是当前阶段最稳的分工 |
结语:AI 编程的成熟度,取决于你能控制多少不确定性
AI Coding 的早期体验,很容易让人沉迷于“生成速度”。
但用得越久,我越觉得,真正重要的不是速度,而是可控性。
Vibe Coding 解决的是“能不能快速写出来”。
Spec Coding 解决的是“能不能按明确目标写出来”。
更进一步,真实项目里的 AI Coding 还要解决:
AI 看到什么;
AI 忽略什么;
AI 遵守什么;
AI 什么时候停;
AI 写完后如何验证;
这次经验如何沉淀到下一次。
AI 编程不是把人从开发流程里拿掉。
恰恰相反,它要求人更清楚地定义流程、边界和判断标准。
未来开发者的能力,可能不只是会不会写代码,而是能不能把模糊需求转化为清晰规格,把隐性知识转化为显性上下文,把一次性经验转化为可复用流程。
AI 负责生成。
人负责定义什么值得生成。