1. 从一次"配置不生效"说起:Codex 本地 Agent 的配置体系到底怎么运转
很多人第一次接触 Codex 的本地自定义 Agent,都会经历一个非常相似的场景:照着文档把config.toml写好了,AGENTS.md也放在项目根目录了,结果启动之后发现模型还是默认那个,Agent 的行为也没按自己写的规则走。于是开始怀疑是不是版本问题、是不是路径放错了、是不是要重启终端。折腾半小时之后才发现,问题出在对"配置优先级"的理解上——Codex 的配置不是一个单一文件说了算,而是多层配置叠加、按优先级覆盖的结果。
这篇内容就是围绕这个核心问题展开的。我会把 Codex 本地自定义 Agent 的配置体系拆成三块来讲:TOML 配置文件的结构与作用域、AGENTS.md 的语义与加载逻辑、以及多层配置之间的优先级规则。这三块是理解 Codex Agent 定制化的地基,搞清楚了它们,你才能稳定地让 Agent 按你的预期工作,而不是靠反复试错碰运气。
适合读这篇的人包括:已经在用 Codex CLI 但配置总是"时灵时不灵"的开发者、想给团队统一 Agent 行为规范的工程负责人、以及准备把 Codex 接入自有模型服务(比如本地部署的推理服务或第三方兼容接口)的技术同学。文中涉及的操作都以本地环境为主,不涉及任何网络访问层面的特殊配置,全部围绕配置文件本身展开。
先说一个结论性的判断:Codex 的配置体系本质上是"就近覆盖 + 显式优先"。越靠近当前工作目录的配置,优先级越高;越显式声明的配置项,越容易覆盖默认值。理解这句话,后面所有的细节都是它的展开。
2. TOML 配置文件的分层结构:哪些字段真正影响 Agent 行为
2.1 全局配置与项目配置的物理位置差异
Codex 的 TOML 配置通常存在两个层级:一个是用户级的全局配置,放在用户主目录下的配置目录里;另一个是项目级的配置,放在项目根目录。这两个层级的文件格式完全一样,但作用范围不同。全局配置对所有项目生效,项目配置只对当前项目生效。
这里有个容易被忽略的点:项目级配置并不是"追加",而是"覆盖"。也就是说,如果全局配置里写了model = "A",项目配置里写了model = "B",那么在这个项目里生效的是 B,而不是两个都生效或者合并。对于标量字段(字符串、数字、布尔值)来说,覆盖关系很直观;但对于表(table)和数组来说,行为会稍微复杂一些,后面会单独讲。
我建议的做法是:全局配置只放那些你希望所有项目都一致的项,比如默认模型、默认的推理参数、日志级别。而项目特有的东西,比如这个项目要用哪个模型、要不要开启某个实验性功能,全部放到项目级配置里。这样做的原因是,项目配置会跟着代码仓库走,团队成员拉下来就能用同一套配置,减少"我这里能跑你那里不能跑"的扯皮。
2.2 模型相关字段:model、provider 与推理参数
模型配置是 TOML 里最核心的部分。通常涉及几个关键字段:指定使用哪个模型、指定模型来自哪个提供方、以及一系列推理参数(温度、最大输出长度、top_p 等)。
这里要特别强调一个实践中的坑:模型名称和提供方名称是两个独立维度。很多人只改了模型名,没改提供方,结果请求发到了错误的端点,报错信息又很含糊,看起来像是"模型不存在",实际上是"提供方不匹配"。正确的做法是成对修改,改完用一次最小请求验证。
推理参数这块,我的经验是不要一上来就调一堆。先把温度固定在一个保守值(比如 0.2 左右),保证输出稳定可复现,等 Agent 行为调通了再去微调创造性相关的参数。因为 Agent 场景和纯聊天场景不一样,Agent 往往要执行多步操作,参数太"发散"会导致每一步都有小偏差,累积起来整个任务就跑偏了。
下面是一个典型的模型配置片段,字段名以实际版本为准,这里展示结构:
[model] name = "your-model-name" provider = "your-provider" temperature = 0.2 max_output_tokens = 4096注意:不同版本的 Codex 对字段命名可能有细微差异,改配置前先确认你当前版本的字段规范,不要直接照搬旧版本的写法。
2.3 表与数组的合并行为:为什么你的配置"只生效了一半"
前面提到标量字段是覆盖关系,但表和数组不是。这是很多人配置"只生效一半"的根本原因。
假设全局配置里有一个[tools]表,里面定义了三个工具;项目配置里也有一个[tools]表,只定义了一个工具。最终生效的往往不是"三个加一个",而是项目级的那个表整体替换掉全局的表,或者按字段逐个覆盖——具体行为取决于实现。数组也是类似,很多配置系统对数组是"整体替换"而非"追加"。
所以当你发现"我明明在项目里加了一个工具,怎么全局配的那些工具都不见了",大概率就是踩了这个坑。解决办法有两个:要么在项目配置里把需要的项全部写全,要么确认你的版本是否支持某种合并语法。我个人的习惯是项目配置写全,虽然啰嗦,但行为可预测,不会因为全局配置改动而意外影响项目。
2.4 环境变量与 TOML 的关系:谁说了算
除了 TOML 文件,Codex 通常还支持通过环境变量注入配置。这就引出了另一个优先级问题:环境变量和 TOML 谁优先?
一般规律是环境变量优先于配置文件,因为环境变量更"临时"、更"显式",通常用于覆盖某次运行的特定值。但这个规律不是绝对的,具体要看实现。我的建议是:不要把同一个配置项同时写在环境变量和 TOML 里,否则你会在排查问题时陷入"到底哪个生效了"的困境。如果确实需要临时覆盖,用完就清理掉环境变量,保持配置来源单一。
排查配置问题时,一个非常实用的技巧是:让 Codex 打印出最终生效的配置。很多 CLI 工具都有类似--show-config或者 verbose 模式的选项,能看到合并后的结果。这比对着几个文件猜要高效得多。
3. AGENTS.md 的加载逻辑:它和 TOML 是两套不同的机制
3.1 AGENTS.md 到底解决什么问题
如果说 TOML 管的是"Agent 用什么模型、开什么功能"这类运行时参数,那么 AGENTS.md 管的是"Agent 应该怎么做事"这类行为指令。它是一个 Markdown 文件,内容会被注入到 Agent 的上下文里,作为系统级或项目级的指导说明。
举个直观的例子:你可以在 AGENTS.md 里写"本项目的所有代码改动必须附带单元测试""提交信息使用约定式提交格式""不要修改vendor/目录下的任何文件"。这些规则不是通过代码强制执行的,而是通过自然语言告诉 Agent,让它在决策时遵守。
这就是 AGENTS.md 的价值:它把团队的隐性规范显性化,并且让 Agent 能读到。以前这些规范写在 wiki 里、写在 onboarding 文档里,Agent 是看不到的;现在写进 AGENTS.md,Agent 每次工作都会带上这些上下文。
3.2 文件位置与作用域:根目录、子目录与用户级
AGENTS.md 的加载通常遵循"就近原则"。项目根目录的 AGENTS.md 对整个项目生效;子目录里的 AGENTS.md 对该子目录及其下级生效,并且会覆盖或补充上级的规则。
这个设计非常符合直觉:你可以在根目录写通用规范,在某个特殊子目录(比如前端目录、基础设施目录)写针对性的补充规则。Agent 在处理那个子目录的文件时,会同时看到两层规则。
还有一个用户级的 AGENTS.md,放在用户配置目录下,对所有项目生效。适合放一些你个人的通用偏好,比如"回答尽量简洁""代码注释用中文"这类。但要注意,用户级规则和项目级规则冲突时,通常是项目级优先,因为项目规范应该压过个人偏好。
3.3 内容写法:什么样的 AGENTS.md 真正有效
写 AGENTS.md 最大的误区是把它写成一篇散文。Agent 不是人,它不会"领会精神",它只会按字面理解。所以有效的 AGENTS.md 应该具备几个特征:
第一,指令要具体、可执行。"注意代码质量"是无效的,"所有新增函数必须有 docstring,且 docstring 要说明参数和返回值"才是有效的。
第二,用列表和分节组织。大段文字容易被忽略,结构化的条目更容易被准确执行。可以用二级标题分节,比如"代码风格""测试要求""提交规范"。
第三,明确边界和禁止项。告诉 Agent 什么不能做,往往比告诉它什么能做更重要。比如"禁止直接修改数据库迁移文件,必须新建迁移"。
第四,控制长度。AGENTS.md 的内容会占用上下文窗口,写得太长会挤占实际任务的空间。我的经验是控制在几百行以内,只放真正重要的规则,细节可以放到被引用的其他文档里。
下面是一个结构示例:
## 代码风格 - 使用项目已有的格式化工具,不要手动调整缩进 - 新增函数必须包含类型注解 ## 测试要求 - 每个新增的公共函数都要有对应测试 - 测试文件放在与被测文件同级的 tests 目录 ## 禁止事项 - 不要修改 vendor 目录 - 不要提交包含密钥的文件3.4 AGENTS.md 与 TOML 的协作关系
这两者不是替代关系,而是互补。TOML 决定"用哪个模型、开哪些能力",AGENTS.md 决定"在这个项目里怎么用这些能力"。一个常见的错误是试图用 AGENTS.md 去配置模型参数,或者用 TOML 去写行为规范,结果两边都不生效。
正确的分工是:凡是能用配置项表达的,放 TOML;凡是需要自然语言描述的规范,放 AGENTS.md。比如"用哪个模型"是配置项,放 TOML;"写代码时要遵循什么风格"是规范,放 AGENTS.md。
4. 优先级规则实战:当多层配置打架时谁赢
4.1 优先级的一般规律与验证方法
把前面讲的串起来,Codex 配置的优先级大致遵循这样的顺序(从高到低):
| 优先级 | 配置来源 | 典型用途 |
|---|---|---|
| 1 | 命令行参数 | 单次运行的临时覆盖 |
| 2 | 环境变量 | 会话级或 CI 环境的覆盖 |
| 3 | 项目级 TOML | 项目统一的运行时配置 |
| 4 | 用户级 TOML | 个人默认偏好 |
| 5 | 内置默认值 | 兜底 |
AGENTS.md 的优先级则是:子目录 > 项目根目录 > 用户级。注意 AGENTS.md 和 TOML 是两条独立的线,不要把它们混在一个优先级序列里比较。
验证优先级最靠谱的方法不是背规则,而是做对照实验:同一个配置项,在两个层级写不同的值,然后观察实际生效的是哪个。花十分钟做一次实验,比看半天文档管用。
4.2 一个真实的排查案例:模型配置被谁覆盖了
我遇到过这样一个情况:项目 TOML 里明明写了模型 A,但实际跑起来用的是模型 B。排查过程是这样的:
第一步,确认项目 TOML 的路径对不对。结果发现文件放错了目录,放到了上一级,根本没被加载。这是最常见的低级错误,先排除。
第二步,确认环境变量。发现 shell 的启动脚本里 export 了一个模型相关的环境变量,指向模型 B。因为环境变量优先级高于项目 TOML,所以 B 赢了。
第三步,清理环境变量,重新运行,模型 A 生效。
这个案例的教训是:排查配置问题要按优先级从高到低逐层排除,而不是盯着你改的那个文件看。很多时候问题不在你改的地方,而在你没注意到的更高优先级来源。
4.3 团队协作场景下的配置管理建议
团队里多人用 Codex,配置管理容易乱。我的建议是:
- 项目级 TOML 和 AGENTS.md 都提交到仓库,作为项目规范的一部分,新人拉下来就有统一行为。
- 个人偏好放用户级配置,不要污染项目配置。
- 敏感信息(如密钥)绝不写进任何提交的文件,用环境变量或本地未跟踪的配置文件。
- 在 README 里说明配置的加载顺序,减少新人踩坑。
这样做的核心思路是:让"项目相关"的配置跟着项目走,让"个人相关"的配置跟着人走,边界清晰,冲突就少。
5. 自定义 Agent 的落地细节:从配置到可用的完整链路
5.1 定义 Agent 角色与能力边界
配置好模型和规范之后,下一步是定义 Agent 本身。一个自定义 Agent 通常需要明确几件事:它的角色是什么(比如"代码审查助手""文档生成器")、它能访问哪些工具、它的输出格式是什么。
角色定义可以放在 AGENTS.md 里,也可以放在单独的提示词文件里。我的做法是:通用规范放 AGENTS.md,特定 Agent 的角色提示放单独文件,然后在配置里引用。这样切换 Agent 时不用改 AGENTS.md,职责更清晰。
能力边界这块要特别注意。给 Agent 开放工具权限时,遵循最小权限原则:只给它完成任务必需的工具。比如一个只负责写文档的 Agent,不需要文件删除权限。这不是不信任模型,而是减少意外操作的风险。
5.2 工具与权限配置的常见写法
工具配置一般在 TOML 里,通过一个工具列表来声明。每个工具可能有自己的参数,比如超时时间、允许的路径范围。
[[tools]] name = "file_read" enabled = true allowed_paths = ["./src", "./docs"] [[tools]] name = "file_write" enabled = true allowed_paths = ["./src"]这里的关键是allowed_paths这类约束字段。能用配置约束的,就不要靠提示词约束。提示词说"不要写 src 以外的文件",模型可能偶尔违反;配置里限制路径,模型想违反也做不到。这是"硬约束优于软约束"的原则。
5.3 多 Agent 场景下的配置隔离
当你同时维护多个 Agent(比如一个写代码、一个做审查、一个写文档),配置隔离就很重要。常见做法是每个 Agent 一个配置目录,里面有自己的 TOML 和提示词文件,通过命令行参数或环境变量切换。
隔离的核心是避免共享可变状态。如果两个 Agent 共用一个配置文件,改一个可能影响另一个。分开之后,每个 Agent 的行为都是可预测的。
6. 那些文档里不会写的踩坑经验
6.1 配置改了不生效的五个高频原因
按出现频率排序:
- 文件路径不对。最常见,尤其是项目级配置放错目录。
- 环境变量覆盖。shell 启动脚本里的 export 是隐形杀手。
- 格式错误导致整个文件被忽略。TOML 对格式敏感,一个语法错误可能让整个文件失效,而且报错信息不一定明显。
- 缓存。有些工具会缓存配置,改完要重启或清缓存。
- 优先级理解错误。以为项目配置一定赢,实际上被更高优先级覆盖了。
排查时按这个顺序走,能解决八成问题。
6.2 AGENTS.md 写太长反而失效
这是个反直觉的经验。AGENTS.md 不是越长越好。写太长有两个问题:一是占用上下文,挤压实际任务空间;二是规则太多时,模型可能顾此失彼,重要的规则反而被淹没。
我的做法是分层:AGENTS.md 只放最高频、最重要的规则,控制在合理长度;详细的规范放到被引用的文档里,需要时再让 Agent 去读。这样既保证了核心规则始终在场,又不会让上下文爆炸。
6.3 模型切换时的兼容性检查清单
换模型是常事,但换完要检查几件事:
- 新模型是否支持你用的所有工具调用格式
- 上下文窗口是否够用(有些模型窗口小,长 AGENTS.md 会超)
- 推理参数是否需要调整(不同模型对温度的敏感度不同)
- 输出格式是否一致(有些模型更爱加解释性文字)
我一般会准备一个最小测试用例,换模型后先跑一遍,确认基本行为正常再投入实际使用。
6.4 配置版本管理的小技巧
把配置纳入版本管理时,注意区分"该提交的"和"不该提交的"。项目级 TOML 和 AGENTS.md 该提交;包含个人路径、密钥的配置不该提交,用.gitignore排除,并提供一份.example模板给团队参考。
这样新人 clone 之后,复制模板、填上自己的值,就能跑起来,既统一又灵活。
7. 把配置体系用顺之后的几点个人体会
配置这东西,前期花时间理清楚,后期省的时间是成倍的。我自己的习惯是:每接手一个新项目,第一件事就是把 TOML 和 AGENTS.md 的加载路径、优先级确认一遍,写个小实验验证,而不是等出问题了再排查。这个前置动作大概花二十分钟,但能避免后面无数次的"为什么没生效"。
另外一个体会是,配置要尽量显式。宁可多写几行,也不要用"我以为它会继承"这种假设。显式配置的好处是,任何人看你的配置文件,都能准确知道最终行为是什么,不需要去脑补合并逻辑。团队协作里,这种可预测性比简洁更重要。
最后,AGENTS.md 的内容建议定期回顾。项目在演进,规范也在变,半年前写的规则可能已经过时了。我一般每个季度过一遍,删掉不再适用的,补上新的约定。保持它精简、准确、有效,Agent 才能真正帮上忙,而不是被一堆过时规则带偏。