这个词描述什么

“Vibe Coding”是对一种工作流的非正式称呼:开发者用自然语言表达意图,AI Agent 提出、修改或解释代码。它不是软件工程的替代品,也不保证结果可执行、安全或可维护。

有效的边界可以写成:

text
意图 -> 受约束的提案 -> 检查 Diff -> 运行证据
     -> 处理失败 -> 修改或拒绝 -> 经过常规控制后合并

模型可以加速草稿,Repository、Tests、Policy 检查和负责人决定变更是否可接受。

适合与不适合的地方

AI 辅助通常适合:

  • 探索陌生模块;
  • 为窄范围 Adapter 或 Test 生成初稿;
  • 解释现有错误路径;
  • 提议重复性重构;
  • 比较实现方案。

它不能替代:

  • 威胁建模和授权设计;
  • 数据所有权与留存判断;
  • Migration 和外部副作用 Review;
  • 医疗、法律、金融或安全关键行为验证;
  • 维护一个团队无人能解释的系统。

当任务有精确 Oracle 时,优先使用更小的确定性工作流。只有额外自主能力值得承担上下文和控制风险时,才使用 Agent。

写出任务契约

把“构建整个应用”替换成契约。可复现的 Vibe Coding 实战流程展示了如何把契约应用到完整 Go 示例:

text
Goal:
  为只读 invoice list Endpoint 增加分页。

In scope:
  packages/billing/src/list_invoices

Out of scope:
  Schema Migration、定价、授权 Policy、部署

Inputs and invariants:
  保留 Tenant 与 Principal 检查;
  拒绝无效 Cursor;
  不暴露完整客户记录。

Evidence:
  相关 Tests、Type Check、Formatter 和 Diff 摘要。

Escalate:
  新依赖、外部写入、凭证访问或公共 API 变化需要升级。

契约为模型提供有用上下文,却不允许模型文本重定义身份、所有权、定价或权限。

上下文是一种预算

上下文工程既是预算决策,也是信任决策。上下文越多可能噪声越大,也可能暴露数据,因此要按信任分开:

上下文 示例 处理方式
Canonical 已提交 Schema、Tests、Build Scripts 记录 Revision 与负责人
Task Issue、验收标准、当前 Diff 验证范围
Generated Index 结果、摘要、Tool 输出 未验证前视为不可信
Sensitive Credential、客户记录、生产 Dump 排除或获批脱敏

优先选择最小相关文件,包含 Interface 和附近 Tests;排除无关 Repository、生成噪声、Secret 和过时副本。记录文件路径与 Revision,重要建议才能复现。

Issue 文本、注释、检索文档和测试输出可能包含 Prompt Injection。它们是数据,不是更高优先级的 Policy。

小步、可观察地迭代

使用留下证据的循环:

  1. 检查当前代码和 Tests;
  2. 要求只在声明范围内提出计划;
  3. 请求一个相干变更;
  4. 检查 Diff 和依赖变化;
  5. 运行相关 Tests 与静态检查;
  6. 对失败分类,不要盲目重试;
  7. 理解上一步后再扩大范围。

小步降低 Review 面积并便于回滚,但不会自动把不安全任务变安全。

不易过时的 Prompt 模式

优先使用可观察指令:

text
复用现有 Error 类型和依赖注入模式。
不要虚构 SDK 方法;引用已安装版本,或明确标为伪代码。
每个行为变化都添加或更新相关 Test。
报告运行过的命令、失败、跳过的检查和假设。
如果需求与 Repository 契约冲突,停止并解释冲突。

避免:

text
写出完美的生产代码。
自主做出所有决定。
永远不要提问。
一次响应返回完整应用。

后者奖励自信并隐藏不确定性。好的助手可以说“无法验证这个依赖”或“这需要审批”。

Review 草稿,而不是 Review 氛围

