实测完胜 Skills:为何 AGENTS.md 是 AI 编程代理的最佳上下文方案
本文翻译自 Next.js 团队 Jude Gao 的技术博客。在 AI 辅助编程日益普及的今天,如何让 AI 准确掌握最新的框架知识(如 Next.js 16 的新 API)成为了一个关键挑战。作者通过严谨的对比测试,揭示了一个反直觉的结论:简单的“被动上下文”往往胜过复杂的“主动工具调用”。这一发现对于希望优化项目以适应 AI 开发(AI-Native)的开发者和框架维护者来说,具有极高的参考价值。
- 原文链接:AGENTS.md outperforms skills in our agent evals - Vercel
- 作者:Jude Gao
- 日期:2026-1-27

Next.js 团队发现,在 AGENTS.md 中嵌入压缩文档索引(被动上下文),比让 AI 主动调用 Skills 工具更有效,评估通过率高达 100%(Skills 仅 79%)。建议使用官方 CLI 一键生成索引,辅助 AI 进行“检索主导”的准确编码。
我们本以为 Skills(技能) 是教会编程代理(Coding Agents)掌握框架特定知识的终极方案。但在构建了一套专注于 Next.js 16 API 的评估套件后,我们发现了意想不到的结果。
一个直接嵌入 AGENTS.md 文件、大小仅为 8KB 的压缩文档索引,实现了 100% 的通过率;相比之下,即使明确指示代理去使用 Skills,其通过率最高也只达到了 79%。而如果去掉这些指示,Skills 的表现甚至和完全没有文档时一样差。
以下是我们尝试的方法、学到的教训,以及如何将这一发现应用到你自己的 Next.js 项目中。
背景:训练数据滞后的挑战
AI 编程代理依赖于训练数据,但训练数据总会过时。Next.js 16 引入了 'use cache'、connection() 和 forbidden() 等全新 API,目前的模型训练数据中并不包含这些内容。当代理不了解这些 API 时,它们就会生成错误的代码,或者退回使用旧版的 API 模式。
反过来也一样,如果你运行的是较旧的 Next.js 版本,模型可能会向你推荐项目中尚不支持的新 API。我们希望通过让代理能够访问与版本相匹配的文档来解决这个问题。
方案:Skills 与 AGENTS.md 的对比
在深入探讨结果之前,先快速介绍一下我们测试的两种方案:
- Skills(技能):这是一种开放标准,用于封装编程代理可用的领域知识。一个 Skill 就是一个包含了提示词(Prompts)、工具和文档的封装包,代理可以按需调用。其核心理念是:当代理意识到自己需要框架方面的帮助时,就会调用这个 Skill 来获取相关文档。
AGENTS.md:这是项目根目录下的一个 Markdown 文件,为编程代理提供持久的上下文。无论你在AGENTS.md里放什么,代理在每一轮对话中都能看到,不需要它自己决定是否去加载。Claude Code 使用的CLAUDE.md也是同样的原理。
我们构建了一个 Next.js 文档 Skill 和一个 AGENTS.md 文档索引,并通过评估套件对比了它们的表现。
预期:Skills 曾被视为理想解法
Skills 看起来是一个很棒的抽象概念。你把框架文档打包成一个 Skill,代理在处理 Next.js 任务时调用它,然后生成正确的代码。这就实现了清晰的关注点分离(Separation of Concerns),最小化了上下文开销,而且代理只在需要时加载内容。skills.sh 上甚至已经有了一个不断增长的通用 Skills 目录。
我们预想的流程是:代理遇到 Next.js 任务 -> 调用 Skill -> 阅读版本匹配的文档 -> 生成正确代码。
然而,现实狠狠打了我们的脸。
现实:Skills 的调用率未达预期
在 56% 的评估案例中,Skill 根本没被调用。 代理明明可以查阅文档,却选择不用。添加 Skill 后,表现与基线相比毫无提升:
| 配置 | 通过率 | 对比基线 |
|---|---|---|
| 基线(无文档) | 53% | — |
| Skill(默认行为) | 53% | +0pp |
零提升。Skill 就在那儿,代理也能用,但它就是不用。在详细的构建/代码检查/测试(Build/Lint/Test)细分数据中,Skill 的表现甚至在某些指标上比基线还差(测试通过率 58% vs 63%)。这表明,环境中存在一个未被使用的 Skill,反而可能成为一种干扰或噪音。
这不是我们的特例。代理无法稳定地使用可用工具,是当前模型的一个已知局限。
发现:指令措辞引发的脆弱性
于是,我们尝试在 AGENTS.md 中添加明确指令,强制代理使用 Skill:
Before writing code, first explore the project structure,
then invoke the nextjs-doc skill for documentation.
在编写代码之前,先探索项目结构,然后调用 nextjs-doc skill 获取文档。
这确实将触发率提到了 95% 以上,并将通过率拉升到了 79%。
| 配置 | 通过率 | 对比基线 |
|---|---|---|
| 基线(无文档) | 53% | — |
| Skill(默认行为) | 53% | +0pp |
| Skill + 明确指令 | 79% | +26pp |
进步明显。但我们发现了一个意想不到的现象:指令的措辞对代理的行为影响巨大。
不同的措辞产生了截然不同的结果:
| 指令 | 行为 | 结果 |
|---|---|---|
| “你必须调用 Skill” | 先读文档,死板套用文档模式 | 忽略项目上下文 |
| “先探索项目,再调用 Skill” | 先建立项目心智模型,将文档仅作参考 | 效果更好 |
同样的 Skill,同样的文档,仅仅是措辞的细微差别,结果却天差地别。
在一个评估案例('use cache' 指令测试)中,“先调用”的策略虽然写对了 page.tsx,却完全漏掉了 next.config.ts 中必须的配置更改。而“先探索”的策略则两者都搞定了。
这种脆弱性令我们担忧。如果微小的措辞调整就能导致行为剧烈波动,这种方法在生产环境中就太不可靠了。
评估:针对新 API 的测试套件
在下结论之前,我们需要一套值得信赖的评估标准。我们最初的测试套件存在提示词模糊、测试过于关注实现细节而非实际行为、以及侧重于模型已知的旧 API 等问题。我们并没有测出我们真正关心的东西。
我们对评估套件进行了加固:移除了可能导致数据泄露的测试,解决了矛盾点,并将重点转向基于行为的断言。最重要的是,我们添加了针对 Next.js 16 新 API(不在训练数据中)的测试。
加固后的评估套件包含以下 API:
- 用于动态渲染的
connection() 'use cache'指令cacheLife()和cacheTag()forbidden()和unauthorized()- 用于 API 代理的
proxy.ts - 异步
cookies()和headers() after()、updateTag()、refresh()
接下来的所有结果均基于这套加固后的评估套件。每种配置都根据相同的测试进行评判,并进行了重试以排除模型差异。
策略:嵌入被动式文档索引
如果我们完全取消“决策”这个环节呢?与其寄希望于代理去“决定”调用 Skill,不如直接在 AGENTS.md 里嵌入一个文档索引。不是全文,只是一个索引,告诉代理去哪里找与当前版本匹配的文档文件。这样,代理就能根据需要读取特定文件,无论你用的是最新版还是旧版。
我们在注入的内容中加了一条关键指令:
IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning
for any Next.js tasks.
重要提示:处理任何 Next.js 任务时,优先使用“检索主导的推理”,而非“预训练主导的推理”。
这句话告诉代理:去查文档,别光靠你脑子里那些可能过时的训练数据。
结果:AGENTS.md 达成 100% 通过率
我们在四种配置下运行了加固后的评估套件:

