1. 为什么我要折腾 Codex 的本地 Agent 配置
Codex 这个工具刚上手的时候,很多人以为它就是个命令行版的代码补全,敲个codex然后问它问题就完事了。但真正用进去之后你会发现,它最值钱的地方其实是本地自定义 Agent 与模型配置这一层——也就是你能不能把 Codex 调教成一个懂你项目、懂你习惯、懂你技术栈的专属助手。
我最初接触 Codex 的时候,踩的第一个坑就是:默认配置下它对我项目的目录结构一无所知,每次都要手动把上下文贴进去,效率极低。后来才搞明白,Codex 提供了一套基于TOML 配置文件加AGENTS.md 项目说明文件的机制,让你可以定义 Agent 的行为、绑定不同的模型、设置优先级,甚至针对不同项目切换不同的配置方案。
这套东西解决的核心问题是:让 Codex 从"通用问答工具"变成"项目专属 Agent"。你可以在 TOML 里定义模型提供商、API 端点、默认模型、超时参数;在 AGENTS.md 里写清楚项目的技术栈、目录约定、代码规范、常用命令。Codex 在启动时会按优先级依次加载这些配置,最终拼出一个完整的运行时上下文。
这篇文章适合谁看?如果你已经在用 Codex CLI,但还停留在"每次手动喂上下文"的阶段,那这篇就是写给你的。如果你刚开始接触 Codex,想从安装到配置一次搞明白,也能跟着走。我会把 TOML 的字段含义、AGENTS.md 的写法、配置优先级规则、模型切换的实操步骤全部拆开讲,并且把我踩过的坑和排查思路一并放出来。
需要提前说明的是,下面涉及的具体路径和字段名,我是基于 Codex 常见版本的实践总结,不同版本可能有细微差异,你以自己本地codex --version和官方文档为准,但整体思路是通用的。
2. Codex 配置体系的整体设计与优先级逻辑
2.1 三层配置结构:全局、项目、会话
Codex 的配置不是单一文件,而是分层的。理解这个分层,是后面所有操作的基础。我把它归纳成三层:
- 全局配置层:位于用户主目录下的配置目录,通常是
~/.codex/config.toml(Windows 下是%USERPROFILE%\.codex\config.toml)。这一层定义的是你所有项目共用的默认值,比如默认模型、默认提供商、全局超时。 - 项目配置层:位于项目根目录下的
.codex/config.toml或者项目级的AGENTS.md。这一层只对当前项目生效,用来覆盖全局配置。比如你某个项目必须用某个特定模型,就在这里改。 - 会话/环境变量层:通过命令行参数或环境变量传入的临时配置,优先级最高,只对当前这次会话生效。比如你临时想切个模型试试效果,直接用命令行参数覆盖就行。
为什么要这么设计?因为实际工作中,你的需求是分层的。你可能有 80% 的项目用同一套默认配置,但剩下 20% 有特殊要求。如果只有一层配置,你要么每次手动改,要么每个项目复制一份完整配置,维护成本极高。分层之后,全局层管共性,项目层管差异,会话层管临时实验,各司其职。
2.2 优先级规则的底层逻辑
优先级这件事,说白了就是"谁覆盖谁"。Codex 的加载顺序是从宽到窄,后者覆盖前者。我用一个表格把常见配置来源的优先级从低到高列出来:
| 优先级 | 配置来源 | 作用范围 | 典型用途 |
|---|---|---|---|
| 1(最低) | 内置默认值 | 全局 | 兜底,保证不配置也能跑 |
| 2 | 全局 config.toml | 所有项目 | 默认模型、通用参数 |
| 3 | 项目 .codex/config.toml | 当前项目 | 项目专属模型与参数 |
| 4 | 项目 AGENTS.md | 当前项目 | 项目上下文与行为约定 |
| 5 | 环境变量 | 当前会话 | 临时覆盖密钥、端点 |
| 6(最高) | 命令行参数 | 当前会话 | 临时切换模型、调试 |
这里有个容易搞混的点:AGENTS.md 和 config.toml 不是同一类东西。config.toml 管的是"机器怎么跑",比如用哪个模型、连哪个端点、超时多少;AGENTS.md 管的是"Agent 怎么想",比如项目用什么框架、代码风格是什么、有哪些禁忌。它们不冲突,而是互补。但在优先级上,AGENTS.md 里的某些指令性内容会覆盖 config.toml 里的默认行为设定,因为它是更贴近具体项目的描述。
提示:不要试图用 AGENTS.md 去改模型参数,那是 config.toml 的活。AGENTS.md 写的是自然语言的项目说明,Codex 会把它作为系统提示的一部分注入。
2.3 为什么用 TOML 而不是 JSON 或 YAML
这个问题我被问过好几次。TOML 的优势在于:可读性强、支持注释、层级清晰、解析严格。JSON 不支持注释,你没法在配置里写"这行是干嘛的";YAML 虽然支持注释,但缩进敏感,一个空格错了就报错,而且复杂嵌套时容易看花眼。
TOML 的[section]语法天然适合配置文件的组织。比如你要配多个模型提供商,每个提供商一个 section,一目了然。而且 TOML 的类型系统比 YAML 严格,不容易出现"字符串被解析成布尔值"这种坑。对于 Codex 这种需要频繁手改配置的场景,TOML 是最优解。
3. TOML 配置文件的核心字段与实操写法
3.1 最小可用配置长什么样
先给你一个能跑起来的最小配置,放在~/.codex/config.toml:
model = "gpt-4o" provider = "openai" [providers.openai] api_key_env = "OPENAI_API_KEY" base_url = "https://api.openai.com/v1"这几行的含义:默认模型是gpt-4o,默认提供商是openai,提供商的密钥从环境变量OPENAI_API_KEY读取,端点走官方地址。
注意api_key_env这个字段——它填的是环境变量的名字,不是密钥本身。这是安全设计,避免你把密钥硬编码进配置文件然后不小心提交到仓库。我见过有人直接把 key 写进 config.toml,结果推到公开仓库,第二天 key 就被刷爆了。这个坑千万别踩。
3.2 多提供商配置与模型切换
实际工作中你往往不止用一个模型。比如日常用某个模型,遇到复杂推理任务切另一个,成本敏感时再切一个。Codex 支持在 TOML 里配多个提供商:
model = "gpt-4o" provider = "openai" [providers.openai] api_key_env = "OPENAI_API_KEY" base_url = "https://api.openai.com/v1" [providers.deepseek] api_key_env = "DEEPSEEK_API_KEY" base_url = "https://api.deepseek.com/v1" default_model = "deepseek-chat" [providers.local] api_key_env = "LOCAL_API_KEY" base_url = "http://localhost:8000/v1" default_model = "local-model"配好之后,切换模型有两种方式。一种是改model和provider字段,另一种是命令行临时指定。我一般用后者做实验,确认好用之后再写进配置。
这里有个细节:default_model是提供商级别的默认模型,当你在顶层model里没指定、或者指定的模型在当前提供商下不存在时,会回退到default_model。这个回退机制很实用,但也很容易让人困惑——明明改了顶层 model 却没生效,八成是提供商那边有默认值在兜底。
3.3 超时、重试与并发参数
网络请求相关的参数,是配置里最容易被忽略但最影响体验的部分。默认超时往往偏短,遇到大上下文或者慢端点就会频繁失败。我的常用配置:
[request] timeout_seconds = 120 max_retries = 3 retry_delay_seconds = 2 stream = truetimeout_seconds设 120 秒,是因为有些复杂任务模型思考时间长,设太短会中途断掉。max_retries = 3配合retry_delay_seconds = 2,能扛住偶发的网络抖动。stream = true开启流式输出,你能看到模型逐字返回,体验上不会觉得卡死。
注意:重试次数不是越多越好。如果端点本身有问题,重试只会浪费时间。我一般设 3 次,超过就说明是配置或网络问题,该去排查而不是继续等。
3.4 沙盒与执行权限配置
Codex 作为 Agent,有时候需要执行命令、读写文件。这部分权限控制很关键,配错了要么啥都干不了,要么风险失控。常见配置:
[sandbox] mode = "workspace-write" allowed_paths = ["./src", "./tests"] deny_paths = ["./secrets", "./.env"]mode常见取值有只读、工作区可写、完全放行几种。我强烈建议默认用workspace-write,只允许在项目目录内写,并且用deny_paths明确排除敏感目录。这样即使 Agent 判断失误,也不会把密钥文件改掉。
我踩过的一个坑:早期图省事把 mode 设成完全放行,结果 Agent 在重构时把配置文件也"顺手优化"了,导致环境变量全丢。从那以后我老老实实配deny_paths。
4. AGENTS.md 的写法与项目上下文注入
4.1 AGENTS.md 到底解决什么问题
config.toml 解决的是"怎么连模型",AGENTS.md 解决的是"模型怎么理解你的项目"。它是一个放在项目根目录的 Markdown 文件,Codex 启动时会自动读取,把内容作为系统提示的一部分注入。
为什么需要它?因为模型再强,也不知道你的项目约定。比如你的项目用 pnpm 而不是 npm,用 vitest 而不是 jest,目录结构是 feature-based 而不是 layer-based。这些信息如果不告诉模型,它给出的建议就会"水土不服"。AGENTS.md 就是把这些隐性知识显性化。
4.2 一份实用的 AGENTS.md 模板
我用了大半年,迭代出来的模板大概长这样:
# 项目说明 ## 技术栈 - 语言:TypeScript 5.x - 框架:React 18 + Vite - 包管理:pnpm(禁止使用 npm/yarn) - 测试:vitest + testing-library - 样式:Tailwind CSS ## 目录约定 - src/features/ 按功能模块组织 - src/shared/ 跨模块复用代码 - src/lib/ 纯工具函数,无副作用 ## 代码规范 - 组件用函数式,禁止 class 组件 - 状态管理优先用 hooks,复杂场景用 zustand - 所有导出函数必须有 JSDoc 注释 - 提交前必须跑 pnpm lint 和 pnpm test ## 常用命令 - 开发:pnpm dev - 构建:pnpm build - 测试:pnpm test - 类型检查:pnpm typecheck ## 禁忌 - 不要修改 package.json 里的依赖版本 - 不要动 src/legacy/ 目录,那是待迁移代码 - 不要引入新的全局状态库这份文件的关键在于具体。不要写"遵循最佳实践"这种废话,要写"用 pnpm 不用 npm"这种可执行的约定。模型看到具体指令才会照做,看到空泛描述只会自由发挥。
4.3 AGENTS.md 的层级与继承
AGENTS.md 支持层级。你可以在项目根目录放一份,在子目录再放一份。Codex 会从当前工作目录向上查找,把找到的所有 AGENTS.md 合并。子目录的配置覆盖父目录的同名项。
这个机制适合 monorepo。根目录的 AGENTS.md 写全局约定,各个 package 目录下的 AGENTS.md 写该 package 的特殊约定。比如根目录说"用 pnpm",某个 package 说"这个包用 npm 因为历史原因",Codex 在那个 package 下工作时就会用 npm。
提示:层级不要超过三层,否则合并逻辑会变得难以预测。我一般就根目录加一层子目录,够用了。
4.4 写 AGENTS.md 的三个经验
第一,用命令式而非描述式。写"使用 pnpm 安装依赖"比写"项目使用 pnpm"更有效,因为前者是明确指令。
第二,把禁忌单独列一节。模型对"不要做什么"的敏感度低于"要做什么",单独列出来能提高遵守率。
第三,定期更新。项目演进了,AGENTS.md 不更新,模型就会按过时约定干活。我一般每个 sprint 结束 review 一次。
5. 完整实操:从零配置一个项目专属 Agent
5.1 环境准备与安装确认
先确认 Codex 装好了。不同平台安装方式不同,我以常见的命令行安装为例:
codex --version能输出版本号就说明装好了。如果提示找不到命令,检查 PATH 或者重新安装。Windows 桌面版的话,确认安装包来源可靠,装完在终端里同样用codex --version验证。
安装完成后,先跑一次codex进入交互模式,随便问个问题,确认能正常连通模型。这一步很重要,因为后面配置出问题时,你需要知道是"本来能通现在不通"还是"从来没通过"。
5.2 创建全局配置
在用户主目录创建配置目录和文件:
mkdir -p ~/.codex touch ~/.codex/config.toml然后把前面 3.1 节的最小配置写进去。设置环境变量:
export OPENAI_API_KEY="你的密钥"Windows 下用setx OPENAI_API_KEY "你的密钥",然后重开终端生效。
验证配置是否被读取:跑codex后问它"你当前用的是什么模型",如果回答和你配置的一致,说明全局配置生效了。
5.3 创建项目级配置与 AGENTS.md
进入你的项目根目录:
cd /path/to/your/project mkdir -p .codex touch .codex/config.toml touch AGENTS.md项目级 config.toml 里只写需要覆盖全局的部分。比如这个项目要用不同的模型:
model = "deepseek-chat" provider = "deepseek"AGENTS.md 按 4.2 节的模板填。填完之后,在项目目录下跑codex,问它"这个项目用什么包管理器",如果回答 pnpm,说明 AGENTS.md 被正确注入了。
5.4 验证优先级是否按预期工作
这是最关键的一步。我设计了一个验证流程:
- 全局配置写
model = "gpt-4o",项目配置不写 model,跑 codex 问模型,应该回答 gpt-4o。 - 项目配置写
model = "deepseek-chat",再跑,应该回答 deepseek-chat。 - 命令行加参数覆盖,比如
codex --model gpt-4o,应该回答 gpt-4o。
三步都符合预期,说明优先级链路是通的。任何一步不对,就去检查对应层级的文件路径和字段名。
5.5 参数计算:超时和重试怎么定
超时和重试不是拍脑袋定的。我的计算方法:
先测正常请求的 P95 延迟。跑 20 次典型请求,记录耗时,取第 19 个的值。假设是 30 秒。那么timeout_seconds设为 P95 的 3 到 4 倍,也就是 90 到 120 秒。这样既能容忍慢请求,又不会在真挂掉时等太久。
重试次数用可用性反推。假设单次请求成功率 95%,重试 3 次后整体成功率是1 - 0.05^4 ≈ 99.99%。如果单次成功率只有 80%,重试 3 次也只有1 - 0.2^4 = 99.84%,这时候该去查为什么单次成功率这么低,而不是加更多重试。
6. 常见问题与排查技巧实录
6.1 配置不生效的排查顺序
配置改了没反应,按这个顺序查:
| 排查项 | 检查方法 | 常见原因 |
|---|---|---|
| 文件路径 | ls ~/.codex/config.toml | 路径拼错、目录不存在 |
| 文件语法 | TOML 解析器验证 | 引号不配对、section 重复 |
| 环境变量 | echo $OPENAI_API_KEY | 没 export、拼写错误 |
| 优先级覆盖 | 逐层注释测试 | 高层配置覆盖了低层 |
| 版本差异 | codex --version | 字段名在新版本变了 |
我遇到最多的是环境变量问题。尤其是 Windows 下setx之后没重开终端,变量根本没加载。还有一次是密钥里带了空格,复制的时候没注意,排查了半天。
6.2 模型切换后行为异常
切了模型之后,同样的 prompt 输出质量差很多,或者格式完全不对。这通常不是配置问题,而是不同模型对系统提示的响应方式不同。有的模型对 AGENTS.md 里的指令遵循度高,有的需要更明确的格式约束。
我的做法是:换模型后,先跑几个标准测试用例,确认基本行为符合预期,再投入实际使用。如果某个模型对 AGENTS.md 响应差,就在项目配置里针对它单独调整提示策略。
6.3 请求超时与连接失败
超时和连接失败要分开看。超时是连上了但响应慢,连接失败是压根没连上。
超时的话,先加timeout_seconds,再考虑换端点。连接失败的话,检查base_url是否正确、网络是否可达、密钥是否有效。我一般用 curl 直接测端点:
curl -X POST https://api.openai.com/v1/chat/completions \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4o","messages":[{"role":"user","content":"hi"}]}'curl 能通但 codex 不通,那就是 codex 配置问题;curl 也不通,那就是网络或密钥问题。这个二分法能快速定位。
6.4 沙盒权限导致的执行失败
Agent 想执行命令但被拦了,报权限错误。先看sandbox.mode是不是太严,再看allowed_paths有没有包含目标路径。我建议不要直接放开到完全权限,而是精确添加需要的路径。比如 Agent 要写日志到./logs,就把./logs加进allowed_paths,而不是把整个项目放开。
6.5 常见问题速查表
| 现象 | 可能原因 | 解决方向 |
|---|---|---|
| 提示找不到配置文件 | 路径错误 | 确认~/.codex/存在 |
| 密钥无效 | 环境变量未加载 | 重开终端或检查 export |
| 模型不存在 | 提供商不支持该模型 | 查提供商文档或换模型 |
| 输出被截断 | 超时太短 | 调大timeout_seconds |
| AGENTS.md 没生效 | 文件名或位置错误 | 确认在项目根目录且拼写正确 |
| 切换模型无效 | 优先级覆盖 | 检查高层配置 |
| 请求频繁失败 | 端点不稳定 | 换端点或加重试 |
| 执行命令被拒 | 沙盒限制 | 调整 mode 或 allowed_paths |
7. 我踩过的坑和几条实在建议
配置这东西,文档看一遍觉得懂了,真上手还是各种问题。我把自己踩过的坑列几条,你对照着避一避。
第一条,别把密钥写进配置文件。这个前面说过,但值得再说一遍。用环境变量,用环境变量,用环境变量。重要的事说三遍。
第二条,改配置前先备份。我有次手抖把 config.toml 改坏了,又没备份,只能从头重写。现在我的习惯是改之前cp config.toml config.toml.bak,出问题直接还原。
第三条,AGENTS.md 要短而精。我一开始写了两千多字,结果模型反而抓不住重点。后来精简到几百字,只留最关键的约定,效果反而更好。上下文是有成本的,别浪费在废话上。
第四条,优先级验证要形成习惯。每次改完配置,跑一遍 5.4 节的三步验证。花两分钟,省得后面排查半小时。
第五条,不同项目用不同配置,别偷懒。我见过有人全局配置一套走天下,结果在需要特定模型的项目里各种别扭。项目级配置就是干这个的,该用就用。
最后分享一个小技巧:如果你不确定某个字段名对不对,可以在 codex 里直接问它"config.toml 里配置超时的字段叫什么",它一般能答上来。这比翻文档快,尤其是版本更新后字段名变了的时候。当然,最终还是要以官方文档为准,模型也可能记错。
这套配置体系我用了大半年,从最初的"能跑就行"到现在每个项目都有精细化的 Agent 配置,效率提升是实打实的。核心就一句话:把重复的上下文和约定固化到配置里,让每次对话都从更高的起点开始。你把这套跑通之后,会发现 Codex 完全不是刚上手时那个样子了。