[译文]在我们的 Agent 评测中,AGENTS.md 的表现优于 Skills
作者: Jude Gao(Next.js 软件工程师)
日期: 2026年1月27日
我们原本以为 Skills(技能) 是教会编程 Agent(智能体)掌握特定框架知识的解决方案。但在构建了专注于 Next.js 16 API 的评测后,我们发现了一些意想不到的结果。
直接嵌入 AGENTS.md 的压缩版 8KB 文档索引实现了 100% 的通过率,而 Skills 即使在有明确指令要求 Agent 使用的情况下,通过率也仅达到 79%。如果没有这些指令,Skills 的表现并不比没有任何文档时更好。
以下是我们尝试的方法、学到的经验,以及如何在您自己的 Next.js 项目中进行设置。
我们试图解决的问题
AI 编程 Agent 依赖于训练数据,而这些数据会变得过时。Next.js 16 引入了诸如 'use cache'、connection() 和 forbidden() 等 API,这些并不在当前模型的训练数据中。当 Agent 不了解这些 API 时,它们会生成错误的代码或退回到旧的模式。
反之亦然,当您运行较旧的 Next.js 版本时,模型可能会建议您项目中尚不存在的新 API。我们希望通过赋予 Agent 访问与版本匹配的文档的能力来解决这个问题。
教授 Agent 框架知识的两种方法
在深入探讨结果之前,先简单解释一下我们测试的两种方法:
- Skills(技能) 是一种打包领域知识的开放标准,供编程 Agent 使用。一个 Skill 捆绑了 Agent 可以按需调用的提示词(prompts)、工具(tools)和文档。其理念是,Agent 能够识别何时需要特定框架的帮助,调用该 Skill,并获取相关文档。
- AGENTS.md 是位于项目根目录下的 Markdown 文件,为编程 Agent 提供持久的上下文。无论您在 AGENTS.md 中放入什么内容,Agent 在每一轮对话中都能获取到,无需自行决定是否加载。Claude Code 也使用
CLAUDE.md来实现相同的目的。
我们构建了一个 Next.js 文档 Skill 和一个 AGENTS.md 文档索引,然后通过我们的评测套件运行它们,看看哪个表现更好。
我们起初押注于 Skills
Skills 看起来是正确的抽象层。您将框架文档打包成一个 Skill,Agent 在处理 Next.js 任务时调用它,从而获得正确的代码。这实现了清晰的关注点分离,最小的上下文开销,且 Agent 只加载它需要的内容。在 skills.sh 上甚至还有一个不断增长的可重用 Skills 目录。
我们原本预期 Agent 会遇到 Next.js 任务,调用 Skill,阅读版本匹配的文档,并生成正确的代码。
然后我们运行了评测。
Skills 未能被可靠触发
在 56% 的评测案例中,Skill 从未被调用。Agent 拥有访问文档的权限,但没有使用它。添加 Skill 后,结果与基线相比没有任何提升:
| 配置 | 通过率 | vs 基线 |
| 基线(无文档) | 53% | — |
| Skill(默认行为) | 53% | +0pp |
零提升。 Skill 就在那里,Agent 可以使用它,但 Agent 选择了不用。在详细的 构建/Lint/测试 (Build/Lint/Test) 细分中,Skill 在某些指标上的表现甚至不如基线(测试通过率 58% vs 63%),这表明环境中存在未使用的 Skill 可能会引入干扰或分心。
这并非我们需要特有的情况。Agent 无法可靠地使用可用工具是当前模型的一个已知局限。
明确的指令有帮助,但措辞很脆弱
我们尝试在 AGENTS.md 中添加明确的指令,告诉 Agent 使用 Skill。
在编写代码之前,先探索项目结构,然后调用nextjs-docskill 获取文档。
(添加到 AGENTS.md 以触发 Skill 使用的指令示例)
这提高了 Skill 的触发率至 95% 以上,并将通过率提升到了 79%。
| 配置 | 通过率 | vs 基线 |
| 基线(无文档) | 53% | — |
| Skill(默认行为) | 53% | +0pp |
| Skill(带明确指令) | 79% | +26pp |
这是一个扎实的改进。但我们发现了一个意想不到的情况,即指令的措辞如何影响 Agent 的行为。
不同的措辞产生了截然不同的结果:
| 指令 | 行为 | 结果 |
| "你必须调用 Skill" (You MUST invoke the skill) | 先读文档,锚定文档模式 | 丢失项目上下文 |
| "先探索项目,然后调用 Skill" | 先建立心智模型,使用文档作为参考 | 结果更好 |
同一个 Skill,同一份文档。仅因措辞的细微变化而产生不同的结果。
在一个评测('use cache' 指令测试)中,“先调用”的方法编写了正确的 page.tsx,但完全遗漏了所需的 next.config.ts 更改。“先探索”的方法则两者都搞定了。
这种脆弱性让我们感到担忧。如果微小的措辞调整会产生巨大的行为波动,那么这种方法在生产环境中使用就显得太脆弱了。
构建我们可以信任的评测
在得出结论之前,我们需要值得信赖的评测。我们最初的测试套件存在提示词模棱两可、测试验证的是实现细节而非可观察的行为,以及侧重于已在模型训练数据中的 API 等问题。我们并没有测量我们真正关心的内容。
我们通过消除测试泄漏、解决矛盾并转向基于行为的断言来强化评测套件。最重要的是,我们添加了针对不在模型训练数据中的 Next.js 16 API 的测试。
我们重点评测套件中的 API 包括:
- 用于动态渲染的
connection() 'use cache'指令cacheLife()和cacheTag()forbidden()和unauthorized()- 用于 API 代理的
proxy.ts - 异步的
cookies()和headers() after()、updateTag()、refresh()
随后的所有结果均来自这个强化后的评测套件。每种配置都针对相同的测试进行了评判,并进行了重试以排除模型差异的影响。
得到回报的直觉
如果我们完全移除决策过程会怎样?如果不寄希望于 Agent 会调用 Skill,我们可以将文档索引直接嵌入到 AGENTS.md 中。不是完整的文档,只是一个索引,告诉 Agent 在哪里可以找到与您项目 Next.js 版本匹配的特定文档文件。然后,Agent 可以根据需要读取这些文件,无论您是使用最新版本还是维护旧项目,都能获得准确的版本信息。
我们在注入的内容中添加了一条关键指令。
重要提示: 对于任何 Next.js 任务,优先使用检索主导的推理 (retrieval-led reasoning),而非预训练主导的推理 (pre-training-led reasoning)。
(嵌入在文档索引中的关键指令)
这告诉 Agent 参考文档,而不是依赖可能过时的训练数据。
结果让我们大吃一惊
我们在所有四种配置下运行了强化后的评测套件:
| 配置 | 通过率 | vs 基线 |
| 基线(无文档) | 53% | — |
| Skill(默认行为) | 53% | +0pp |
| Skill(带明确指令) | 79% | +26pp |
| AGENTS.md 文档索引 | 100% | +47pp |
在详细细分中,AGENTS.md 在构建、Lint 和测试方面均取得了满分。
| 配置 | Build | Lint | Test |
| 基线 | 84% | 95% | 63% |
| Skill(默认行为) | 84% | 89% | 58% |
| Skill(带明确指令) | 95% | 100% | 84% |
| AGENTS.md | 100% | 100% | 100% |
这出乎我们的意料。“笨”方法(静态 Markdown 文件)的表现优于更复杂的基于 Skill 的检索,即使我们对 Skill 的触发器进行了微调。
为什么被动上下文胜过主动检索?
我们的工作理论归结为三个因素:
- 无决策点。 使用
AGENTS.md,不存在 Agent 必须决定“我应该查一下这个吗?”的时刻。信息已经存在了。 - 持续的可用性。 Skills 是异步加载的,且仅在被调用时加载。
AGENTS.md的内容存在于每一轮对话的系统提示词(system prompt)中。 - 无顺序问题。 Skills 会产生顺序决策(先读文档 vs 先探索项目)。被动上下文完全避免了这个问题。
解决上下文膨胀的担忧
在 AGENTS.md 中嵌入文档有使上下文窗口膨胀的风险。我们通过压缩解决了这个问题。
初始文档注入大约 40KB。我们将其压缩至 8KB(减少了 80%),同时保持了 100% 的通过率。压缩格式使用管道符分隔的结构,将文档索引打包到最小空间:
[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 文档的每个部分。Agent 知道在哪里可以找到文档,而无需在上下文中拥有完整的内容。当它需要特定信息时,它会从 .next-docs/ 目录中读取相关文件。
亲自尝试
只需一条命令即可为您的 Next.js 项目设置此功能:
npx @next/codemod@canary agents-md
该功能是官方 @next/codemod 包的一部分。
此命令做三件事:
1. 检测您的 Next.js 版本
2. 下载匹配的文档到 .next-docs/
3. 将压缩索引注入到您的 AGENTS.md 中
如果您使用的 Agent 支持 AGENTS.md(如 Cursor 或其他工具),同样的方法也适用。
这对框架作者意味着什么
Skills 并非毫无用处。AGENTS.md 方法为 Agent 如何处理所有任务中的 Next.js 工作提供了广泛的、横向的改进。Skills 更适合用户显式触发的垂直、特定操作的工作流,例如“升级我的 Next.js 版本”、“迁移到 App Router”或应用框架最佳实践。这两种方法是互补的。
即便如此,对于通用的框架知识,被动上下文目前的表现优于按需检索。如果您维护一个框架并希望编程 Agent 生成正确的代码,请考虑提供一个用户可以添加到其项目中的 AGENTS.md 片段。
实用建议:
• 不要等待 Skills 改进。 随着模型在工具使用方面变得更好,差距可能会缩小,但现在的效果才是最重要的。
• 积极压缩。 您不需要在上下文中放入完整的文档。一个指向可检索文件的索引同样有效。
• 使用评测进行测试。 构建针对不在训练数据中的 API 的评测。这才是文档访问最重要的地方。
• 为检索而设计。 构建您的文档结构,以便 Agent 可以查找和读取特定文件,而不是一开始就需要所有内容。
目标是将 Agent 从预训练主导的推理转变为检索主导的推理。AGENTS.md 证明是实现这一目标最可靠的方法