四种配置的评估结果。AGENTS.md(第三列)在构建、Linter 和测试中均达到 100%。
最终通过率:
| 配置 | 通过率 | 对比基线 |
|---|---|---|
| 基线(无文档) | 53% | — |
| Skill(默认行为) | 53% | +0pp |
| Skill + 明确指令 | 79% | +26pp |
AGENTS.md 文档索引 |
100% | +47pp |
在详细数据中,AGENTS.md 在构建、Lint 检查和测试三个环节全都拿了满分。
| 配置 | Build | Linter | Test |
|---|---|---|---|
| 基线 | 84% | 95% | 63% |
| Skill(默认行为) | 84% | 89% | 58% |
| Skill + 明确指令 | 95% | 100% | 84% |
AGENTS.md |
100% | 100% | 100% |
这完全出乎意料。这个“笨办法”(一个静态 Markdown 文件)竟然完胜了看似更高级的 Skill 动态检索,即使我们已经微调过 Skill 的触发机制。
为什么被动上下文优于主动检索?
我们目前的理论归结为三个因素。
- 没有决策点:使用 AGENTS.md,代理不需要判断“我该不该查这个?”信息就在眼前。
- 持续可用:Skill 是异步加载的,且仅在被调用时存在;AGENTS.md 的内容则存在于每一轮对话的系统提示词(System Prompt)中。
- 无顺序问题:Skill 会引入执行顺序的难题(是先读文档还是先看项目?);被动上下文完全避免了这个问题。
优化:80% 的索引压缩率
在 AGENTS.md 中嵌入文档可能会挤占上下文窗口。我们通过压缩解决了这个问题。
原始文档注入量约为 40KB。我们将其压缩到了 8KB(减少了 80%),同时保持了 100% 的通过率。压缩格式使用了一种基于管道符(Pipe)分隔的结构,将索引压缩到极致:
[Next.js Docs Index]|root: ./.next-docs
|IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning
|01-app/01-getting-started:{01-installation.mdx,02-project-structure.mdx,...}
|01-app/02-building-your-application/01-routing:{01-defining-routes.mdx,...}
AGENTS.md 中的管道分隔索引。
完整的索引涵盖了 Next.js 文档的每个部分:

