☰
Codex CLI本地自定义Agent:config.toml、AGENTS.md与配置优先级实战
2026/9/28 18:53:53 网站建设 项目流程

Codex CLI 装好之后,大多数人第一步就是codex回车,接官方模型跑一条 prompt。这当然没问题,但如果你指望它成为日常开发的主力,很快就会撞上三堵墙:第一堵是模型源怎么切——官方 API、本地部署的开源模型、第三方兼容服务,总不能每次临时改环境变量;第二堵是项目规范怎么传达——每次对话都要重复“别动 migrations、用 pnpm、遵循现有错误码风格”,既费 token 又容易漏;第三堵是配置到底听谁的——config.toml、环境变量、AGENTS.md、命令行参数同时存在,改了一个被另一个覆盖,排了半天发现是环境变量在捣乱。

这篇文章我想把 Codex 本地自定义 Agent 这件事讲透,核心围绕 TOML 配置、AGENTS.md和配置优先级三条线展开。内容偏实操,会覆盖本地推理服务的接入、常见报错的完整排查链路,以及用 cc-switch 管理多套配置的日常经验。适合两类人:一类是刚把 Codex 装好,想接本地模型或第三方兼容模型的;另一类是被各种配置覆盖问题折磨过,想系统搞明白到底谁覆盖谁的。读完你至少能自己写出一份可用的config.toml,并且再看到auth token is unavailable或者endpoint /responses这类报错时,知道该往哪个方向查。

1. 先弄清 Codex 的配置体系由什么组成

很多人一上来就搜“Codex 怎么配置模型”,结果看到TOML、AGENTS.md、profile、provider一堆名词直接懵了。其实这些东西背后就三件事:用哪个模型服务、按什么规范干活、临时的需求怎么覆盖。

1.1 三个配置入口,对应三种不同的“为什么”

Codex 的配置不是一个大而全的文件,而是分层的。我通常会把它拆成三个入口:

  • config.toml(运行时配置):决定 Agent 用什么模型、连哪个推理服务。它管的是“发动机和油路”。比如模型 ID、base_url、API key 的环境变量名、还有wire_api这种通信协议。
  • AGENTS.md(行为规范):决定 Agent 怎么干活。它管的是“司机手册”,告诉 Codex 这个项目有什么架构约束、用什么包管理器、哪些文件绝对不要动。它不是 prompt,而是持续生效的上下文指令。
  • 环境变量 / CLI 参数(临时覆盖):用来处理“今天临时换个模型试一下”这类场景。它们的优先级通常比文件配置高,所以也是出问题最多的地方。

这三个入口的职责是不同的。config.toml是长期默认,AGENTS.md是项目级约束,环境变量和 CLI 参数是即时覆盖。如果你在用 cc-switch 这类工具,它管理的其实只是config.toml这一层,不会帮你管AGENTS.md。

1.2 本地自定义的真实诉求

为什么要费劲去自定义 Agent 和模型?我遇到的情况大致有四类:

  • 本地部署开源模型:比如用 Ollama 跑 Qwen2.5-7B,图的是隐私、离线可用、不按 token 计费。把 Codex 接到本地服务之后,跑普通任务完全可以在本地闭环。
  • 企业内部模型网关:不少公司不允许代码直接出内网,会提供一个内网 API 网关地址。这种情况必须把base_url指向内网地址,而不是默认的官方地址。
  • 多供应商切换:官方模型、DeepSeek、OpenAI 兼容的第三方服务……每个服务商一个 key、一个base_url,想一键切换就得靠 profile 和工具管理。
  • 团队统一行为规范:希望每个项目里的 Codex 都遵循同样的代码风格和操作边界,这就得靠AGENTS.md在不同层级铺开。

这四类场景里,config.toml负责解决模型源问题,AGENTS.md负责解决行为规范问题,而“优先级”则是这两者都逃不开的副作用。下面我一个个拆开讲。

2. config.toml 逐段拆解:provider、base_url 与 wire_api

config.toml是 Codex 最核心的配置文件,路径在用户目录下的.codex文件夹里。macOS/Linux 是~/.codex/config.toml,Windows 是%USERPROFILE%\.codex\config.toml。第一次运行codex或者执行登录流程之后,它就会自动生成。

