Spec 与上下文:一切的起点

Vibe Coding; Spec; AGENTS.md; CLAUDE.md; 上下文工程 2413 字 13 min read

上一篇讲了 Vibe Coding 是”指挥 Agent 写代码”,你的活儿从敲字符变成了管注意力。这一篇讲最前置、也最容易被跳过的一步:你到底喂了什么给 Agent

一个残酷的事实

写出来的东西质量,大部分在它动手之前就已经定了。不是被模型能力定的,是被你的输入定的。输入含糊,再强的模型也只能猜;输入清楚,中等模型也能干得不错。这一篇拆两样输入——Spec(这次要做什么)和 AGENTS.md/CLAUDE.md(这个项目长什么样)。

一、Spec

Spec(规范)就是你想让 AI 做什么的清晰描述。它可以是聊天框里的一段话,可以是一份 Markdown 文档,也可以是一个 GitHub/GitLab 的 Issue(Issue 本质上就是结构化的任务描述,天然适合当 Spec,Agent 也能直接读 Issue 链接)。

好 Spec 的三个特征

1. 意图清晰。 对比一下:

  • ❌ “做一个登录功能”
  • ✅ “基于现有的 auth/ 模块,添加邮箱 + OTP 登录,OTP 用 Redis 存储,5 分钟过期”

前者 Agent 只能靠”登录功能”这三个字去脑补——用什么方式登录?存哪?过期多久?它会挑一个训练数据里最常见的实现,而那大概率不是你项目现在的样子。后者把关键决策都钉死了,Agent 没有猜的空间。

2. 约束明确。 风格、依赖、性能、错误处理边界都要说清。尤其是”不要做什么”:

  • “不要引入新依赖”
  • “保持现有 DTO 命名”
  • “不要改 auth/ 下的文件”

这些约束必须说在前面。等 Agent 写完了你才说”哦对了不能加新依赖”,它已经基于新依赖写了一大堆,只能返工。

3. 验收标准可测。 “成功的标志是什么”——能跑通哪个测试?哪个 endpoint 返回什么?给不出可测的验收标准,通常说明你自己也没想清楚要什么,这时候先别急着让 Agent 动手。

Spec 的两种模式

轻量 Spec(对话式): 写在聊天框里,适合小改动。

在 UserService 加一个 deleteAccount 方法:
- 软删除(设 deleted_at)而不是物理删除
- 同时撤销该用户所有的 session
- 写一个单元测试,覆盖正常流程和"用户不存在"的情况

重量 Spec(文档式): 写成 specs/feature-xxx.md,适合要跨多个 session、甚至跨天的功能:

# 用户注销功能

## 背景
当前系统只有禁用账户,没有真正的注销流程。GDPR 合规要求...

## 目标
- 用户可以发起注销
- 30 天冷静期内可撤销
- 30 天后自动执行物理删除

## 非目标
- 不处理已发布内容的归属转移(下一期做)

## 技术方案
[让 Agent 在这里填,你来审]

## 验收
- [ ] POST /account/deletion 创建注销请求
- [ ] 测试覆盖率 > 80%
- [ ] 撤销 endpoint 可用

注意”非目标”这一节——它和”目标”一样重要。明确划出边界,Agent 才不会顺手把下一期的活儿也做了,把 PR 撑成一个没人敢 review 的大块头。

关键: Spec 不是写完就扔的。开发过程中它要随着发现的问题不断更新。它是你和 Agent 之间的”合约文档”——你改了主意,先改 Spec,再让 Agent 跟着改,而不是在聊天里甩一句”刚才那个不算了”。

一个实用技巧
Agent 提问

需求本身还模糊的时候,别直接要代码。先让 Agent 帮你把需求问清楚:

先不要写代码。请基于下面这段业务描述,提出 8 个澄清问题,
覆盖:目标用户、核心流程、失败场景、性能约束、兼容范围、上线节奏。
等我回答后,再输出实现方案。

业务描述:......

这一步看着慢,实际上经常能省掉后面几小时的返工——因为它把”我以为我想清楚了、其实没有”的地方,在动手前就暴露出来了。这正是主流工具的 Plan 模式在做的事(详见本系列的什么时候 Vibe,什么时候收一篇)。

二、AGENTS.md / CLAUDE.md

Spec 说的是”这次做什么”,而 Agent 还需要知道”这个项目长什么样、有什么约定、之前踩过什么坑”。这些不该每次都在聊天里重讲一遍,而应该固化到项目根目录的一份文件里——这是给 Agent 看的 README。人类读 README.md,Agent 读 AGENTS.md

AGENTS.md 已经是跨工具标准

AGENTS.md 不再是某个产品的私有配置。它由 agents.md 推动,被 Cursor、Codex、GitHub Copilot、Aider、Google Jules 等 25+ 工具原生读取。多数 Agent 在 session 启动时会自动加载它。