完整的索引涵盖了 Next.js 文档的每一个章节
代理知道去哪里找文档,而无需把全文都塞进上下文。当它需要特定信息时,它会去 .next-docs/ 目录读取相应文件。
实践:一行命令自动配置
只需一个命令即可为你的 Next.js 项目设置此功能:
npx @next/codemod@canary agents-md
该功能已包含在官方 @next/codemod 包 中。
该命令会做三件事:
- 自动检测你的 Next.js 版本;
- 下载匹配的文档到
.next-docs/; - 注入压缩后的索引到你的
AGENTS.md。
如果你使用的代理工具支持 AGENTS.md(如 Cursor 或其他工具),这套方法同样适用。
结论:被动上下文优于主动检索
Skills 也并非一无是处。AGENTS.md 方案为代理处理 Next.js 任务提供了广泛的、基础性的提升。而 Skills 更适合那些用户明确触发的、垂直的、特定操作的工作流,比如“升级我的 Next.js 版本”、“迁移到 App Router”或应用框架最佳实践。两者是互补的。
但就通用的框架知识而言,被动上下文目前优于按需检索。如果你是一个框架维护者,并希望编程代理能写出正确的代码,不妨提供一个 AGENTS.md 片段供用户添加到项目中。
实用建议:
- 别干等着 Skills 改进:随着模型在工具使用能力上的提升,差距可能会缩小,但当下的结果才是最重要的。
- 大力压缩:你不需要把完整文档塞进上下文。一个指向可检索文件的索引就足够了。
- 用评估说话:构建针对“非训练数据内 API”的测试用例。这才是文档访问发挥最大价值的地方。
- 为检索而设计:优化你的文档结构,让代理可以查找和读取特定文件,而不是非得一口气吞下所有内容。
我们的目标是让代理从“预训练主导的推理”转向“检索主导的推理”。事实证明,AGENTS.md 是目前实现这一目标最可靠的途径。
研究及评估: Jude Gao | CLI 工具: npx @next/codemod@canary agents-md