1. 从一次配置翻车说起:为什么本地 Agent 和模型配置值得单独聊
先说个真实场景。前段时间我在一台新机器上装好 Codex CLI,兴冲冲地准备接一个本地自定义 Agent 跑任务,结果一上来就给我甩了个cc switch local proxy failed while handling codex endpoint /responses,紧接着又提示the 'gpt-5.6-sol' model is not supported when using codex with a...。折腾了大半天才搞明白,问题根本不在网络,而在于我对 Codex 的配置优先级理解错了——TOML 配置文件、AGENTS.md、环境变量、命令行参数,这几层东西谁覆盖谁,我一开始完全是懵的。
这篇就围绕Codex 本地自定义 Agent 与模型配置这件事,把 TOML 配置、AGENTS.md 约定、以及配置优先级这三块讲透。核心关键词就三个:Codex、Agent、TOML、AGENTS.md、模型配置。适合谁看?适合已经装好 Codex、想接自己的模型服务、想跑自定义 Agent、但被各种配置覆盖关系搞晕的人。如果你还在纠结 Codex 怎么安装、Codex 安装教程、Codex 官网下载这些前置问题,那这篇可以当作进阶篇,装完之后再回来看。
我尽量不写成官方文档的复读机,而是按“我踩过什么坑、为什么这么设计、你该怎么抄作业”的顺序来。涉及具体参数的地方我会给出计算和取舍逻辑,涉及操作的地方我会给可直接复制的配置片段。文中所有配置示例都是基于常见实践的合理补全,你实际用的时候按自己环境微调即可。
2. 配置体系整体设计:三层结构到底谁说了算
2.1 为什么 Codex 要搞这么多层配置
很多人第一次看到 Codex 的配置体系会懵:一个 TOML 文件不够吗,为什么还要 AGENTS.md,为什么还有环境变量和命令行参数?其实这套设计思路和大多数现代 CLI 工具是一致的——分层覆盖。底层给默认值,中间层给项目级约定,上层给临时覆盖。
你可以把它类比成写代码时的变量作用域:全局变量、模块变量、函数局部变量。离你越近的那一层,优先级越高。Codex 的配置层级从低到高大致是这样:
| 层级 | 配置来源 | 作用范围 | 典型用途 |
|---|---|---|---|
| 1 | 内置默认值 | 全局 | 出厂行为 |
| 2 | 用户级 TOML | 当前用户所有项目 | 个人偏好、默认模型 |
| 3 | 项目级 TOML | 当前项目 | 项目专属模型、Agent 定义 |
| 4 | AGENTS.md | 当前目录及子目录 | 给 Agent 的上下文指令 |
| 5 | 环境变量 | 当前会话 | 临时切换、密钥注入 |
| 6 | 命令行参数 | 单次调用 | 一次性覆盖 |
这个顺序不是随便排的。越靠上的层级越“持久”,越靠下的越“临时”。持久层负责稳定行为,临时层负责灵活调试。理解这一点,后面所有覆盖问题都能自己推出来。
2.2 TOML 和 AGENTS.md 的分工不是重复
新手最容易犯的错,是把 TOML 和 AGENTS.md 当成两套可以互相替代的东西。实际上它们管的是完全不同的两件事。
TOML 管的是“怎么跑”:用哪个模型、模型服务地址在哪、超时多少、并发多少、Agent 叫什么名字、绑定哪些工具。这些是机器读的配置,格式严格,写错了直接报错。
AGENTS.md 管的是“跑的时候脑子里想什么”:项目背景、代码规范、禁止事项、常用命令、目录结构说明。这些是给模型读的自然语言上下文,格式宽松,本质上是注入到对话里的系统提示。
打个比方,TOML 是汽车的仪表盘设置——发动机型号、油品标号、胎压;AGENTS.md 是贴在挡风玻璃上的便签——“这车刹车偏软,转弯提前减速”。你不能把便签内容写进仪表盘,也不能指望仪表盘告诉你怎么开。
注意:很多人遇到
ccswitch会覆盖toml这类现象,本质上是某个中间层工具在启动时重写了你的 TOML。搞清楚谁在写、写到哪一层,比盲目改配置有用得多。
2.3 优先级冲突的典型表现
配置冲突不会总是报错,更多时候是“静默生效了错误的那个”。我整理了几种最常见的表现:
- 明明在 TOML 里改了模型,跑起来还是旧模型——大概率是环境变量或命令行参数在覆盖。
- AGENTS.md 写了规范但 Agent 不遵守——可能是文件没放在正确目录,或者被更高优先级的指令冲掉了。
- 报
model is not supported——通常是模型名写对了但服务端点不匹配,属于 TOML 内部字段之间的一致性冲突。 - 报
local proxy failed while handling codex endpoint /responses——多半是模型服务地址或协议格式对不上,不是优先级问题,但容易被误判成优先级问题。
把这几类现象记住,排查时能少走一半弯路。
3. TOML 配置逐字段拆解:模型和 Agent 到底怎么写
3.1 模型配置的核心字段与取值逻辑
Codex 的 TOML 配置里,模型相关字段是最容易出问题的部分。核心就几个:模型标识、服务地址、协议类型、认证方式。我按重要性排一下。
模型标识(model)决定调用哪个模型。这里有个坑:模型名不是随便起的,它必须和服务端点支持的名称一致。你写gpt-5.6-sol但端点只认gpt-4o,就会直接报 not supported。所以改模型名之前,先确认你的服务端到底暴露了哪些名字。
服务地址(base_url 或类似字段)决定请求发到哪。本地自定义 Agent 场景下,这个地址通常指向你自己的推理服务或中转服务。格式上要注意结尾有没有斜杠、路径前缀对不对,/responses和/v1/responses是两个不同的端点。
协议类型决定用哪套 API 规范。不同服务端可能兼容不同的请求格式,选错了就会在/responses这个环节挂掉。
认证方式决定密钥怎么传。有的走 header,有的走 query,有的干脆本地不校验。
一个典型的模型配置段落长这样:
[model] name = "your-model-name" base_url = "http://127.0.0.1:8000/v1" api_key_env = "LOCAL_MODEL_KEY" timeout_seconds = 120 max_retries = 3这里api_key_env指向一个环境变量名,而不是直接写密钥。这是好习惯——密钥不进版本库。本地服务如果不校验,这个字段可以留空或指向一个占位变量。
3.2 自定义 Agent 的定义方式
Agent 在 TOML 里的定义,本质上是给一个“带工具和提示的模型调用单元”起名字。核心字段包括 Agent 名称、绑定的模型、系统提示来源、可用工具列表。
[agents.my_local_agent] model = "your-model-name" prompt_file = "AGENTS.md" tools = ["shell", "read_file", "write_file"] max_turns = 20几个关键点值得展开。
prompt_file指向 AGENTS.md,意味着这个 Agent 的上下文指令从文件读。这样你改指令不用动 TOML,改文件就行,职责分离更干净。
tools列表决定 Agent 能干什么。给多了有安全风险,给少了干不了活。本地场景我一般先给最小集合,跑通了再按需加。
max_turns是防止 Agent 陷入死循环的保险丝。设太小任务做不完,设太大可能烧 token。我的经验值是:简单任务 10,中等任务 20,复杂重构类 40 起步,但要配合超时一起用。
3.3 参数计算:超时和并发怎么定
超时和并发这两个参数,很多人是拍脑袋填的。其实可以算。
超时时间 = 单次请求最长耗时 × 安全系数。本地推理服务如果单次响应 30 秒,安全系数取 2 到 3,超时设 60 到 90 秒比较稳。设太短会频繁超时重试,设太长会卡住整个流程。
并发数 = 服务端能承受的并发上限 × 0.7。留 30% 余量给突发。本地单卡推理一般并发 1 到 2 就够了,硬上高并发只会让每个请求都变慢。
[model] timeout_seconds = 90 max_concurrent = 2这两个值不是越大越好。我见过有人把并发设成 16,结果本地服务直接 OOM。本地 Agent 的瓶颈通常在显存和内存,不在网络,所以并发要保守。
3.4 配置文件的放置位置与加载顺序
TOML 放哪,决定了它属于哪一层。常见位置:
- 用户级:用户主目录下的配置目录,对所有项目生效。
- 项目级:项目根目录下的配置目录,只对当前项目生效。
加载时,项目级覆盖用户级。如果你在两个地方都定义了同一个 Agent,项目级的赢。
提示:改完配置后,用
--verbose或类似的调试开关跑一次,看它实际加载了哪个文件、用了哪个值。这比猜快得多。
4. AGENTS.md 实战:写给 Agent 看的项目说明书
4.1 AGENTS.md 应该写什么、不该写什么
AGENTS.md 是给模型读的,所以写法要顺着模型的“理解习惯”来。该写的:项目是干什么的、目录怎么组织、代码风格、测试怎么跑、有哪些坑不能踩。不该写的:密钥、内部地址、和任务无关的闲聊。
我见过有人把 AGENTS.md 写成 README 的复制粘贴,结果 Agent 该遵守的规范一条没写,全是项目介绍。AGENTS.md 的重点是“约束”和“指引”,不是“介绍”。
一个实用的结构:
# 项目约定 ## 代码规范 - 使用 4 空格缩进 - 函数必须有类型注解 ## 常用命令 - 测试:pytest -q - 格式化:ruff format . ## 禁止事项 - 不要修改 migrations 目录 - 不要提交 .env 文件4.2 目录级 AGENTS.md 的继承规则
AGENTS.md 支持放在不同目录,形成层级。子目录的 AGENTS.md 会叠加在父目录之上。这让你可以给某个子模块写专属约定,而不影响全局。
比如根目录写通用规范,backend/AGENTS.md写后端专属规则,frontend/AGENTS.md写前端专属规则。Agent 在backend目录下工作时,读到的是根目录加 backend 两份的合并结果。
合并时如果冲突,离当前目录近的优先。这和 TOML 的覆盖逻辑是一致的。
4.3 让 Agent 真正遵守约定的技巧
写了不等于遵守。几个提高遵守率的技巧:
把最重要的约束放在文件最前面。模型的注意力对开头和结尾更敏感,中间容易忽略。
用祈使句,别用描述句。“不要修改 X”比“X 通常不应该被修改”有效得多。
约束要具体可执行。“写高质量代码”是废话,“函数不超过 50 行”才是约束。
数量要克制。一次给十几条约束,模型会顾此失彼。核心约束控制在 5 到 8 条。
注意:AGENTS.md 里的指令和 TOML 里的系统提示如果冲突,通常 TOML 侧更硬。所以别把关键约束只写在 AGENTS.md 里,重要的双重保险。
4.4 AGENTS.md 与 TOML 的协作模式
最顺的协作模式是:TOML 定义 Agent 骨架和模型,AGENTS.md 填充行为细节。TOML 里prompt_file指向 AGENTS.md,Agent 启动时自动加载。
这样你调整行为只改 Markdown,调整能力只改 TOML,两边互不干扰。团队协作时,AGENTS.md 可以进版本库让大家一起维护,TOML 里的密钥部分用环境变量隔离。
5. 优先级实战:从报错到跑通的完整排查
5.1 一个完整的配置冲突复现
我复现一次典型的翻车过程。用户级 TOML 里模型是 A,项目级 TOML 里模型是 B,环境变量里又设了模型 C,命令行还传了--model D。最后跑起来用的是 D。
为什么?因为命令行参数优先级最高。很多人改了半天项目级 TOML 没生效,就是因为 shell 里有个环境变量或者 alias 在偷偷覆盖。
排查方法:把每一层的值都打印出来对比。Codex 一般有查看当前生效配置的命令,没有的话就逐层注释掉再跑,二分定位。
5.2 常见报错与对应排查表
| 报错信息 | 大概率原因 | 排查方向 |
|---|---|---|
| model is not supported | 模型名与服务端不匹配 | 核对服务端模型列表 |
| local proxy failed /responses | 服务地址或协议不对 | 检查 base_url 和路径前缀 |
| 无法发送消息 | 认证失败或超时 | 检查密钥和 timeout |
| 显示更新 agent 沙盒 | 沙盒权限或路径问题 | 检查工具权限配置 |
| 无法加载组织设置 | 用户级配置损坏 | 检查用户级 TOML 语法 |
这张表我建议存下来,遇到报错先对号入座,能省很多时间。
5.3 用最小配置定位问题
排查配置问题,最有效的方法是最小化复现。把 TOML 砍到只剩模型和服务地址,AGENTS.md 清空,环境变量清掉,命令行不带参数。跑通了,再一层层加回来。
这样做的逻辑是:配置项越少,变量越少,问题越容易定位。一上来就带着全套配置排查,等于同时解十个方程。
我一般会准备一个minimal.toml,专门用来验证模型服务通不通。通了再套完整配置。
5.4 避免被中间层工具覆盖
ccswitch会覆盖toml这类问题,根源是某个工具在启动时重写了配置文件。应对策略:
搞清楚这个工具写的是哪一层。如果是用户级,那你的项目级配置应该还能赢。如果它直接改项目级,那就得在它之后手动恢复,或者干脆不用它。
更稳的做法是把关键配置放在优先级更高的层。比如把模型定义放环境变量,让中间层工具改 TOML 也影响不到。
提示:任何会自动改你配置的工具,都要先搞清楚它的写入时机和写入层级,否则你永远在和一个看不见的手打架。
6. 本地自定义 Agent 的进阶玩法与避坑心得
6.1 接本地模型服务的注意事项
接本地模型服务,最大的坑是协议兼容性。很多本地服务号称兼容某套 API,实际在/responses这种端点上行为不一致。表现就是请求发出去了,返回格式对不上,然后报 proxy failed。
我的做法是先用 curl 直接打服务端点,确认返回格式,再让 Codex 去接。这样能把“服务端问题”和“配置问题”分开。
curl -X POST http://127.0.0.1:8000/v1/responses \ -H "Content-Type: application/json" \ -d '{"model":"your-model-name","input":"hello"}'返回正常了,再配 Codex。返回不正常,先修服务端,别在 Codex 配置上浪费时间。
6.2 Agent 并发与稳定性
本地 Agent 跑并发任务,稳定性是头号问题。前面说过并发要保守,这里补充几个细节。
给每个 Agent 设独立的超时,别用全局超时。一个慢任务拖垮全局不划算。
重试要有上限,且要区分错误类型。网络抖动可以重试,模型返回格式错误重试也没用。
长任务要能断点续跑。Agent 跑到一半挂了,从头再来成本太高。把中间状态落盘,是本地 Agent 的必备设计。
6.3 配置版本管理
TOML 和 AGENTS.md 都建议进版本库,但密钥部分要剥离。用环境变量引用密钥,配置文件里只留变量名。
这样团队里每个人拉下来就能用,只是各自配自己的环境变量。新人上手成本从“配半天”降到“填两个变量”。
6.4 我踩过的几个坑
第一个坑:以为改了 TOML 就生效,其实环境变量在覆盖。后来养成习惯,改完先env | grep一遍。
第二个坑:AGENTS.md 放在子目录但 Agent 在父目录跑,读不到。搞清楚 Agent 的工作目录很关键。
第三个坑:模型名带版本号,服务端升级后名字变了,配置没跟着改,报 not supported。现在我会在配置里加注释标明模型名的来源。
第四个坑:并发设太高,本地服务 OOM,整个机器卡死。现在本地场景并发一律从 1 开始试。
6.5 后续可以怎么扩展
这套配置体系跑通之后,可以往几个方向扩展。一是多 Agent 协作,不同 Agent 绑不同模型,各司其职。二是把 AGENTS.md 做成模板,不同项目复用。三是把配置校验做成脚本,提交前自动检查语法和字段一致性。
我个人在实际操作中的体会是,Codex 的配置体系看着复杂,但一旦理解了“分层覆盖”这个核心,剩下的都是细节。真正花时间的不是写配置,而是搞清楚每一层谁在生效。把优先级理顺了,本地自定义 Agent 和模型配置这件事就顺了。