检查每个生成 Diff:

  • 行为和错误路径;
  • 授权、Tenant 隔离和输入校验;
  • Secret、日志、依赖和 License 变化;
  • 并发、重试、幂等、取消和资源限制;
  • Test 覆盖与负面案例;
  • Observability、回滚和 Migration 影响。

不要要求模型证明隐藏推理。要求简短的变更摘要、假设和证据链接即可。流畅解释不是测试结果。

示例:安全的数据转换边界

AI 生成的数据转换,在运行和数据假设被显式定义之前不能称为“完成”。下面这段 Go 边界只接受有类型的 Record,限制批次大小,只规范化已声明字段,拒绝格式非法的地址,也不会把输入中的未知字段复制到输出:

go
package records

import (
	"fmt"
	"net/mail"
	"strings"
	"unicode/utf8"
)

const maxRecords = 10_000

type InputRecord struct {
	Email       string
	DisplayName string
}

type Record struct {
	Email       string
	DisplayName string
}

func NormalizeRecords(input []InputRecord) ([]Record, error) {
	if len(input) > maxRecords {
		return nil, fmt.Errorf("too_many_records")
	}

	output := make([]Record, 0, len(input))
	for index, item := range input {
		email := strings.ToLower(strings.TrimSpace(item.Email))
		if email == "" {
			continue
		}
		address, err := mail.ParseAddress(email)
		if err != nil || address.Address != email {
			return nil, fmt.Errorf("record_%d_invalid_email", index)
		}

		displayName := strings.TrimSpace(item.DisplayName)
		if utf8.RuneCountInString(displayName) > 200 {
			return nil, fmt.Errorf("record_%d_display_name_too_long", index)
		}
		output = append(output, Record{
			Email:       email,
			DisplayName: displayName,
		})
	}

	return output, nil
}

这段函数仍然没有定义 JSON 或 CSV Parsing、File Path、字符编码、输出原子性、数据留存、加密,以及谁有权处理这些记录。这些边界属于调用方契约与测试。Prompt 绝不能授予任意路径访问,也不能允许把记录上传到不可信目的地。

Tests 是需求的一部分

要求覆盖行为,而不是只复刻实现:

  • 有效和无效输入;
  • 空输入和超大输入;
  • 重复与重放请求;
  • 超时和部分失败;
  • 未授权与跨 Tenant 标识符;
  • 转义、注入和畸形外部数据;
  • 取消与清理;
  • 向后兼容和回滚。

随后运行项目真实的 Test、Type、Format、Lint、安全和 Build 命令。没有运行的命令应明确说明。

Tool 与权限

AI Agent 可以执行命令时,Executor 应强制:

  • 已认证 Principal 与 Repository Scope;
  • 默认只读;
  • 命令和网络 Allowlist;
  • 隔离 Worktree 或 Sandbox;
  • 时间、输出、文件和进程预算;
  • 取消和清理;
  • Merge、Release、删除、凭证变化和外部写入需要审批;
  • 经过脱敏的审计 Event。

Prompt 约束和模型拒答只是提示,不是授权。Coding Assistant、IDE Extension 和 Terminal Agent 都适用这一点。

使用显式执行策略:

能力 安全默认值 升级时必须提供的证据
读取受版本控制的源码与测试 允许,但仅限任务仓库 审计记录中的路径与版本
运行 Formatter 和聚焦测试 允许,但来自命令白名单 命令、退出码与有界输出
安装或更新依赖 询问 原因、Lockfile Diff、License、漏洞扫描
读取 Secret 或生产数据 拒绝 独立审批流程与脱敏方案
访问任意网络地址 拒绝或 Host 白名单 目的地、用途、数据分类
写入外部系统 询问 幂等键、Dry Run、负责人、回滚
合并、部署、删除、迁移 人工审批 已评审证据包与恢复方案

策略必须由宿主工具或 Sandbox 强制执行。在 Prompt 里反复写“禁止部署”,不等于真正移除部署权限。

建立分层验证阶梯

