1. 先搞清楚:AGENTS.md 到底是 Prompt 还是 Readme
同事那句“你的 AGENTS.md 当 Prompt 还是当 Readme”,其实戳中了一个很常见的误区。很多人第一次写 AGENTS.md,会下意识把它当成项目说明书来写:项目背景、目录结构、技术栈介绍、如何安装依赖、如何贡献代码,洋洋洒洒几百行。结果 Codex 读完之后,改代码还是乱来,构建命令还是猜,命名风格还是飘。
问题不在 Codex 不聪明,而在于你把一份“给 Agent 的执行指令”写成了“给人的阅读材料”。这两者的目标完全不同。Readme 是让人快速理解项目,允许铺垫、允许背景、允许“本项目致力于打造……”这种叙述。AGENTS.md 是让 Agent 在每一次改代码时知道“该怎么做、不该怎么做”,它需要的是命令、约束、优先级,而不是故事。
我自己的判断标准很简单:如果一句话删掉之后,Agent 的行为不会发生任何变化,那这句话就不该出现在 AGENTS.md 里。比如“本项目采用微服务架构”这种描述,Agent 看完也不会因此改变任何操作;但“新增服务必须放在 services/ 目录下,且 crate 名以 codex- 为前缀”就会直接改变它的文件创建行为。
所以 AGENTS.md 的本质是 Prompt,而且是那种“启动时注入、运行中持续生效”的项目级 Prompt。它和你在对话框里临时敲的那句“帮我重构一下”不是一回事。临时 Prompt 是单次任务指令,AGENTS.md 是持久化的项目约定。它更像是一份写给 Agent 的“团队规范手册”,而不是写给新人的“项目导览”。
这里必须把 CLAUDE.md 拉进来对照,因为很多人是 Claude Code 和 Codex 双开。CLAUDE.md 是 Claude Code 的私有指令文件,只有 Claude Code 认;AGENTS.md 是一个开放标准,目前被大量工具支持,包括 Codex、Copilot、Cursor、Aider、Zed 等。一份文件多个 Agent 通用,这是它最大的价值。我通常的做法是:把通用规则写在 AGENTS.md,然后在 CLAUDE.md 里用一行@AGENTS.md把它导入进来,再补充 Claude Code 特有的 Skills、hooks 配置。这样通用规则只维护一份,两边都生效。
理解了“它是 Prompt 不是 Readme”这个定位,后面的加载机制、写法模板、验证动作才有意义。接下来先解决接入层的问题:不管你用 Codex 还是 Claude Code,多工具并存时 Key 和 Base URL 的管理会变得很碎,我用 TaoToken 的统一通道来收敛这件事。
2. TaoToken 统一 Key 通道:多工具接入的前置准备
当你同时用 Codex、Claude Code、Cursor 这类工具时,最烦的不是写 AGENTS.md,而是每个工具都要单独配一遍 Key、Base URL、Model ID。Codex 走~/.codex/config.toml,Claude Code 走环境变量或 settings,Cursor 又是另一套 UI。时间一长,你自己都记不清哪个工具用的是哪个 Key,排查 401 的时候要翻四五个配置文件。
TaoToken 在这里的作用是把“接入层”统一掉:一个 Key、一个 Base URL,多个工具共用。它的 API 地址是https://taotoken.net/api,官网是https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。注意 API 地址不带 UTM 参数,配置里就写干净的https://taotoken.net/api。
先说清楚它适合谁:如果你只是偶尔用一次 Codex,那没必要折腾统一通道;但如果你是“文用 Claude Code、武用 Codex”这种双开甚至多开状态,或者团队里几个人共用一套模型额度,那统一 Key 通道能省掉大量重复配置和排障时间。
接入前你需要准备三样东西,我把它叫做“三件套”,后面每个工具的配置都会用到:
第一是 Base URL,统一写https://taotoken.net/api。第二是 API Key,在控制台的 API Keys 页面创建,地址是https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。第三是 Model ID,这个取决于你要接的模型,在模型对话页面可以先验证一下模型是否可用,地址是https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。
这里有个坑要提前说:不同工具对 Base URL 的拼接方式不一样。有的工具会自动在 Base URL 后面拼/v1/chat/completions,有的要求你写全。TaoToken 的 API 根是https://taotoken.net/api,如果某个工具报 404,先检查是不是它自己又拼了一层路径。我的习惯是先用 curl 验证根路径通不通,再去配具体工具。
验证根路径连通性的命令很简单:
curl -s -o /dev/null -w "%{http_code}\n" https://taotoken.net/api如果返回 401 或 403,说明网络通了但没带 Key,这是正常的;如果返回 404,说明路径不对;如果直接超时,那是网络层的问题,跟 Key 无关。这一步能帮你快速区分“配置错”和“网络错”,省掉很多瞎猜。
拿到三件套之后,先别急着写 AGENTS.md。正确的顺序是:先把工具接入跑通,确认模型能正常返回,再去调 AGENTS.md 的内容。因为如果接入层是坏的,你根本分不清是 AGENTS.md 写得不好,还是请求压根没发出去。这个顺序很多人会搞反,先埋头写一堆规则,结果发现 Codex 根本没读到文件,白忙一场。
3. 可复制配置:AGENTS.md 双身份模板与 Codex config.toml
这一节是全文的核心,给你可以直接抄的配置。先讲 Codex 的加载机制,再给 AGENTS.md 的模板,最后给~/.codex/config.toml的完整片段。
Codex 启动时会构建一条指令链,这个过程只执行一次。加载分两层。第一层是全局配置,去~/.codex/目录找:如果存在AGENTS.override.md就读它,不存在就读AGENTS.md,两者只取一个,不叠加。第二层是项目配置,从项目根目录(通常是 Git 根目录)一路走到你当前的工作目录,每到一个目录按AGENTS.override.md → AGENTS.md → fallback 文件名的顺序查找,找到的文件按顺序拼接,后面的优先级高于前面的。
举个例子,项目结构是这样:
my-project/ ├── AGENTS.md ├── services/ │ └── payments/ │ └── AGENTS.override.md └── frontend/ └── AGENTS.md如果你在services/payments/下启动 Codex,加载路径是:~/.codex/AGENTS.md(全局默认)→my-project/AGENTS.md(项目根)→my-project/services/payments/AGENTS.override.md(当前目录覆盖)。三份拼接,后面的覆盖前面的。
AGENTS.override.md的设计很巧妙:它替代同级的AGENTS.md,而不是叠加。所以你可以用它做临时实验——公司有一份统一的全局规则,你今天想换一套做实验,就建一个 override,实验完删掉,原文件不受影响。
现在给~/.codex/config.toml的完整片段,这是接入 TaoToken 统一通道的关键:
# ~/.codex/config.toml # 模型接入:TaoToken 统一 Key 通道 model = "你的 Model ID" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY" # AGENTS.md 加载相关 project_doc_max_bytes = 65536 project_doc_fallback_filenames = ["CLAUDE.md", "TEAM_GUIDE.md", ".agents.md"]这里有几个点要解释。base_url写https://taotoken.net/api,不要带 UTM。env_key指定从哪个环境变量读 Key,所以你要在 shell 里设置:
export TAOTOKEN_API_KEY="你的 API Key"project_doc_max_bytes默认是 32 KiB,所有 AGENTS.md 拼接后的总大小超过这个值会被截断。我调到 65536,给多目录拼接留余量。project_doc_fallback_filenames是 fallback 列表,如果你的项目历史原因用的是CLAUDE.md或TEAM_GUIDE.md,加进来 Codex 就会当 AGENTS.md 处理。这一条对双开用户特别有用——你甚至可以不建 AGENTS.md,直接让 Codex 读 CLAUDE.md。
接下来是 AGENTS.md 的模板。记住原则:只写 Agent 推断不出来的东西。我把它分成四块。
# AGENTS.md ## 构建与测试命令 - 构建:`cargo build --workspace` - 快速测试:`cargo test -p codex-core` - 全量测试:`cargo test --workspace` - 格式化:`just fmt`(改完代码必须执行) - Lint:`cargo clippy --workspace -- -D warnings` ## 编码规范 - 新增 crate 名必须以 `codex-` 为前缀,例如 `codex-core` - 格式化字符串时优先内联变量,例如 `format!("{name}")` 而非 `format!("{}", name)` - 避免模糊的 bool/Option 参数,优先用 enum 或具名方法 - match 语句必须穷举,禁止用通配符 `_` 兜底 ## 红线规则 - 禁止修改与沙箱环境变量相关的代码 - 禁止提交 `.env` 文件 - 不要向已经臃肿的 `codex-core` crate 添加新功能,考虑新建 workspace crate ## 代码定位策略 - 优先用 `glob` 定位文件,再用 `grep` 搜索符号,最后才 `read` - `search_code` 是 RAG 辅助,不作为首选这份模板短小精准,没有一句废话。对比一下 Readme 风格的写法——“本项目是一个基于 Rust 的编程助手,采用模块化设计,致力于提供高效的代码生成能力”——这种句子删掉,Agent 行为零变化,所以不该出现。
如果你要双开 Claude Code,CLAUDE.md 这样写:
# CLAUDE.md @AGENTS.md ## Claude Code 专属配置 - Skills 引用见 `.claude/skills/` - memory 规则:长期记忆写入 `.claude/memory/` - hooks 配置见 `.claude/settings.json`@AGENTS.md这一行把通用规则导入,下面只写 Claude Code 特有的东西。这样改 AGENTS.md,两边同时生效。
4. 验证请求:确认 Codex 真的读到了 AGENTS.md
配置写完不代表生效,必须验证。很多人配完就以为万事大吉,结果 Codex 压根没读到文件,还在那儿纳闷“为什么规则不生效”。这一节给你几个可执行的验证动作。
第一步,验证接入层通不通。先用 curl 打一次对话请求,确认 Key 和 Base URL 没问题:
curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "你的 Model ID", "messages": [{"role": "user", "content": "回复 OK 两个字母"}] }'如果返回里有choices字段和正常内容,说明接入层通了。如果返回 401,检查 Key;如果返回local proxy failed或连接错误,检查 Base URL 和网络;如果返回里choices为空或报reading choices相关错误,多半是模型 ID 写错了。
第二步,验证 Codex 读到了 AGENTS.md。最直接的办法是在 AGENTS.md 里放一条“可观测规则”,比如加一句“所有回复开头必须带上[AGENTS-LOADED]标记”。然后启动 Codex 问一个简单问题,看它是否带这个标记。验证完记得删掉这条规则,它只是用来测试的。
第三步,验证加载顺序。在项目根目录和子目录各放一份 AGENTS.md,写不同的规则,然后在子目录启动 Codex,问它“当前生效的构建命令是什么”,看它回答的是哪一份。这能帮你确认拼接顺序符合预期。
第四步,检查是否被截断。如果你的 AGENTS.md 很长,用这个命令看总字节数:
find . -name "AGENTS.md" -o -name "AGENTS.override.md" | xargs wc -c把所有匹配文件的大小加起来,对比project_doc_max_bytes。超了就会被截断,后面的内容读不到。这也是为什么我一直强调“短小精准”——写太长不仅遵循率下降,还可能直接被截断。
第五步,验证 CLAUDE.md 的 fallback 是否生效。如果你在config.toml里配了project_doc_fallback_filenames = ["CLAUDE.md"],那就删掉或重命名 AGENTS.md,只留 CLAUDE.md,启动 Codex 看规则是否还生效。生效说明 fallback 配置对了。
实测下来,这五步走完,你对“Codex 到底读到了什么”会非常清楚。后面再出问题,你就能快速定位是接入层、加载层还是内容层的问题,而不是一通乱改。
5. 常见报错排查:401、local proxy failed、reading choices、OAuth
这一节把最常见的几类报错摊开讲,每个都给你现象、原因、解决动作。这些是我自己踩过的坑,也是社群里问得最多的。
401 Unauthorized。现象是请求直接被拒,返回体里带 401。原因通常是三种:Key 没设置、Key 设了但没 export、Key 写错了。排查顺序:先echo $TAOTOKEN_API_KEY看环境变量有没有值;再看config.toml里的env_key是不是写成了TAOTOKEN_API_KEY,大小写要一致;最后确认 Key 没有多余空格或换行。注意,如果你在config.toml里直接写 Key 而不是用环境变量,某些版本可能不认,建议统一用env_key。
local proxy failed。现象是连接失败,提示本地代理相关错误。这个多半是 Base URL 写错,或者工具自己拼了一层路径导致 404。先确认base_url = "https://taotoken.net/api",不要带/v1,也不要带 UTM 参数。然后用第 4 节的 curl 命令直接打一次,如果 curl 通但 Codex 不通,那就是 Codex 的配置问题,检查config.toml的[model_providers.taotoken]段有没有拼写错误。
reading choices 相关错误。现象是返回体解析失败,提示读取choices字段出错。这通常是模型 ID 写错了,或者返回的不是标准 OpenAI 格式。先确认 Model ID 在模型对话页面能正常用,再检查请求体格式。如果返回体里根本没有choices,可能是模型名不对导致服务端返回了错误结构。
OAuth 相关报错。如果你用的是 Codex 的 OAuth 登录模式,又同时配了自定义 provider,可能会冲突。现象是提示认证方式不匹配。解决动作:确认你是走 API Key 模式还是 OAuth 模式,两者不要混用。走 TaoToken 统一 Key 通道时,用env_key方式,不要同时开 OAuth。
配置改了不生效。现象是改了config.toml或 AGENTS.md,Codex 行为没变。原因通常是 Codex 启动时只加载一次指令链,运行中不会动态重载。解决动作:完全退出 Codex 再重新启动。另外确认你改的是当前工作目录链路上的文件,不是别的目录的。
AGENTS.md 被截断。现象是后面的规则不生效。用第 4 节的wc -c命令算总大小,对比project_doc_max_bytes。超了就精简内容,或者调大这个值。但我的建议是精简,因为长文件本身遵循率就低。
把这几类报错和对应动作整理成一张表,方便你对照:
| 报错现象 | 最可能原因 | 解决动作 |
|---|---|---|
| 401 Unauthorized | Key 未设置或写错 | 检查env_key和环境变量 |
| local proxy failed | Base URL 错误 | 确认https://taotoken.net/api |
| reading choices 失败 | Model ID 错误 | 在模型对话页验证模型 |
| OAuth 冲突 | 认证模式混用 | 统一用 API Key 模式 |
| 配置不生效 | 未重启 Codex | 完全退出后重启 |
| 规则被截断 | 超过 max_bytes | 精简或调大配置 |
排查的核心思路是分层:先确认接入层(curl 能不能通),再确认加载层(Codex 读没读到),最后确认内容层(规则写得对不对)。大部分人一上来就改内容,其实问题往往在前两层。
6. 长期编码与多工具协同:把统一通道用起来
如果你只是偶尔用 Codex 改个小脚本,那到上一节就够了。但如果你是长期用 Codex 做工程、或者 Claude Code 和 Codex 双开跑 Agent 任务,那接入层的稳定性就变得很重要。这时候可以考虑用 Coding Plan 来管理长期额度,地址是https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。
为什么长期编码场景要单独说?因为 Agent 任务的特点是“一个 Turn 里几十次模型推理加工具调用”,token 消耗是持续且密集的。如果接入层不稳定,中途断一次,整个任务就得重来。统一 Key 通道的价值在这里体现得最明显:Codex、Claude Code、Cursor 共用一套 Key 和 Base URL,你只需要维护一份配置,排查问题时也只有一个入口。
回到 AGENTS.md 的双身份。当你把通用规则收敛到 AGENTS.md,CLAUDE.md 只做增强,多工具协同时的规则一致性就有了保障。Codex 天然读 AGENTS.md,Claude Code 通过@AGENTS.md导入,Cursor 这类工具也认 AGENTS.md。你改一次通用规则,所有工具同步生效,不会出现“Codex 按 A 规则、Claude Code 按 B 规则”的割裂。
最后给一个我自己的实践习惯:把 AGENTS.md 当成代码来维护,纳入版本控制,每次调整规则都写清楚为什么改。因为规则这东西,写的时候觉得都对,过两周你自己都忘了某条是干嘛的。留个注释,比事后猜要省事得多。
如果你还没配好接入层,先去 API Keys 页面创建 Key,再对照第 3 节的config.toml片段配一遍,然后用第 4 节的 curl 验证。接入通了,再去调 AGENTS.md 的内容。顺序别反,反了就是白忙。