多工具共存时的推荐分工:

文件谁读放什么
AGENTS.md大多数 Agent项目通识
、目录、红线、坑
CLAUDE.mdClaude CodeClaude 专属能力(权限、hooks、skills 路径);可用首行 @AGENTS.md 导入共享内容
.cursor/rules/*.mdcCursor按 glob 匹配的规则;项目级通识仍放 AGENTS.md
子目录 AGENTS.md进入该目录时叠加包/模块级约定

💡 Claude Code 默认不读 AGENTS.md。官方推荐在 CLAUDE.md 首行写 @AGENTS.md,或者干脆 ln -sf AGENTS.md CLAUDE.md,这样 Codex、Cursor、Claude Code 共用一份源文件,不用维护三处。

应该放什么进去

1. 项目身份——一句话说清技术栈和部署形态:

## 项目简介
这是一个 B2B SaaS 的后端,Go 1.22 + PostgreSQL + Redis,
部署在 AWS ECS Fargate,前端在另一个仓库。

2. 目录地图——这是最救命的一节。Agent 不知道你的 internal/billing/ 里藏着”金额必须用 decimal 不能用 float”这种血泪教训:

## 代码结构
- `cmd/api/`        - HTTP 入口
- `internal/auth/`  - 认证,改这里要先看 SECURITY.md
- `internal/billing/` - 计费,所有金额用 decimal,禁止 float
- `pkg/`            - 对外可引用的工具,慎改
- `migrations/`     - 数据库迁移,只增不改

3. 常用命令——测试、构建、lint 怎么跑。Agent 知道了才能自己验证。

4. 红线与坑——那些”看起来能这么做但千万别”的地方。

写 AGENTS.md 的四条心法

这几条来自大规模使用后的沉淀,能让你的手册真正有效而不是变成一坨没人看的字:

1. 先设限制,而不是写指南。 别一上来就想写一本百科全书。从小处起步,根据 Agent 实际犯的错逐步补充。它哪次搞砸了,你就把对应的规则加进去。

2. 别到处 @ 引用文档。 你可能想把已有的大量文档都用 @path/to/doc.md 塞进来。但这会在每次运行时把整份文件灌进上下文,迅速撑爆窗口。正确做法是只提路径,并说明何时该读:

“遇到复杂的 FooBar 用法或碰到 FooBarError 时,参见 path/to/foobar_docs.md。”

这样 Agent 平时不会加载它,真需要时才去读。

3. 不要只说”禁止”。 纯负面约束(如”绝对不要用 --foo 标志”)会让 Agent 在它认为必须用的时候左右为难、卡死。永远给一个可行的替代方案:“不要用 X,改用 Y。”

4. 把 AGENTS.md 当成精简代码库的强制手段。 如果你的 CLI 命令复杂到需要长篇解释,与其写大段文档,不如写一个简单的 bash 包装脚本,提供清爽的接口,然后只记录这个包装器。保持手册尽可能短,反过来逼你把工具做得更好用。

核心要点:AGENTS.md 当作一套高层次、精心策划的护栏,而不是无所不包的说明书。控制篇幅(通常建议 200 行以内),它的作用是指引 Agent 去哪里找细节,而不是把所有细节都塞进上下文。

三、上下文是有预算的

Spec 和 AGENTS.md 都是在”喂上下文”。但上下文窗口是有限资源——就像磁盘空间,会被逐渐填满。理解这一点,才能理解为什么”喂得准”比”喂得多”重要。

一个典型的成本结构

,光是加载 AGENTS.md、目录结构、基础工具定义,可能就要占掉 20K token(10%);剩下的才是留给你实际改动的空间。如果你的 AGENTS.md 臃肿、动辄 @ 引用一堆文档,基线成本就会飙升,留给真正干活的空间越来越少。

所以喂上下文的原则是:

  • Agent 这次任务真正需要的文件和信息,不多不少
  • ;能放脚本里的别写进手册
  • 及时
    ,别等它写完才补

至于会话开到一半上下文快满了怎么办、什么时候该清零重开,那是”注意力管理”的下半场,放在什么时候 Vibe,什么时候收一篇细讲。


这一篇的核心就一句话:Vibe Coding 的产出,80% 由输入决定。 你花在写清楚 Spec、维护好 AGENTS.md 上的时间,会以”少返工几小时”的形式加倍还给你。

下一篇讲当你已经把上下文喂对了,怎么把每一次具体的提问也变成一次设计——Prompt 不是聊天,是工程。


本文为 Vibe Coding 系列第 2 篇。主要参考:《Vibe Coding 实战教学指南》(Vibe_coding_guide)、《How I Use Every Claude Code Feature》(sshh.io,vibecoding/13 译文)。