2.1 配置文件在哪,长什么样

默认生成的config.toml通常很简洁,类似这样:

model = "gpt-5-codex" model_provider = "openai" temperature = 0

你要是只用官方服务,这个文件基本不用动。但一旦要接本地模型或第三方服务,就得开始往里面加[model_providers.xxx]段和[profiles.xxx]段。前者定义“这个服务商怎么连”,后者定义“我要用哪套组合”。

举一个典型的 profile 写法:

[profiles.local_qwen] model = "qwen2.5:7b" model_provider = "ollama"

profiles的意义在于,你可以在同一个配置文件里预置多套组合,比如local_qwen、deepseek、official。切换的时候只需要告诉 Codex 用哪个 profile,而不需要反复改model和model_provider这两个顶层字段。cc-switch 这类 GUI 工具做的事情,本质上就是在替你维护这些 profile 和 provider 段落。

2.2 provider 字段逐个过

下面这段是我实际在用的 provider 配置,加了注释:

[model_providers.ollama] name = "Ollama Local" base_url = "http://127.0.0.1:11434/v1" env_key = "OLLAMA_LOCAL_KEY" wire_api = "chat" [model_providers.deepseek] name = "DeepSeek" base_url = "https://api.deepseek.com/v1" env_key = "DEEPSEEK_API_KEY" wire_api = "chat"

四个字段各有各的坑:

  • name:显示名。写清楚就行,主要是日志和工具界面里看的。
  • base_url:API 地址。这里有个最容易手滑的地方:末尾到底带不带/v1。Ollama 的 OpenAI 兼容端点是http://127.0.0.1:11434/v1,DeepSeek 的兼容地址是https://api.deepseek.com/v1。Codex 会在你给的base_url后面拼具体路径,比如/chat/completions或/responses,所以多写少写一个/v1,URL 就完全不对。
  • env_key:Codex 会去读这个环境变量作为该 provider 的 API key。本地模型通常不校验 key,但 Codex 的逻辑是“这个 provider 必须有一个 key 来源”,如果没有就报codex auth token is unavailable。解决办法是设一个占位值,比如export OLLAMA_LOCAL_KEY=dummy。
  • wire_api:请求走哪种协议。chat对应/v1/chat/completions,responses对应/v1/responses。官方 Codex 默认走responses,但很多本地服务只实现了chat,所以接 Ollama 这类服务时通常要显式写成chat。

理解了这四个字段,绝大多数“接不上”“认证失败”的报错就已经解决一半了。

2.3 local proxy failed 报错到底在说啥

很多人在 cc-switch 里切换配置时会看到这样一条报错:

cc switch local proxy failed while handling codex endpoint /responses

先说清楚,这里的 local proxy 指的是你自己在配置里填写的那个本地 API 网关地址,比如http://127.0.0.1:11434/v1或者内网网关地址,它只是把请求转发给本机或内网后端服务的中间层,跟系统网络设置没有关系。

报错的字面意思是:cc-switch 在切换完配置后,用新的base_url去请求endpoint /responses这个路径,结果失败了。所以根因基本可以锁定在两点:

  1. 目标服务不支持/responses。大部分本地推理服务只实现了 OpenAI 的/chat/completions,并没有实现新版/responses接口。cc-switch 的探测请求打到/responses上,自然得到 404 或者 405。
  2. base_url本身拼错了。比如探地址是http://127.0.0.1:11434,而正确兼容端点是http://127.0.0.1:11434/v1,中间少了路径,请求同样失败。

排查方法很直接,先用 curl 分别测两个路径:

curl http://127.0.0.1:11434/v1/responses \ -H "Content-Type: application/json" \ -d '{"model":"qwen2.5:7b","input":"ping"}' curl http://127.0.0.1:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"qwen2.5:7b","messages":[{"role":"user","content":"ping"}]}'

如果第一个失败、第二个成功,那就是wire_api的问题,把 provider 配置改成wire_api = "chat"就行。如果两个都失败,那就是base_url不对或者服务没起来,先去把推理服务跑起来再说。

3. AGENTS.md 不是提示词,是项目的操作手册

