1. 这不是“换接口”那么简单:Codex CLI 接入 OpenAI 兼容层的真实价值与适用边界
Codex CLI 接入 OpenAI 兼容接口——光看标题,很多人第一反应是“不就是改个地址?配个 key?”但我在某高校实验室带学生做代码辅助工具链集成时发现,超过70%的失败案例,根本不是出在 API 调用本身,而是卡在 config.toml 的一个空格、一个引号、一次错误的类型推断,或者对“兼容接口”底层行为的误判上。Codex CLI 本身是一个轻量级命令行工具,它不内置模型推理能力,也不做 token 缓存或流式响应封装,它的全部职责就是:精准解析用户指令 → 构造符合 OpenAI v1 API 规范的 HTTP 请求 → 安全传输 → 解析返回 → 渲染结果。所以,“接入兼容接口”,本质是让 Codex CLI 信任并正确对话一个“长得像 OpenAI、但内核可能完全不同”的服务端。这个过程里,config.toml 就是唯一的“外交协议文本”,它定义了身份(API key)、信使(base URL)、语言(model name)、礼仪(timeout、max tokens)、甚至紧急联络方式(fallback endpoint)。2026 年这个时间点很关键:主流开源 LLM 服务框架(如 Ollama、LiteLLM、vLLM 的 API server 模式)已普遍支持/v1/chat/completions路径和openai格式响应,但各家对systemrole 支持度、tool call字段解析逻辑、stream响应 chunk 分隔符、甚至429错误的 retry-after 头处理,都存在细微却致命的差异。因此,这篇内容不是教你怎么“连上”,而是带你把 config.toml 当成一份需要逐字审阅的法律合同来读,搞懂每一行背后的服务端契约、客户端约束和网络现实。适合三类人:正在本地部署 Llama 3-70B 并想用 Codex CLI 快速验证 prompt 效果的算法工程师;需要为团队统一配置多套后端(OpenAI + 自建 vLLM + 某云厂商兼容层)的 DevOps 同学;以及被Error: invalid model name或Request failed with status code 400卡住一整天、最后发现是 toml 文件里 model 名称多了一个下划线的前端开发者。你不需要会写 Rust(Codex CLI 是 Rust 写的),但你需要理解 HTTP、JSON Schema 和配置驱动型工具的设计哲学。
2. config.toml 结构全景图:为什么必须“逐行”讲,而不是“按模块”讲?
Codex CLI 的配置文件设计非常克制,没有分组、没有嵌套 section,就是一个扁平化的键值对列表。这种设计看似简单,实则暗藏玄机:所有字段都在同一作用域,意味着任意两个字段之间可能存在隐式依赖。比如model字段的值,会直接影响max_tokens的合理取值范围;而timeout的设置,又必须结合你所用兼容接口的实际响应延迟来定,否则 timeout 过短会导致大量“假失败”。所以,我们不按“认证”、“模型”、“网络”等传统分类来讲,而是严格按 config.toml 文件中字段出现的物理顺序,一行一行拆解。这不是为了形式主义,而是因为 Codex CLI 的加载逻辑就是顺序解析——它先读api_key,再读base_url,再读model……中间任何一个字段解析失败(比如timeout = "30s"写成timeout = 30s缺少引号),整个配置加载就会中断,并抛出一个极其模糊的Failed to parse config file错误,根本不会告诉你哪一行错了。我试过用 toml-lint 工具校验,它能发现语法错误,但发现不了语义错误,比如model = "gpt-4-turbo"配给一个只支持llama3:70b的本地 Ollama 实例——这在语法上完全合法,但运行时必然报错。因此,逐行讲解的本质,是模拟 Codex CLI 的加载引擎视角,提前预判每一行可能埋下的雷。下面这张表,列出了 2026 年最新版 Codex CLI(v0.8.3)config.toml 的全部可配置字段及其默认值,我们将以此为蓝本展开:
| 字段名 | 类型 | 默认值 | 是否必需 | 说明 |
|---|---|---|---|---|
api_key | string | "sk-..."(占位符) | 是 | 认证凭据,对 OpenAI 是真实 key,对兼容接口可能是空字符串、"dummy"或特定格式 token |
base_url | string | "https://api.openai.com/v1" | 是 | 兼容接口的根地址,必须包含/v1,且末尾不能有斜杠 |
model | string | "gpt-3.5-turbo" | 是 | 模型标识符,需与兼容接口/v1/models返回的列表完全一致,区分大小写 |
timeout | string | "30s" | 否 | 超时时间,格式为数字+单位(s,ms),必须加引号,否则 toml 解析失败 |
max_tokens | integer | 1024 | 否 | 单次请求最大生成 token 数,受模型上下文窗口限制,设得过大将被服务端静默截断 |
temperature | float | 0.7 | 否 | 采样温度,范围 0.0 ~ 2.0,0.0 为确定性输出,兼容接口对此参数的支持度差异极大 |
top_p | float | 1.0 | 否 | 核心采样概率阈值,部分兼容接口(如早期 LiteLLM 版本)会忽略此参数 |
stream | boolean | true | 否 | 是否启用流式响应,设为false可规避某些兼容接口的 stream chunk 解析 bug |
proxy | string | "" | 否 | HTTP 代理地址,格式http://user:pass@host:port,仅支持 http/https,不支持 socks |
提示:Codex CLI不支持
.env文件自动加载,也不支持环境变量覆盖(如CODER_CLI_API_KEY)。所有配置必须显式写在 config.toml 中,这是它轻量化的代价,也是稳定性的保障——避免了环境变量污染和优先级混乱。
2.1api_key = "your-api-key-here":认证不是“有就行”,而是“匹配服务端预期”
这一行看起来最简单,却是报错率第二高的地方(仅次于 base_url 格式错误)。很多人直接把 OpenAI 的 key 粘贴过来,然后去连一个本地 Ollama 实例,结果得到401 Unauthorized。原因在于:Ollama 的/v1/chat/completions接口默认不校验 API Key,它期望api_key字段为空或任意字符串(如"ollama"),而 Codex CLI 在构造请求头时,会无条件添加Authorization: Bearer <api_key>。如果 Ollama 配置了OLLAMA_ORIGINS或启用了--host绑定,它可能拒绝带有非空 Authorization 头的请求。解决方案不是删掉这行,而是将其设为api_key = ""(空字符串)或api_key = "no-auth"。反过来,如果你连的是 LiteLLM,它默认要求一个有效的api_key,但这个 key 不是 OpenAI 的,而是你在 LiteLLM 启动时通过--api_key参数指定的(如litellm --api_key sk-123),那么这里就必须填sk-123。更复杂的情况是某云厂商的兼容层,它可能要求一个 Base64 编码的project_id:api_key组合。所以,api_key的值,必须是你所连接的具体兼容接口文档中明确要求的认证方式,而不是一个通用占位符。我踩过的坑是:在测试一个自研的 vLLM API server 时,开发同学说“我们不鉴权”,我就填了空字符串,结果发现他们内部用了一个中间件,会把空 Authorization 头当成Bearer null并拦截。最后解决方案是填api_key = "valid",并在服务端中间件里放行这个固定字符串。这再次印证:api_key行不是填一个密码,而是填写一个“服务端能识别的通行证”。
2.2base_url = "https://your-compat-endpoint.com/v1":URL 末尾的斜杠,是 90% 新手的“断点调试起点”
base_url是报错率最高的字段,没有之一。错误示例五花八门:https://localhost:11434(缺/v1)、http://127.0.0.1:8000/v1/(末尾多斜杠)、https://api.ollama.ai(路径不对)、甚至base_url = localhost:11434/v1(缺协议头)。Codex CLI 的请求构造逻辑非常直白:它把base_url当作根,然后硬编码拼接/chat/completions。所以,如果你的base_url是https://localhost:11434,最终请求地址就是https://localhost:11434/chat/completions,这显然 404。正确的 Ollama 地址必须是http://127.0.0.1:11434/v1(注意是http,不是https,Ollama 默认不启 https)。而 LiteLLM 的标准地址是http://0.0.0.0:4000/v1。关键细节来了:base_url末尾绝对不能有斜杠。为什么?因为 Codex CLI 的源码里是这样拼的:format!("{}/chat/completions", base_url)。如果base_url = "http://127.0.0.1:11434/v1/",拼出来就是http://127.0.0.1:11434/v1//chat/completions,双斜杠导致 404。这个 bug 在 2025 年底的某个 PR 里被修复,但大量线上文档和教程还没更新,所以你看到的很多“正确示例”其实是错的。实测下来最稳的写法是:先用 curl 手动测试你的兼容接口是否工作,例如curl http://127.0.0.1:11434/v1/chat/completions -H "Content-Type: application/json" -d '{"model":"llama3","messages":[{"role":"user","content":"hi"}]}',如果这个 curl 成功,那么你的base_url就应该精确等于这个 curl 命令里https://...到/v1为止的部分,且确保末尾没斜杠。我建议把这个测试步骤写成一个 shell 脚本,每次换环境前先跑一遍,比反复改 config.toml 然后看 Codex CLI 报什么错要高效得多。
2.3model = "llama3:70b":模型名不是“随便起”,而是“服务端注册名”的镜像
model字段的值,必须与你所连兼容接口的/v1/models接口返回的data[].id字段完全一致。这不是 Codex CLI 的规定,而是 OpenAI API 规范的要求。当你访问http://127.0.0.1:11434/v1/models(Ollama),你会看到类似这样的 JSON:
{ "object": "list", "data": [ { "id": "llama3:70b", "object": "model", "owned_by": "community", "permission": [] } ] }这里的"id": "llama3:70b"就是你要填的 model 值。常见错误是填llama3-70b(用短横线)、llama3_70b(用下划线)或Llama-3-70B(大小写混用)。Ollama 对模型名是严格区分大小写和符号的。另一个典型场景是 LiteLLM,它支持路由(routing),你可以把多个后端模型映射到一个逻辑名,比如在 LiteLLM 的litellm_model_config.yaml里定义:
model_list: - model_name: my-prod-model litellm_params: model: "azure/gpt-4o" api_base: "https://my-azure.openai.azure.com/" api_key: "..."那么你的 Codex CLI config.toml 里就应该写model = "my-prod-model",而不是gpt-4o。这里的关键洞察是:model字段是客户端视角的模型别名,它最终会被兼容接口解析并路由到真正的后端模型。所以,在配置前,务必先调用GET /v1/models,把返回的id列表复制粘贴到 config.toml 里,这是唯一可靠的方法。我见过最离谱的案例是:一位同事在 config.toml 里写了model = "gpt-4-turbo-2024-04-09",连的是一个只支持qwen2:7b的 Ollama 实例,结果 Codex CLI 报错Error: model not found,他花了两小时查文档,最后发现 Ollama 根本没这个模型,/v1/models返回的只有一个qwen2:7b。所以,model行的本质,是一份“服务端能力声明”,你填什么,就代表你确认服务端有这个能力。
2.4timeout = "30s":超时不是“越长越好”,而是“比服务端 P99 延迟多留 20%”
timeout字段的值是一个字符串,格式为<数字><单位>,单位支持s(秒)和ms(毫秒),且必须用双引号包裹。这是 TOML 语法的硬性要求。如果你写成timeout = 30s,TOML 解析器会把它当作一个未定义的标识符,直接崩溃。这个字段控制的是 Codex CLI 发起 HTTP 请求后的最大等待时间。设得太短,比如timeout = "5s",对于一个在本地 GPU 上跑llama3:70b的 Ollama 实例,首次加载模型可能就要 10 秒,结果请求永远超时;设得太长,比如timeout = "300s",一旦服务端彻底挂掉,Codex CLI 会傻等 5 分钟才报错,严重影响开发体验。所以,合理的timeout应该基于你所连服务端的实际 P99 延迟来设定。怎么测?用ab(Apache Bench)或hey工具。例如,对 Ollama 的/v1/chat/completions接口做压力测试:
hey -n 100 -c 10 -m POST -H "Content-Type: application/json" -d '{"model":"llama3:70b","messages":[{"role":"user","content":"Hello"}]}' http://127.0.0.1:11434/v1/chat/completions查看输出里的99th percentile时间,假设是12.4s,那么你的timeout就应该设为"15s"(12.4 * 1.2 ≈ 14.9,向上取整)。这个“多留 20%”的经验值,是为了应对网络抖动、GPU 显存碎片化等瞬时因素。对于 LiteLLM 这种代理层,它的 P99 延迟通常很低(< 1s),但它的上游(比如 Azure OpenAI)延迟可能很高,所以你的timeout应该以最终下游的 P99 为准,而不是 LiteLLM 本身的响应时间。我自己的配置习惯是:本地 Ollama 用"20s",远程 LiteLLM 用"60s",纯 OpenAI 用"45s"。这个数值不是拍脑袋,而是每次换模型、换硬件、换网络环境后,都重新测一遍 P99 得来的。
2.5max_tokens = 1024:这个数字不是“越大越好”,而是“模型上下文窗口减去输入 tokens 的安全余量”
max_tokens是一个整数,它告诉服务端:“除了我的输入 prompt,你最多可以生成这么多 token”。但它不是无上限的。每个模型都有一个硬性的“上下文长度”(context length),比如llama3:70b是 8192,gpt-4-turbo是 128k。但max_tokens的值,必须小于等于context_length - input_tokens。Codex CLI不会帮你计算input_tokens,它只是把你的命令行输入(如codex ask "写一个快速排序的 Python 函数")原样塞进messages数组,然后把max_tokens作为max_completion_tokens发送给服务端。如果你设max_tokens = 8192,但你的 prompt 本身已经占了 2000 tokens,那么服务端要么静默截断,要么返回400 Bad Request。所以,max_tokens的合理值,取决于你日常使用的 prompt 复杂度。一个简单的代码问答,512足够;一个需要分析 200 行代码的 review,可能需要2048。我自己的经验是:先用tiktoken库估算你的典型 prompt 的 token 数,然后用context_length - prompt_tokens得到理论最大值,再打个 7 折作为max_tokens的初始值。例如,llama3:70b上下文 8192,我的平均 prompt 是 800 tokens,那么max_tokens初始设为(8192-800)*0.7 ≈ 5174,取整5120。后续根据实际生成是否被截断,再微调。这个字段之所以重要,是因为它是唯一能防止“生成一半突然中断”的客户端控制点。服务端不会告诉你“我给你生成了 3000 tokens 就停了”,它只会返回一个完整的、但内容不全的 response,让你误以为逻辑有问题。
3. 从“报错信息”反向定位:一张表搞定 95% 的常见故障
Codex CLI 的错误信息设计得很“程序员友好”——它不给你任何废话,只抛出最原始的 HTTP 状态码或底层错误。这很好,但也意味着你需要具备一定的网络和 JSON 解析基础。下面这张表,是我过去一年在多个项目中收集、验证并归因的最常见报错,按出现频率从高到低排列,并给出了可立即执行的排查步骤,而不是泛泛而谈的“检查网络”:
| 报错信息(CLI 输出) | 根本原因 | 1 分钟内可执行的排查动作 | 修复方案 |
|---|---|---|---|
Error: failed to parse config file: expected a value | config.toml 语法错误,最常见于timeout字段没加引号,或api_key值里有未转义的#符号 | 运行tomlcheck config.toml(需安装 tomlcheck)或在线 TOML 校验器粘贴内容 | 给所有字符串字段加双引号;#符号用#替换或移除 |
Error: request failed with status code 404 | base_url拼接错误,导致请求发到了不存在的路径 | curl -v <base_url>/chat/completions,观察 curl 的实际请求 URL 和返回 | 修正base_url,确保其精确等于curl命令中https://...到/v1的部分,且末尾无斜杠 |
Error: request failed with status code 401 | api_key不被服务端接受,或服务端根本不要 key | curl -H "Authorization: Bearer <your_api_key>" <base_url>/models,观察 401 是否依然存在 | 若服务端不要 key,设api_key = "";若要 key,确认 key 值与服务端文档要求完全一致(包括大小写、前缀) |
Error: request failed with status code 400 | model名称错误,或max_tokens超出服务端限制,或messages格式非法 | curl -H "Content-Type: application/json" -d '{"model":"<your_model>","messages":[{"role":"user","content":"test"}]}' <base_url>/chat/completions | 用GET <base_url>/models获取正确 model id;降低max_tokens值;确保 messages 数组至少有一个对象,且 role 为user/system/assistant |
Error: request failed with status code 429 | 请求频率超限,服务端返回了retry-after头 | curl -I <base_url>/chat/completions,查看响应头中是否有retry-after | Codex CLI 本身不处理retry-after,需手动等待指定秒数,或联系服务端管理员提升配额 |
Error: connection refused | base_url的 host:port 根本没在监听,或被防火墙拦截 | telnet <host> <port>或nc -zv <host> <port> | 检查服务端进程是否运行(ps aux | grep ollama);检查端口绑定(ss -tuln | grep <port>);关闭防火墙或开放端口 |
Error: stream parse error | 兼容接口返回的 stream chunk 格式不符合 OpenAI 标准(如缺少data:前缀,或data: [DONE]格式错误) | curl <base_url>/chat/completions -H "Content-Type: application/json" -d '{"model":"...","stream":true,"messages":[{"role":"user","content":"hi"}]}',观察原始响应流 | 设stream = false绕过;或升级兼容接口版本(如 Ollama 0.3.0+ 修复了 stream 格式);或在 LiteLLM 中启用--drop-ratelimit-headers |
注意:当遇到
400或401错误时,绝对不要先去改 Codex CLI 的源码或重编译。99% 的情况,问题出在配置或服务端状态。上面表格里的curl测试,就是你的“黄金三分钟诊断法”——它绕过了 Codex CLI 的所有封装,直接与服务端对话,能瞬间定位是客户端配置问题,还是服务端实现问题。
3.1 “Connection refused” 的深度排查:不只是 telnet 那么简单
Connection refused是最让人抓狂的错误,因为它意味着网络层就断了,你甚至看不到任何 HTTP 响应。但它的原因远不止“服务没开”。我遇到过一个典型案例:一台 Ubuntu 服务器上,Ollama 进程明明在运行(ps aux \| grep ollama显示正常),telnet 127.0.0.1 11434却显示Connection refused。排查步骤如下:
- 确认监听地址:Ollama 默认只监听
127.0.0.1:11434,这意味着它只接受来自本机的连接。如果你的 Codex CLI 是在另一台机器上运行,base_url设为http://<server-ip>:11434/v1,那必然Connection refused。解决方案是启动 Ollama 时加--host 0.0.0.0:11434参数,让它监听所有网卡。 - 检查端口占用:
sudo ss -tuln \| grep :11434,看是不是有其他进程(比如一个旧的 Ollama 实例)占用了这个端口。如果有,kill掉它。 - 验证防火墙:Ubuntu 默认的
ufw防火墙可能阻止了外部连接。运行sudo ufw status verbose,如果状态是active,则运行sudo ufw allow 11434。 - Docker 网络陷阱:如果你用 Docker 运行 Ollama(
docker run -d -p 11434:11434 --name ollama -v ollama:/root/.ollama ollama/ollama),-p 11434:11434只是把容器的 11434 映射到宿主机的 11434,但容器内部的 Ollama 还是默认监听127.0.0.1。所以你需要docker run -d -p 11434:11434 --name ollama -v ollama:/root/.ollama -e OLLAMA_HOST=0.0.0.0:11434 ollama/ollama,通过环境变量强制 Ollama 监听0.0.0.0。 这四步做完,90% 的Connection refused都能解决。核心思想是:Connection refused不是“连不上”,而是“连到了一个明确拒绝你的端口”,所以问题一定出在服务端的网络配置上,而不是客户端的 DNS 或路由。
3.2 “Stream parse error” 的根源:兼容接口的流式响应,至今没有统一标准
Stream parse error是 2026 年最典型的“时代错位”错误。OpenAI 的流式响应规范是:每个 chunk 是一个以data:开头的纯文本行,最后一行是data: [DONE]。但很多开源兼容接口在实现时,要么忘了加data:前缀,要么把[DONE]写成了{"done": true},要么在 chunk 之间插入了空行。Codex CLI 的流式解析器非常严格,它期望一个完美的 OpenAI 格式。解决方案有三个层次:
- 最低成本(推荐):在 config.toml 中设
stream = false。这会让 Codex CLI 发送一个非流式请求,服务端返回一个完整的 JSON,解析成功率 100%。虽然失去了实时响应的体验,但对于大多数代码生成、解释类任务,影响不大。 - 中等成本:升级你的兼容接口。Ollama 在 0.3.0 版本(2025 Q4 发布)中彻底重写了 stream handler,完全兼容 OpenAI 格式;LiteLLM 在 1.45.0 版本中增加了
--stream-chunk-size参数,可以精细控制 chunk 分隔。查一下你的版本号,不行就ollama update或pip install --upgrade litellm。 - 最高成本(不推荐):自己写一个中间代理,把不规范的 stream 响应转换成规范格式。这违背了 Codex CLI “轻量”的设计初衷,属于杀鸡用牛刀。
4. 实操全流程:从零开始,5 分钟完成 Codex CLI + Ollama 本地闭环
现在,我们把前面所有的知识点,串成一个可立即执行的完整流程。目标:在一台全新的 Ubuntu 24.04 机器上,从安装 Ollama 和 Codex CLI,到配置好 config.toml,再到成功运行codex ask "用 Rust 写一个斐波那契数列函数"。整个过程不依赖任何外部网络(除了下载安装包),所有命令都是实测有效的。
4.1 环境准备:安装 Ollama 和 Codex CLI
首先,安装 Ollama。Ollama 官方提供了极简的一行安装脚本:
curl -fsSL https://ollama.com/install.sh | sh安装完成后,启动 Ollama 服务:
systemctl start ollama # 设置开机自启 systemctl enable ollama然后,拉取一个模型。我们选llama3:8b,它小、快、适合测试:
ollama pull llama3:8b接下来,安装 Codex CLI。Codex CLI 是一个单二进制文件,官方 Release 页面(https://github.com/codex-team/codex-cli/releases)提供了 Linux x86_64 的预编译包。我们用wget直接下载:
# 下载最新版(截至2026年,v0.8.3) wget https://github.com/codex-team/codex-cli/releases/download/v0.8.3/codex-cli-v0.8.3-x86_64-unknown-linux-gnu.tar.gz # 解压 tar -xzf codex-cli-v0.8.3-x86_64-unknown-linux-gnu.tar.gz # 移动到 PATH sudo mv codex-cli /usr/local/bin/ # 验证 codex-cli --version4.2 创建并验证 config.toml:一行一行来
创建配置文件:
mkdir -p ~/.config/codex-cli nano ~/.config/codex-cli/config.toml现在,严格按照我们前面讲的规则,逐行填写:
# 第1行:api_key,Ollama 不需要,填空字符串 api_key = "" # 第2行:base_url,Ollama 的标准地址,注意 http、端口、/v1,且末尾无斜杠 base_url = "http://127.0.0.1:11434/v1" # 第3行:model,必须和 /v1/models 返回的 id 一致 model = "llama3:8b" # 第4行:timeout,Ollama 本地运行,P99 延迟约 3s,设为 "5s" timeout = "5s" # 第5行:max_tokens,llama3:8b 上下文 8192,简单 prompt 约 200 tokens,设为 2048 max_tokens = 2048 # 第6行:temperature,保持默认 temperature = 0.7 # 第7行:top_p,保持默认 top_p = 1.0 # 第8行:stream,为规避潜在的 stream 格式问题,设为 false stream = false # 第9行:proxy,本地不用,留空 proxy = ""保存退出。现在,用tomlcheck验证语法(如果没有,pip install tomlcheck):
tomlcheck ~/.config/codex-cli/config.toml # 如果输出 "Valid TOML",说明语法正确4.3 最终验证:用一个真实的代码请求,走通全链路
现在,执行最终测试:
codex-cli ask "用 Rust 写一个计算斐波那契数列第 n 项的函数,要求使用迭代而非递归,函数签名是 `fn fib(n: u32) -> u64`"如果一切顺利,你应该在几秒钟内看到类似这样的输出:
fn fib(n: u32) -> u64 { if n == 0 { return 0; } if n == 1 { return 1; } let mut a: u64 = 0; let mut b: u64 = 1; for _ in 2..=n { let next = a + b; a = b; b = next; } b }恭喜,你已经完成了 Codex CLI 与 OpenAI 兼容接口的完整接入。这个过程之所以能 5 分钟搞定,核心在于:我们没有在“连不通”之后盲目地改东改西,而是严格遵循了“先验证服务端(curl)、再配置客户端(config.toml)、最后执行命令(codex-cli)”的三步铁律。每一次失败,都对应着上面表格里的一条明确路径。
5. 进阶技巧与避坑心得:那些文档里不会写的“老司机经验”
作为一个在过去两年里,用 Codex CLI 搭建了 7 套不同后端(Ollama、LiteLLM、vLLM、Azure OpenAI、某国产大模型 API、自研 FastAPI 代理、Kubernetes Ingress 路由)的实践者,我想分享几个血泪换来的、文档里绝不会写的技巧。它们不炫技,但能帮你每天节省半小时。
5.1 技巧一:用codex-cli --debug看见“看不见的请求”
Codex CLI 有一个隐藏的--debug标志,它会打印出所有发出的 HTTP 请求和收到的响应(脱敏后的)。这是你排查400、401问题的终极武器。例如:
codex-cli --debug ask "hello"输出会类似:
DEBUG sending request to http://127.0.0.1:11434/v1/chat/completions DEBUG request headers: {"Content-Type": "application/json", "Authorization": "Bearer "} DEBUG request body: {"model":"llama3:8b","messages":[{"role":"user","content":"hello"}],"max_tokens":2048,"temperature":0.7,"top_p":1.0,"stream":false} DEBUG response status: 200 DEBUG response body: {"id":"chatcmpl-...","object":"chat.completion","created":1712345678,"model":"llama3:8b","choices":[{"index":0,"message":{"role":"assistant","content":"Hello! How can I help you today?"},"finish_reason":"stop"}],"usage":{"prompt_tokens":12,"completion_tokens":15,"total_tokens":27}}看到了吗?request body