先运行成本最低、但能做出决定的检查:

  1. 格式化并编译被修改的 Package;
  2. 运行聚焦 Unit Test 与 Contract Test;
  3. 运行 Type、Lint、Static、Dependency 与 Secret 检查;
  4. 在隔离环境执行 Integration Test;
  5. 审查完整 Diff 与生成产物;
  6. 执行更广的 Build 或 E2E 门禁;
  7. 对外部副作用要求显式审批。

每一层都必须产生 Artifact:命令结果、测试报告、评审决定或部署记录。模型信心和文字摘要不属于验证阶梯。

团队协作

把共享指令当作版本化工程产物:

  • 项目契约短小且与 Provider 无关;
  • 指定负责人和复查日期;
  • 链接实际脚本与 Canonical 文档;
  • 用合成示例替代 Secret 和生产 Dump;
  • 用代表性和对抗任务测试指令变化;
  • 测量成功结果、Review 工作量、缺陷、成本和开发者学习;
  • 高风险切片回归时回滚配置。

不要对所有 Repository 强制同一工作流。只读文档项目不应获得部署 Agent 所需的权限。

衡量成功验收结果

不要把 Prompt 数、Token 消耗或生成代码行数当作生产力指标。应测量:

  • 每名开发者每周成功验收的任务数;
  • 从接受任务到评审合并的 Lead Time;
  • 一次验收通过率;
  • 人工评审与返工分钟数;
  • 逃逸缺陷、事故与回滚;
  • 每个成功变更的成本;
  • 通过 Review 或后续维护任务抽样验证的开发者理解度。

结果应按 Greenfield 与成熟代码、任务类型、风险等级和工具版本拆分。一个汇总平均值可能同时掩盖“测试起草明显提效”和“授权逻辑严重退化”。

不做排行榜的 Provider 选择

产品能力、路径、Model、价格和留存条款会变化。针对真实工作负载比较当前版本:

标准 证据
Context 选择、Provenance、排除和过时行为
执行 Sandbox、Command Policy、Network、取消
隐私 留存、训练使用、驻留、删除
Review Diff、Tests、审批、审计导出
可迁移性 可导出指令与 Provider 独立性
运营 配额、故障、延迟、版本固定
经济 订阅、推理、Review、迁移

根据证据选择,不维护永久的“最佳 IDE”结论。

常见失败模式

  • 因为代码看起来惯用就信任它;
  • 提供整个生产 Repository,而不是少量必要文件;
  • 把 Issue 或检索文档当作可信指令;
  • 授予宽泛 Shell、Network 或凭证权限;
  • 让模型选择身份、所有者、价格或角色;
  • 把局部片段称为完整可运行;
  • 在设计已被默认正确后才生成 Tests;
  • 因为模型说 Tests 通过就直接合并;
  • 没有用途和删除路径却长期保留 Prompt 与源码;
  • 测量速度却隐藏重工、缺陷和 Review 成本。

实践清单

  • [ ] 写出有范围、约束和升级路径的任务契约。
  • [ ] 选择最小、版本化、可信的上下文并排除 Secret。
  • [ ] 将检索内容和 Tool 输出视为不可信数据。
  • [ ] 请求小 Diff,检查依赖和权限变化。
  • [ ] 要求确定性 Tests 和安全检查。
  • [ ] 对命令使用 Sandbox,副作用需要审批。
  • [ ] 记录假设、跳过的检查、失败和回滚步骤。
  • [ ] Review 行为、授权、数据处理、并发和运营影响。
  • [ ] 版本化并 Replay 共享指令。
  • [ ] 测量成功结果、质量、成本和学习,而非 Prompt 数量。

总结

Vibe Coding 最有价值的形式是一种有纪律的交互循环:表达意图、约束变更、检查证据,并让工程师和 Repository 保持所有权。自然语言可以加速草稿,但不能替代 Tests、Policy、安全 Review 或对系统结果负责。

一手来源