AGENTS.md是 Codex 当前版本支持的项目级指令文件,作用类似 Claude Code 里的CLAUDE.md。简单说,它就是给 Agent 看的项目操作手册,每次对话开始时会被自动加载进上下文。

3.1 它是怎么被加载的

Codex 会在项目目录里向上逐级查找AGENTS.md,同时也会读取用户配置目录下的全局AGENTS.md(我手头版本的路径是~/.codex/AGENTS.md,旧版本不一定支持,建议升级到最新版再验证)。加载顺序大致是:全局文件先作为基础上下文,然后项目根目录的文件补充,再往下的子目录文件继续补充。子目录里的AGENTS.md一般只描述那个子目录的特定规范,比如backend/AGENTS.md只讲后端代码的约束。

有一件事容易混淆:不要把AGENTS.md和context.md搞混。AGENTS.md是你手工维护的规范,长期有效;context.md是 Codex 在会话过程中导出上下文时产生的记录文件,属于产物,不是输入。网上搜“agents.md context.md”经常是这两个东西一起出现,但定位完全不同。

AGENTS.md比每次重复贴 prompt 好的地方在于:省 token、跨会话一致、团队成员共享一份规范。关键是要把它当成“操作手册”来写,而不是当成“人生格言”来写。

3.2 一份能落地的 AGENTS.md 模板

写AGENTS.md最忌讳的是空话。比如“请写出高质量的代码”这句话一点用都没有,因为 Agent 并不知道“高质量”具体指什么。我常用的模板结构是这样的:

# 项目操作手册 ## 项目概述 这是一个基于 FastAPI 的订单服务,前端使用 React + pnpm + monorepo 管理。 ## 常用命令 - 安装依赖:pnpm install - 本地开发:pnpm dev - 运行测试:pnpm test - 构建镜像:docker build -t order-service . ## 架构约束 - 新增接口必须放在 app/routers/ 目录下 - 数据库迁移脚本只能手写,不允许让 Agent 自动生成 - 外部 API 调用必须走 clients/ 目录下的封装 ## 代码风格 - 变量命名使用 camelCase - 错误消息统一格式:ERR_CODE: description - 日志使用现有 logger 实例,不要直接用 print ## 禁止事项 - 不要格式化不属于本次改动范围的文件 - 不要修改 migrations/ 目录下已经合入主干的迁移脚本 - 不要擅自升级第三方依赖版本

编写要点有三个。第一,用“必须/禁止”这种确定性措辞,别用“尽量避免”这种模糊表达。第二,只放当前项目真正独特的规则,通用的语言规范放全局AGENTS.md就好,每个仓库都复制一份通用规范会很臃肿。第三,控制篇幅,因为AGENTS.md会占用上下文 token,太长反而稀释了重点。

3.3 和命令行 prompt 冲突时听谁的

在实际使用中,显式 prompt 里的即时指令通常比AGENTS.md更优先。比如AGENTS.md里写了“包管理用 pnpm”,你某次对话里明确说“这次用 npm 执行”,它大概率会按你 prompt 来做。但下一次新会话没人强调时,它又会回到 pnpm。

所以我的经验是:把“不可违背的底线”放在AGENTS.md里,比如“不要删除未改动的测试文件”“不要动生产环境配置”;把“本次任务的具体要求”放在 prompt 里,比如“这次用 npm 装依赖”“这次只改登录模块”。这样即使某次 prompt 写得比较随意,底线依然有效。

4. 配置优先级全景:别再被静默覆盖坑了

配置管理里最常见的坑不是“写错了”,而是“写对了但被别的层覆盖了”。理解优先级,比记住某个字段怎么写更重要。

4.1 一次典型的“改完不起作用”现场

我踩过最典型的一次坑是这样的:我在config.toml里配好了 Ollama provider,也把顶层model指到了qwen2.5:7b,然后满怀期待地跑codex "解释一下这个仓库的结构",结果发现它还在请求官方 API,甚至报 key 相关的问题。

排查了一个多小时,最后是env命令救了我:

env | grep -i openai

发现 shell 里早就export OPENAI_BASE_URL=...和export OPENAI_API_KEY=...了。Codex 对环境变量的信任优先级高于config.toml,只要OPENAI_BASE_URL存在,它就会用这个地址,而不是我在 TOML 里写的base_url。当场unset OPENAI_BASE_URL之后,配置立刻生效。

