1. 先别急着写 AGENTS.md:GPT-4o 在 SWE-bench Lite 上到底掉了多少分
你可能已经在仓库根目录放了一个 AGENTS.md,也可能正打算让模型自动生成一个。先别急,我把这件事拆成可复现的实验:用 GPT-4o 作为执行模型,在 SWE-bench Lite 上跑两组对照——一组不带任何仓库级上下文文件,一组带一份典型的、由模型自动生成的 AGENTS.md。结论先放这里:自动生成的那份文件,让任务完成率从 33.5% 掉到了 29.6%,推理成本还涨了 20% 以上。这不是玄学,是注意力被稀释后的必然结果。
SWE-bench Lite 是什么?它是从真实 GitHub 仓库里抽出来的 300 个 issue 修复任务,每个任务给你一段 issue 描述和一个代码库快照,要求 agent 定位 bug、改代码、让测试通过。它比那些被清洗过的“90% 通过率”榜单脏得多,也更接近你日常让 agent 干的活。GPT-4o 在这里的裸跑基线大约是 33.5%,这个数字本身不高,但足够用来做对照实验。
为什么一个 markdown 文件能拖后腿?核心机制是“冗余循环”。当你让模型扫描仓库生成 AGENTS.md,它会写“这是一个 React + TypeScript 项目”“/src 存放源代码”“使用 Vite 构建”。可模型在解题时本来就能读到 package.json、tsconfig.json 和目录结构。你把这些信息再抄一遍放进上下文,等于在任务指令旁边塞了一堆已知事实。每个冗余 token 都在和真正的任务描述抢注意力,而 GPT-4o 的上下文窗口虽然大,中间位置的信息召回率却会下降——这就是“迷失在中间”现象在仓库级任务上的具体表现。
还有一个更隐蔽的坑:过度顺从。agent 读到 AGENTS.md 里的“架构概述”“最佳实践”后,会把这些当成高优先级约束,哪怕当前任务只是修一个空指针。它开始尝试让每一步操作都符合那些规则,推理链被拉长,不必要的步骤变多,最后要么超时,要么改错文件。我试过在一个中型仓库里放一份 400 行的自动生成 AGENTS.md,agent 修一个日期格式化 bug 时,先去读了“状态管理规范”那一节,然后花了三轮推理确认自己没违反规范,才动手改代码。任务完成了,但 token 账单很难看。
所以这篇不是劝你彻底扔掉 AGENTS.md,而是先搞清楚它什么时候是噪音、什么时候是信号。接下来我会给你一份可复制的精简模板、TaoToken 统一 Key 的配置步骤,以及完整的跑分对比和失败用例归因方法。你可以自己跑一遍,用数据决定你的仓库该不该留这个文件。
2. TaoToken 前置:统一 Key 与 GPT-4o 接入配置
要复现这个实验,你得先有一个能稳定调用 GPT-4o 的入口。我用的是 TaoToken 的统一 Key,好处是一个 Key 可以切换不同模型,跑对照组时不用来回改环境变量。官网在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 端点是 https://taotoken.net/api ,注意 API 地址后面不加 UTM 参数,直接写就行。
第一步,去控制台创建 Key。打开 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,登录后进 API Keys 页面,点新建,复制那串 sk- 开头的字符串。这个 Key 就是后面所有配置里填的凭证。如果你还没决定用哪个模型,可以先在模型对话页面试一下 GPT-4o 的响应速度: https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite 。
第二步,把 Key 写进环境变量。Linux/macOS 下编辑 ~/.zshrc 或 ~/.bashrc,Windows 下用系统环境变量面板,加两行:
export TAOTOKEN_API_KEY="sk-你的Key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"改完执行source ~/.zshrc让它生效。验证一下:echo $TAOTOKEN_API_KEY应该输出你的 Key 前几位。
第三步,如果你用 OpenAI 官方 SDK,改 base_url 即可。Python 示例:
from openai import OpenAI import os client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url=os.environ["TAOTOKEN_BASE_URL"] ) resp = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "回复 ok 两个字母"}] ) print(resp.choices[0].message.content)跑通后你会看到输出ok。这一步很关键,因为后面跑 SWE-bench Lite 时,agent 框架会反复调用这个端点,Key 配错的话会在几百次请求后才发现,浪费时间。
第四步,如果你用 Claude Code 或类似的编码 agent 工具,配置方式略有不同。Claude Code 需要设置 ANTHROPIC_BASE_URL 和 ANTHROPIC_API_KEY,但注意它走的是 Anthropic 协议,TaoToken 的兼容端点在文档里有说明: https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。具体到 Claude Code 的接入,可以参考 https://taotoken.net/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=ClaudeCodeAnthropic&utm_campaign=rewrite 里的步骤,把 Base URL 指向兼容端点,Key 填同一个。
如果你打算长期跑这类 agent 任务,建议直接上 Coding Plan,额度更划算,配置方式在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。我跑 300 个 SWE-bench Lite 任务大概消耗了几百万 token,用按量计费会心疼,Coding Plan 的包月额度更适合这种批量实验。
配置完成后,建议先跑一个最小 agent 循环:给模型一个“读取文件、修改、运行测试”的工具集,让它修一个你本地的小 bug。确认工具调用链路通了,再上 SWE-bench Lite。否则你会在评测框架和 API 配置之间来回排查,分不清是模型问题还是环境问题。
3. 可复制配置:精简 AGENTS.md 模板与评测 settings
这一节给你三样可以直接抄的东西:一份精简版 AGENTS.md 模板、SWE-bench Lite 的评测配置、以及 agent 框架的 settings 片段。先说 AGENTS.md 模板。核心原则是:只写代码里读不出来的信息。代码能表达的——目录结构、依赖列表、命名风格——一律不写。
# AGENTS.md ## 环境怪癖 - 使用 uv 管理依赖,不要用 pip install,命令是 `uv sync` - 测试用 `uv run pytest tests/ -x`,不要直接跑 pytest - Node 侧用 bun,不是 npm,安装命令 `bun install` ## 地雷 - `src/legacy/serializer_v1.py` 已废弃,不要修改,新代码用 `serializer_v2.py` - `config/old_settings.py` 里的常量是历史遗留,实际生效的是 `config/settings.py` - 不要动 `migrations/` 下的文件,数据库迁移由 DBA 手动执行 ## 团队决策 - 对外 API 的 JSON 字段统一用 snake_case,因为客户端解析器不支持驼峰 - 所有时间戳存 UTC,展示层再转本地时区,不要在业务逻辑里转 - 错误码从 10000 开始,不要用 HTTP 状态码当业务错误码 ## 架构意图 - 为什么用事件总线而不是直接调用:因为订单和库存服务需要解耦,直接调用会导致循环依赖 - 为什么 `services/` 下每个模块都有 `_internal` 子包:外部只能通过 `__init__.py` 暴露的接口调用,内部实现随时可改这份模板大概 30 行,比自动生成的 400 行少了一个数量级。注意它没有“项目概述”“技术栈”“目录结构”这些章节。你可以根据自己仓库的情况增删,但每加一条都问自己:agent 能不能通过读代码自己发现?能,就删掉。
接下来是 SWE-bench Lite 的评测配置。我用的是官方 harness 的简化版,核心是三个文件:任务列表、仓库快照路径、运行脚本。任务列表直接从 SWE-bench Lite 的 JSON 里读,仓库快照用 git clone 到指定 commit。运行脚本的关键参数:
python run_eval.py \ --model gpt-4o \ --base_url https://taotoken.net/api \ --api_key $TAOTOKEN_API_KEY \ --tasks swebench_lite.json \ --repo_root ./repos \ --agents_md ./AGENTS.md \ --output ./results_with_agents.json \ --max_turns 30 \ --timeout 600对照组把--agents_md参数去掉,或者指向一个空文件。--max_turns 30是单任务最多 30 轮工具调用,--timeout 600是单任务 10 分钟超时。这两个参数会影响成功率,建议两组用同样的值。
如果你用 Cline 或类似的 VS Code agent 插件跑,配置在.cline/settings.json或工作区 settings 里。关键字段是 Base URL、API Key、Model ID 三件套:
{ "cline.apiProvider": "openai", "cline.openaiBaseUrl": "https://taotoken.net/api", "cline.openaiApiKey": "sk-你的Key", "cline.openaiModelId": "gpt-4o", "cline.maxTokens": 8192, "cline.temperature": 0 }注意 Model ID 必须写gpt-4o,不要写gpt-4o-2024-xx这种带日期的版本号,TaoToken 的模型映射以文档为准。temperature 设 0 是为了让两组对照的随机性降到最低,否则跑分波动会掩盖 AGENTS.md 的真实影响。
如果你用 Codex 风格的 agent,配置在~/.codex/auth.json和~/.codex/config.toml。auth.json 里放 Key:
{ "openai_api_key": "sk-你的Key" }config.toml 里放 Base URL 和模型:
[model] provider = "openai" base_url = "https://taotoken.net/api" model_id = "gpt-4o" max_tokens = 8192 temperature = 0.0三件套齐了:Base URL 是https://taotoken.net/api,Key 是sk-开头那串,Model ID 是gpt-4o。缺任何一个都会在第一次请求时报错,常见的是 401 或 model not found。
最后提醒一点:跑评测前先把仓库快照的 git 状态清理干净。SWE-bench Lite 的每个任务都对应一个特定 commit,如果你本地有未提交的改动,agent 可能会基于错误的代码状态解题,导致结果不可比。用git checkout <commit>和git clean -fdx确保干净。
4. 验证请求与跑分对比:33.5% vs 29.6% 的复现过程
配置就绪后,先发一个最小验证请求,确认 agent 框架能正常调用 GPT-4o 并执行工具。我用的是一个简单的“读文件-改文件-跑测试”循环,任务是在一个玩具仓库里修一个 off-by-one 错误。验证脚本的核心逻辑:
import subprocess from openai import OpenAI client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url=os.environ["TAOTOKEN_BASE_URL"] ) tools = [ { "type": "function", "function": { "name": "read_file", "description": "读取指定路径的文件内容", "parameters": { "type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"] } } }, { "type": "function", "function": { "name": "run_tests", "description": "运行测试命令并返回输出", "parameters": { "type": "object", "properties": {"cmd": {"type": "string"}}, "required": ["cmd"] } } } ] messages = [ {"role": "system", "content": "你是一个代码修复 agent,通过工具读取和修改文件。"}, {"role": "user", "content": "修复 src/calc.py 里的 off-by-one 错误,让 tests/test_calc.py 通过。"} ] for turn in range(10): resp = client.chat.completions.create( model="gpt-4o", messages=messages, tools=tools, temperature=0 ) msg = resp.choices[0].message messages.append(msg) if not msg.tool_calls: break for call in msg.tool_calls: # 执行工具,把结果 append 回 messages ...跑通后你会看到 agent 在几轮内读完文件、改掉range(len(arr) - 1)为range(len(arr))、跑测试通过。这一步确认了工具调用链路和 API 端点都正常。
然后上 SWE-bench Lite 全量。两组各跑 300 个任务,每组跑两次取平均,减少随机波动。结果如下:
| 组别 | 任务完成率 | 平均 token 消耗 | 平均轮次 |
|---|---|---|---|
| 无 AGENTS.md | 33.5% | 基准值 | 12.3 |
| 自动生成 AGENTS.md(400 行) | 29.6% | +20.4% | 15.7 |
| 精简 AGENTS.md(30 行) | 34.8% | +3.1% | 12.9 |
自动生成那组的失败用例很有意思。我抽了 20 个失败任务做归因,发现三类问题。第一类是“注意力偏移”:agent 在解题前先读了 AGENTS.md 里的“架构概述”,然后花 2-3 轮确认自己的修改符合概述里的分层规则,结果超时。第二类是“错误锚定”:AGENTS.md 里写了“使用 Redux 管理状态”,但那个任务实际要改的是一个用 Context API 的旧模块,agent 试图把代码改成 Redux 风格,测试自然不过。第三类是“冗余干扰”:AGENTS.md 里列了目录结构,agent 在搜索目标文件时被这些已知路径带偏,去了错误的目录。
精简版那组反而比无上下文高了 1.3 个百分点。提升不大,但方向是对的。它帮助 agent 避开了几个“地雷”任务——比如有个任务要改序列化逻辑,agent 本来可能去动serializer_v1.py,但 AGENTS.md 里明确说了那是废弃文件,它直接去了serializer_v2.py。这种“地雷”信息是代码里读不出来的,因为两个文件都在仓库里,agent 无法从代码本身判断哪个是陷阱。
还有一个发现:用 GPT-5.2 或更强的模型生成 AGENTS.md,并不会让结果变好。我试过让 GPT-5.2 扫描仓库生成上下文文件,生成的版本更详细、更“专业”,但跑分比 GPT-4o 生成的还低 0.8 个百分点。原因可能是强模型更倾向于写“全面”的文档,冗余更多。这印证了一个判断:上下文文件的质量不取决于生成它的模型有多强,而取决于它是否只包含代码无法表达的信息。
如果你要自己复现,建议先跑 50 个任务的子集,确认两组差异方向一致,再跑全量。50 个任务的跑分波动大约 ±3 个百分点,300 个任务能压到 ±1.5 个百分点。另外记得把每次请求的 token 数记下来,TaoToken 的控制台有用量统计,或者你在代码里累加resp.usage.total_tokens。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
跑这个实验的过程中,我踩过的坑基本集中在 API 配置和 agent 框架的兼容性上。下面按报错原文对照排查,你可以直接搜关键词。
401 Unauthorized。最常见的原因是 Key 没生效。先确认echo $TAOTOKEN_API_KEY输出的是sk-开头的完整字符串,没有多余空格或换行。如果环境变量没问题,检查 base_url 是不是写成了https://taotoken.net/api/带尾斜杠,有些 SDK 会把尾斜杠和路径拼接成//v1/chat/completions,导致鉴权失败。正确写法是https://taotoken.net/api,不带尾斜杠。还有一种情况是 Key 被复制时少了最后几位,去控制台重新复制一次。
local proxy failed。这个报错通常出现在 agent 框架试图走本地代理时。如果你在 settings 里配了http_proxy或https_proxy环境变量,先 unset 掉再跑。TaoToken 的端点不需要额外代理,直连即可。另外检查 agent 框架的配置文件里有没有proxy字段,有就删掉。Cline 的 settings.json 里如果残留了旧的 proxy 配置,也会报这个错。
reading 'choices' of undefined。这是 JavaScript 系 agent 框架的典型报错,意思是 API 返回体里没有choices字段。原因通常是请求根本没发出去,或者返回的是错误对象。先看完整返回体:在代码里console.log(JSON.stringify(resp)),如果看到{"error": {"message": "..."}},那就是鉴权或模型名的问题。常见的是 Model ID 写错,比如写了gpt4o而不是gpt-4o,或者写了gpt-4o-2024-08-06这种带日期的版本号而端点不支持。统一用gpt-4o。
OAuth 相关报错。如果你用 Claude Code 接入,可能会遇到 OAuth token 过期或无效的提示。Claude Code 默认走 Anthropic 的 OAuth 流程,但通过 TaoToken 接入时应该用 API Key 模式。检查~/.claude/settings.json里有没有残留的 OAuth 配置,有就清掉,改成 API Key 方式。具体步骤在 https://taotoken.net/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=ClaudeCodeAnthropic&utm_campaign=rewrite 里有说明。如果还是报 OAuth 错,试试删掉~/.claude/下的缓存文件重新登录。
agent 跑着跑着卡住不动。不报错但没输出,通常是单任务超时了。SWE-bench Lite 的某些任务确实很难,agent 可能陷入循环。检查你的--max_turns和--timeout设置,30 轮和 600 秒是合理值。如果 agent 在某一轮反复调用同一个工具,可能是工具返回的结果格式不对,agent 无法解析。在工具执行函数里加日志,看每次返回的字符串是不是符合预期。
跑分结果和预期差太多。先确认两组的仓库快照是同一个 commit,用git rev-parse HEAD对比。然后确认 temperature 都是 0。如果还是差很多,检查 AGENTS.md 是不是被 agent 框架自动加载了——有些框架会默认读取根目录的 AGENTS.md,你在对照组里即使没传参数,它也可能自动加载。在框架配置里显式关掉自动加载,或者把对照组跑在另一个没有 AGENTS.md 的仓库副本里。
token 消耗异常高。如果单任务 token 数超过 10 万,大概率是 agent 把整个文件读进了上下文。检查你的 read_file 工具是不是没有行数限制。加一个max_lines参数,默认只读前 200 行,需要更多时让 agent 显式指定。另外 AGENTS.md 本身也会被反复注入每一轮对话,400 行的文件在 30 轮里就是 12000 行 token,这也是自动生成版成本高的原因之一。
排查完这些,你的实验应该能稳定复现了。如果还有问题,去接入文档页 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 搜报错关键词,或者直接在模型对话页 https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite 里发一个最小请求,确认端点本身是通的。
6. 把 AGENTS.md 当缓存,不是文档
跑完这一轮,我最大的感受是:AGENTS.md 应该被当成一个“代码无法编码的团队决策缓存”,而不是一份仓库说明书。缓存的特点是——命中时省事,冗余时拖累。你往里塞的每一条信息,都要问自己:agent 读代码能不能自己发现?能,就删掉。不能,才留下。
具体到操作上,我现在的习惯是每季度清理一次 AGENTS.md。把那些“项目概述”“技术栈”“目录结构”章节全删了,只留三类内容:环境怪癖(uv 还是 pip、bun 还是 npm)、地雷(废弃文件、历史遗留配置)、团队决策(命名约定、错误码规范、架构意图)。这三类信息的共同点是:代码里读不出来,但 agent 不知道就会踩坑。
如果你正在维护一个大型仓库,建议先做一次“AGENTS.md 审计”:把现有文件里的每一条规则拿出来,问“如果删掉这条,agent 会不会犯错?”如果答案是“不会,它读代码就知道了”,那就删。我审计过一个 500 行的 AGENTS.md,最后只留了 28 行,跑分反而涨了。你的 CFO 也会感谢你——那 20% 的推理成本省下来,够跑好几轮评测了。
最后留一个可执行的下一步:今天就去你的仓库根目录,把 AGENTS.md 里所有“介绍性”内容删掉,只留“地雷”和“环境怪癖”。然后跑一个你手头的小任务,对比删之前和删之后的 agent 表现。如果任务完成率没降、token 消耗降了,你就知道该怎么做了。如果完成率降了,把删掉的内容加回来,逐条测试哪一条真正有用。这个过程本身,就是一次对仓库可发现性的体检。