# 从 Vibe Coding 到工程化 AI Coding：如何让 AI 写代码更可靠？


![从 Vibe Coding 到工程化 AI Coding：如何让 AI 写代码更可靠？](https://img.lixueduan.com/ai/cover/vibe-coding-engineered-ai-coding-v2.jpg)

让 Agent 修一个 Bug，它可能很快就给出修改，还附上一句“测试通过”。接下来要做的事情却不少：看它改了哪些文件，核对运行过的测试，确认原来的行为有没有受到影响。

如果任务做到一半需要换一个 Session，还得留下当前进度。代码可以从 Git 里找到，但方案为什么这样定、哪个问题还没解决，需要另外记录。

这篇文章就从这些环节展开，讨论需求怎么写、代码该让 Agent 看哪些，以及改完以后怎么验收。

<!--more-->

## 理解 Vibe Coding

### 什么是 Vibe Coding

Andrej Karpathy 最初提出 Vibe Coding 时，描述的是一种跟着 AI 生成结果不断尝试的开发方式：用自然语言提出要求，运行代码，遇到问题再让 AI 修改，过程中未必逐行审查代码。

现在这个词也常被用来泛指通过自然语言让 AI 辅助编程。本文讨论的范围更具体：在已有项目中使用 Coding Agent，由它阅读仓库、分析问题、修改文件和运行测试，开发者负责检查方案和结果。

比如前面说的修 Bug，第一版代码很快就能拿到。接下来花多少时间，要看它有没有找对原因、测试是否覆盖了出问题的场景，以及修改后是否需要返工。

### 代码写出来以后，还要处理什么

实际使用中，麻烦往往不是 AI 完全写不出代码，而是这些修改很难直接交付。比如，本来只想修一个 Bug，它却顺手重构了几个模块，甚至引入新依赖、改变公共接口；测试虽然通过，业务行为却不符合要求。

任务一长，还可能出现另一类问题：早期约束被遗漏，已经否决的方案又被拿出来，实际执行失败却被总结成“已完成”。到最后，连人自己也得重新翻记录，才能弄清楚当前改到了哪里。

等代码写完才追问这些问题，可能已经需要返工了。所以，任务开始前就要说清楚预期结果和修改范围，提供相关代码；开发过程中检查变更、执行验证，并留下确认过的决策和未完成项。

### 开发者与 Agent 如何分工

拿修 Bug 来说，开发者要先划定范围。如果现有接口必须保留，就提前说明；Agent 提议改变接口时，也得由开发者决定是否接受。

Agent 可以去读代码、找原因，给出方案后完成修改和补测试。开发者重点看方案是否合适，以及最后究竟改了什么。

验收还要看执行结果。项目要求的构建、测试、Lint，以及类型、Schema 等检查，都应留下记录。这些结果供开发者审查，也可以作为进入下一阶段或合并代码的必要条件。

![开发者、Agent 与工具的职责及验证门禁](https://img.lixueduan.com/ai/vibe-coding/vibe-coding-responsibilities.png)

## 先把 Spec 定义清楚，再让 AI 动手

“增加重试”听起来是个明确的任务。交给 AI 时，可能就只写了这一句：

> 帮我给这个功能增加重试机制。

Agent 接下来仍有不少事情需要确认。是所有错误都重试，还是只处理临时错误？能否加依赖？现有接口能不能动？如果这些要求都没写，它就可能按自己的理解实现。

我会先把任务写成一份简短的 Spec。Goal 写要修复的问题，Scope 划定修改范围，Constraints 留下不能违反的约定。最后补上 Acceptance Criteria 和 Verification，分别写预期结果和检查方法。

![Spec 的五个要素：Goal、Scope、Constraints、Acceptance Criteria 与 Verification](https://img.lixueduan.com/ai/vibe-coding/spec-five-elements.jpg)

这最后两项要分开写。“API 恢复后，资源最终达到期望状态”是一条验收标准；“用集成测试复现临时错误和恢复过程”才是验证方法。只写前一句，改完以后仍然缺少检查依据。

### 把模糊需求写成可验收的 Spec

假设一个 Controller 遇到临时 Kubernetes API 错误后，资源一直没有恢复。可以把任务写成下面这样：

```text
Goal:
修复 Controller 在临时 API 错误后无法正常恢复的问题。

Scope:
- 检查并修改相关 Reconciler
- 补充对应测试

Constraints:
- 不修改 CRD Schema 和现有公共接口
- 优先复用项目已有的错误处理与重试机制
- 不引入新的重试框架
- 保持 Reconcile 幂等

Acceptance Criteria:
- 临时错误不会被误判为调谐成功
- API 恢复后，资源最终达到期望状态
- 重复调谐不会创建重复资源

Verification:
- 单元测试：验证临时错误的处理和返回行为
- 集成测试：运行实际调谐循环，验证临时错误恢复后资源能够收敛
- 幂等性测试：验证重复调谐不会创建重复资源
- 执行项目规定的 Build / Test / Lint 检查
```

这份 Spec 把目标写成了“恢复正常”，没有指定要新增一套重试代码。按照 controller-runtime 的接口约定，`Reconcile` 返回非终止性错误时，会触发退避重入队。Agent 应先检查现有实现，找出恢复过程断在了哪里，具体行为以项目实际依赖版本为准。

“不修改 CRD Schema”这样的限制，现在就能写清楚。至于要改哪段逻辑，等读过代码再讨论。

### 复杂任务先看 Plan

如果问题牵涉几个模块，我会先让 Agent 读代码，把准备怎么改写出来。这一步就是 Plan：在文件还没变动时，先看它有没有找对问题，确认方案后再动手。

工具有 Plan Mode 就直接用，也可以在任务里加上这段要求：

```text
先不要修改代码。

阅读相关实现后给出 Plan：
1. 当前逻辑是什么
2. 准备采用什么方案，为什么
3. 需要修改哪些文件
4. 有哪些假设、风险，以及对现有行为的影响
5. 准备如何验证
```

比如上面的恢复问题，如果 Plan 要求修改 CRD Schema，就需要追问：恢复调谐为什么必须改变资源定义？这个理由说不清楚，就先调整方案。等多个文件都改完，再找出哪些改动是多余的，会更费力。

改错别字这类小任务就可以省掉 Plan。问题和修改位置都清楚，再写一遍计划帮助不大。

读代码后发现需求有误，也应回头更新 Spec。例如，已有机制就能完成重试，任务可能只需要修正错误处理，不必继续按“新增机制”的方向做。

## 管理 Context：让 AI 读到相关代码和项目约定

Spec 说明了资源应该恢复，却没有告诉 Agent 项目里有哪些现成代码可用。它如果没读过相邻的 Controller，就可能另写一个 retry helper，错误日志和测试写法也与项目里其他地方不同。

先找到相关实现和测试，看看现有逻辑怎样处理这类错误，再决定怎么改。

### 项目级 Context：把长期规则写下来

每次修 Bug 都重新解释项目怎么构建、接口能不能改，很容易遗漏。可以把这些约定放进工具支持的规则文件，比如 `AGENTS.md`、`CLAUDE.md` 或 Project Rules。

优先写清构建和测试命令、项目特有的约定，以及不能随意修改的区域。技术栈和目录用途简要说明即可，不必把仓库概述再写一遍。

下面是一份 Go Controller 项目的简短示例，命令需要按项目实际情况调整：

```markdown
# Project

This is a Go project based on Kubernetes controller-runtime.

## Commands

- `make build`
- `make test`
- `make lint`

## Conventions

- Follow existing controller/reconciler patterns.
- Keep public APIs backward compatible.
- Add tests for new reconciliation logic.
- Run gofmt on modified Go files.

## Restrictions

- Do not modify CRD APIs unless explicitly requested.
- Do not update dependencies without explicit approval.
```

长文档可以只列路径，并说明什么时候需要阅读。比如改资源接口前先看兼容性约定，改调谐逻辑前先看模块设计。发现说明与代码不一致时，要更新对应文档，否则下一个任务还会碰到同样的误导。

规则文件也不是越长越好。《Evaluating AGENTS.md》 在所测任务与 Agent 中，没有发现仓库上下文文件普遍提高任务成功率，还观察到了推理成本增加。这不等于规则文件没用，但值得逐条检查：这条说明能减少什么具体错误，还是只增加了需要阅读的内容？

### 任务级 Context：告诉 AI 这次应该看什么

到了这次恢复问题，可以进一步指出要读的 Controller 和测试文件。如果另一个 Controller 已有合适的错误处理方式，也把它列出来，说明参考哪一部分：

```text
先阅读：
internal/controller/foo_controller.go
internal/controller/foo_controller_test.go

另外参考：
internal/controller/bar_controller.go

其中 bar_controller.go 的错误处理和 Event 记录方式
可以作为本次实现参考。
```

参考前，也要确认这份实现仍然适用。旧代码可能有历史限制，不能照搬到新任务里。涉及多个模块时，还需要沿调用关系查看相关逻辑，不能只读一个文件就决定怎么改。

### 一个任务尽量保持一个干净的 Context

除了提供相关信息，还要避免无关内容干扰 Agent。

如果在同一个 Session 中连续处理新功能、Bug 修复和重构等互不相关的任务，之前的临时方案、错误假设和调试记录可能继续留在上下文中，影响后续判断。

对于相对独立的任务，我更倾向于开启新的 Session，让 Agent 从当前任务需要的信息开始，而不是在一段越来越长的对话中不断追加新需求。

### 不要让 Session 成为唯一的事实源

任务做到一半换 Session，最容易丢失的往往是“为什么决定这样改”和“还有哪项没检查”。这些信息需要另有记录。

确认过的需求和决策放进 Spec 或项目文档，代码变更由 Git 保存；当前进度、失败检查和下一步操作，另留一份任务记录。后面的 Workflow State 小节会给出一个模板。

为了便于管理，可以把这些信息分成项目规则、任务参考资料和需要持续保存的决策与进度。下面这张图展示的是本文的组织方式，不是必须采用的标准分层。

![项目规则、任务参考资料与持久化记录：Project Context、Task Context 与 Durable State](https://img.lixueduan.com/ai/vibe-coding/three-layer-context-model.jpg)

## Verify + Review：AI 说“完成了”，不代表真的完成了

代码改完，Agent 可能会在回复里写：

> Implementation completed. All tests passed. No breaking changes.

这时可以打开执行记录，把实际运行的命令与项目要求对一下。如果只跑了一个测试文件，“All tests passed”就只能说明这次运行的测试通过了。命令中途退出、测试被跳过，也需要单独记录。

接着按 Spec 查看 Diff 和测试内容。恢复问题有没有对应测试，修改是否涉及无关模块，都能在这里核对。缺少执行记录或测试没有覆盖的验收项，先记为未验证，不能靠这句总结补上。

### 从验收标准到实际验证

前面的 Controller 测试，要从临时 API 错误开始，检查错误怎样返回，再观察 API 恢复后资源能否继续调谐。还要重复执行调谐，确认没有创建重复资源。只测错误返回，无法覆盖整个恢复过程。

这里有个容易漏掉的区别：**测试代码手动再次调用 `Reconcile` 后成功，不等于 Controller 会自动恢复。** 要验证后者，需要让实际调谐循环运行起来。使用 envtest 时，还要注册被测 Controller 并启动 Manager；只启动 API Server 和 etcd，并没有运行你的 Controller。具体可参考 文末的 Kubebuilder envtest 测试说明。

这些场景检查完，再运行项目要求的构建和代码检查。例如，项目配置了下面这些命令：

```bash
make build
make test
make lint
```

命令只是示例，实际要执行哪些检查，以项目配置为准。运行记录需要对应当前代码，不能用修改前的测试结果为修改后的代码背书。

检查失败时，先结合错误输出、调用链和复现步骤定位原因，再修复和验证。不要为了让测试变绿就删除断言、吞掉错误，或者用硬编码结果伪造成功。Mock 可以帮助验证特定错误分支，但不能凭这类结果声称实际调谐链路已经通过验证。

如果失败来自环境不可用、缺少权限，或者继续修复需要改变已确认的方案，就应记录阻塞并交给开发者处理，而不是无限重试，也不能把未完成检查改写成“通过”。

### Quality Gate：让验证结果真正起作用

Quality Gate 要明确的是：哪些检查必须通过，才能进入下一阶段或合并代码。这个条件最好由工具执行，而不只是写在 Prompt 里。

对于代码合并，可以通过 CI 的必需检查和分支保护落实门禁。同时要确认要求的测试确实执行过，没有被条件跳过，也没有忽略失败。以 GitHub 为例，部分必需检查的 `skipped`、`neutral` 状态也能满足合并要求，具体要结合分支保护规则检查（文末附官方文档）。

任务记录中的 `passed` 也不能代替执行结果。至少应能追溯到实际命令、日志，以及它们对应的代码版本。

工具检查之外，还需要人工审查。比如这次只修恢复问题，Diff 却改了公共接口，构建和测试可能照样通过，但这项改动已经超出约定范围。审查时要确认接口变化是否获批、原来的行为有没有受到影响，以及既有重试机制能否复用，避免为一次修复维护两套相似逻辑。

## 从 Prompt 到 Workflow：把有效的做法留下来

如果修复 Issue 时总要重复输入“先定位原因，再提出方案，改完补测试”，可以把这段做法保存下来，下次直接调用。任务更长、需要中途检查方案或跨 Session 继续时，再用 Workflow 安排阶段和记录进度。

![从 Prompt 到 Workflow：任务执行与工程经验沉淀](https://img.lixueduan.com/ai/vibe-coding/vibe-coding-workflow.png)

不需要每次都启动完整 Workflow。简单任务用简单流程；影响范围大、需要跨会话推进的任务，再加入更多约束和状态管理。

### 把重复 Prompt 变成 Skill

修复 Issue 通常要经历阅读问题描述、定位原因、制定方案、修改代码、补充测试，最后验证和审查。如果这套步骤已经适用，就不必每次重新输入。

简单的固定提示，可以保存成工具支持的 Command；需要一起携带参考文档、模板或脚本，并按任务加载时，再考虑封装为 Skill。Agent Skills 的格式支持打包这些材料，但封装本身不能保证任务执行正确，验证仍然要做。

也不必所有 Skill 都自己开发。通用的调试、代码审查和测试流程，可以参考社区实现，再按项目需要调整。引入前要检查其中的指令、脚本和权限要求，不能只看名称和介绍。

### 为 Workflow 设置阶段检查点

当 Spec、Design、Coding 和 Verification 被串成 Workflow 后，还需要明确每个阶段怎样才算完成。例如：

```text
Spec    → 需求范围和验收标准是否明确
Design  → 方案和关键决策是否已经确认
Coding  → 约定的变更及对应测试是否已经完成
Verify  → 必要检查是否执行，验收结果是否有记录
```

部分条件可以用脚本检查，比如文档是否存在、必要字段是否完整、测试是否通过；方案是否获批，则要由指定人员确认。**Agent 自己写入“已批准”，不能代替审批。**

从 Design 进入 Coding 前，如果方案仍有争议，就先停下来确认，而不是因为已经生成了一份设计文档就继续编码。同样，进入交付阶段也不能只检查一份状态文件，仍要核对实际验证结果。

### 长任务还需要 Workflow State

前面提到，跨 Session 的任务需要保存决策和进度。下面是一份交接模板，不代表前述 Controller 示例已经完成修改或验证：

```text
当前阶段：验证
当前任务：修复临时 API 错误后无法恢复的问题

已确认的约束与决策：
- 不修改 CRD Schema 和现有公共接口
- 优先复用现有错误处理与重试机制
- 方案及确认记录：<文档路径或讨论记录>

代码位置：
- 分支与提交：<分支名、提交 ID>
- 未提交变更：<是否存在；存在时写明位置和范围>

验证记录：
- 已执行：<实际命令、结果、日志位置、对应代码版本>
- 失败项：<错误摘要；没有则注明无>
- 尚未验证：<剩余验收项，例如 API 恢复后的自动调谐>

下一步：<具体操作及预期检查结果>
需要人工决定：<阻塞项；没有则注明无>
停止条件：<权限不足、需要改变已确认方案等>
```

不必每次重写整个任务经过，只更新发生变化的部分。测试结果与代码版本对不上时，接手者应先确认是否需要重跑，不能照着记录中的“通过”继续往下做。

![长任务的 Workflow State：记录进度、决策、重试与停止条件](https://img.lixueduan.com/ai/vibe-coding/workflow-state.jpg)

### Workflow 本身也应该被评估

流程增加以后，要看看返工和人工介入是否减少，又多花了多少时间和 Token。步骤更多，不一定就更划算。

可以拿同一组任务比较新旧流程，记录验收是否通过、返工次数、人工介入和执行成本。比较时使用相同的验收标准，并从相同的代码和环境起点分别运行，不要让后一组继承前一组改好的代码或历史记录。

样本不多时，先看具体失败在哪一步，不急着判断哪套流程更好。如果结果没有改善，等待时间和 Token 却增加了，就检查哪些步骤没有带来收益，能简化的就简化。

## 小结

回到前面的 Controller 例子，验收要看三个结果：临时 API 错误没有被当成成功，API 恢复后资源能够继续调谐，重复执行也不会创建重复资源。Agent 有没有新增重试代码，并不是验收重点。

审查时，把这三个结果与实际 Diff、测试记录逐项对上。只通过编译，还不能说明资源会恢复；只检查了错误返回，也没有覆盖后续调谐。没有验证的部分就留下来，写清楚还缺什么检查。

下一个任务可以先这样做：提供相关代码，写下预期结果，改完以后核对变更和测试。等同一类问题反复出现，再把有效的做法写进项目规则或 Skill，不必一开始就搭建整套 Workflow。

## 延伸阅读

- [OpenAI — Harness engineering: leveraging Codex in an agent-first world](https://openai.com/index/harness-engineering/)：短 `AGENTS.md` 作为导航，仓库知识作为事实源，以及可执行的反馈机制。
- [Anthropic — Effective harnesses for long-running agents](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents)：长任务的进度保存、上下文接续及端到端验证。
- [Cursor — Best practices for coding with agents](https://cursor.com/blog/agent-best-practices)：Plan、任务范围、代码理解和 Agent 工作流。
- [Thoughtworks — Context Engineering for Coding Agents](https://martinfowler.com/articles/exploring-gen-ai/context-engineering-coding-agents.html)：项目指令、相关 Context 与上下文工具的区别。
- [Addy Osmani — Agentic Engineering](https://addyosmani.com/blog/agentic-engineering/)：从快速生成代码转向有计划、有审查的工程化协作。
- [Gloaguen 等 — Evaluating AGENTS.md（v2，2026 年 6 月 23 日）](https://arxiv.org/abs/2602.11988v2)：在所测任务与 Agent 中，仓库上下文文件并未普遍提高任务成功率，还增加了推理成本；项目特有约定比泛泛的仓库概述更可能有用。
- [controller-runtime — FAQ](https://github.com/kubernetes-sigs/controller-runtime/blob/main/FAQ.md)：Reconcile 幂等性、最终状态和测试实践。
- [controller-runtime — Reconciler API 文档](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/reconcile)：`Reconcile` 返回非终止性错误时的重新入队、退避以及特殊错误的语义；不同版本应参考实际依赖的 API 文档。
- [Anthropic — Demystifying evals for AI agents](https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents)：Agent 工作流评测方法，以及多次尝试的完成能力与重复执行稳定性之间的区别。
- [Kubebuilder — envtest 测试说明](https://book.kubebuilder.io/reference/envtest.html)：测试控制平面的组成、Controller 调谐测试和与真实集群的差异。
- [GitHub — 分支保护规则](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches)：必需检查的状态要求及合并限制。
- [Agent Skills — What are skills?](https://agentskills.io/what-are-skills)：Skill 的目录结构，以及指令、脚本和参考材料的组织方式。


---

> 作者: [意琦行](https://github.com/lixd)  
> URL: https://www.lixueduan.com/posts/ai/29-vibe-coding-best-practices/  