这个案例值得单独说:用 cc-switch 切完配置没生效,先别怀疑工具,先查环境变量。很多朋友在工具里来回切换,结果 shell 里挂着一个全局OPENAI_BASE_URL,切什么都没用。

4.2 环境变量、config.toml、CLI 参数的真实权重

根据我的实测,Codex 解析配置的权重大致是这样的:

配置来源作用范围典型场景实际权重
CLI 参数单次命令临时指定 model、profile最高
环境变量当前 shell 会话临时改 base_url、API key高,会压过 config.toml
config.toml全局长期默认 provider、profile中
全局 AGENTS.md所有项目通用代码规范低
项目 AGENTS.md当前项目及子目录项目专属规范低

这个表格是行为层面的感受,不是官方承诺的严格定义,Codex 版本迭代又很快,不同版本可能有差异。但大方向是稳定的:越显式、越临时的配置,优先级越高。

推荐的做法是:想长期生效的就写进config.toml;只想某一轮对话生效的就用 CLI 参数或 prompt 指令;想在某个仓库统一行为的就写AGENTS.md;环境变量只在 CI 或临时调试时用,平时别乱export。

4.3 验证当前到底用的哪个模型

排查配置问题,第一件事是确认当前生效的到底是哪套配置。我常用的验证方法是:跑一条最小指令,然后看两个信号。

第一个信号是模型返回里的model字段。如果能打开调试信息,或者服务端有日志,直接看日志最靠谱。第二个信号是故意把当前base_url改错端口,再跑一次。如果报错信息里出现了那个错误地址,说明 Codex 确实在走这套配置;如果报错还是指向别的地址,说明有更高优先级的配置在拦截。这个方法说起来有点笨,但排障效率极高。

5. 本地模型接入实战:把 Qwen2.5-7B 变成 Codex 的默认 Agent 模型

这一节我给一份完整的实操方案,以本地部署 Qwen2.5-7B 为例,把 Codex 接到本机推理服务上。整个过程跑在本地回路里,不依赖任何外部网络通道,适合隐私敏感或者想省成本的场景。

5.1 先起一个本地推理服务

最简单的方案是 Ollama。装好之后拉模型、起服务:

ollama pull qwen2.5:7b ollama serve

Ollama 默认监听11434端口,OpenAI 兼容端点是:

http://127.0.0.1:11434/v1

先用 curl 确认服务是通的:

curl http://127.0.0.1:11434/v1/models

能返回模型列表就行。如果你用的是 LM Studio 或者 vLLM,原理一样,它们也会暴露 OpenAI 兼容端点。Codex 不关心后端是什么推理框架,它只关心这个端点是不是 OpenAI 兼容的。

一个容易忽略的点:Ollama 的 OpenAI 兼容层目前主要实现的是/chat/completions,对/responses的支持不完整。所以配置里务必把wire_api设为chat,否则就会出现前面说的endpoint /responses相关失败。

5.2 写一份能跑通的 config.toml

在~/.codex/config.toml里加入以下内容:

model = "qwen2.5:7b" model_provider = "ollama" [model_providers.ollama] name = "Ollama Local" base_url = "http://127.0.0.1:11434/v1" env_key = "OLLAMA_LOCAL_KEY" wire_api = "chat" [profiles.local_qwen] model = "qwen2.5:7b" model_provider = "ollama"

这里有两个关键点。

第一个是env_key。Ollama 本地服务完全不校验 API key,但 Codex 需要一个 key 来源,所以你必须设置这个环境变量,哪怕是个占位值:

export OLLAMA_LOCAL_KEY=dummy

如果不设置,跑任何指令都会遇到codex auth token is unavailable。

第二个是环境变量干扰。如果你之前的 shell 里有OPENAI_API_KEY或OPENAI_BASE_URL,尽量先清掉再测试:

unset OPENAI_API_KEY unset OPENAI_BASE_URL

否则环境变量优先级会压过config.toml,你的本地配置就白写了。

5.3 高频报错排查链路

接本地模型最常见的报错就那么几个,我按排查顺序列一下。

报错一:codex auth token is unavailable

含义是 Codex 在选定的 provider 上拿不到 key。先检查env_key对应的变量是否存在:

echo $OLLAMA_LOCAL_KEY

没有就 export 一个占位值。同时检查 shell 里有没有其它 key 干扰,尤其是OPENAI_API_KEY。

报错二:agent execution terminated due to error.

这个报错非常笼统,可能是沙箱权限、token 超限、模型服务崩溃、URL 拼错等原因。我的排查顺序是固定的:先手动 curl 调一次接口确认模型服务本身正常,再核对base_url是否带/v1,然后看wire_api是否和服务的实际协议一致,最后看模型服务的日志里有没有收到请求。如果日志里连请求都没有,说明 Codex 根本没把请求发到这个地址,回到第 4 章的优先级问题去查。

报错三:本地网关不认/responses

这类报错通常出现在用 cc-switch 或自建网关的场景。核心就是你的服务没有实现 OpenAI 新版/responses接口。解决办法有两个:一个是在 Codex 的 provider 配置里把wire_api改成chat;另一个是在网关层加一个/responses到/chat/completions的转换。对绝大多数人来说,改wire_api最省事。

补充一个观察:很多图形化配置工具在保存配置时会先请求一次目标地址做校验,如果你填的服务不支持它探测的路径,工具就会报“保存失败”。这种时候不要跟工具死磕,先手工写好一份标准 TOML,确认 request 能通,再导入工具,成功率会高很多。

5.4 验证请求真的打到了本地模型

配置写完,怎么确认 Codex 真的在用本地模型?不要只看“命令没报错”,要看证据。

最直接的办法:把ollama serve停掉,换成前台运行,然后跑一条最简单的指令:

codex "hi"

前台日志里如果出现类似POST /v1/chat/completions的请求记录,说明 Codex 确实把请求发到了本地服务,并且路径、协议都对了。如果日志没有记录,那就是请求根本没进来,继续查配置层的优先级和base_url。

还有一种验证技巧:把base_url故意改成http://127.0.0.1:12345/v1这种不存在的端口,跑一次指令。如果报错是connection refused指向这个地址,说明 Codex 确实在按你的配置走;如果报错里出现的是别的地址,说明有环境变量或其它配置在覆盖。验证完之后记得改回来。

确认链路通了之后,可以给 Codex 一个稍微真实一点的任务,比如让它读项目 README 并生成摘要,观察整个对话是不是都由本地模型完成。这一步通过,本地自定义 Agent 就算真正跑起来了。

6. 用 cc-switch 管理多套配置的日常心得

最后说一下我日常怎么管理多套配置。cc-switch(网上也有人写成 ccswitch)是一个桌面端 GUI 工具,用来管理 Codex 和 Claude Code 这类 CLI 工具的多供应商配置。它做的事情很朴素:把不同的 provider 和 profile 存成模板,在你切换时改写~/.codex/config.toml。官方一套、本地 Ollama 一套、第三方兼容 API 一套,一键换。

我个人的配置组合长期维持三套:

  1. 官方默认:需要最强模型能力时用。
  2. 本地 Ollama Qwen2.5-7B:日常开发、简单重构、离线环境用。
  3. DeepSeek:需要不错的中文能力和代码理解、又不想用官方时用。

用 cc-switch 有几个实操注意点。第一,切换完习惯性cat ~/.codex/config.toml复核一眼,不要盲目相信 GUI 提示成功。第二,手工改配置文件和使用工具切换之间二选一,不要两边同时改,否则很容易出现你手写的 provider 被工具整段替换掉的情况。第三,切换之前先确认 shell 环境变量干净,否则环境变量层会一直压过文件层,切了等于白切。

我见过不少类似 pi agent、hermes agent 的框架,它们也都有“把模型配置抽成独立文件、用工具切换”的设计思路。Codex 的config.toml加AGENTS.md就是这套思路在官方 CLI 里的实现。理解了一份,上手另一份会很快。

最后分享一个我一直在用的小技巧:每次切完配置,别急着开大任务,先跑一条最小指令codex "ping",再看一眼模型服务日志,确认返回的模型名和请求路径都对,再进入正式工作。这算是最低成本的健康检查,能帮你把大多数配置问题挡在开工之前。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询