为什么 Codex CLI 接 GLM-5.1 会卡在协议这一层
Codex CLI 从 0.84.0 开始,默认走的是 OpenAI 的 Responses API 协议;而智谱 GLM-5.1 对外暴露的是 Chat Completions API。两者在请求体结构、流式事件格式、工具调用字段上都不一致,直接把base_url指向智谱的端点,Codex CLI 发出去的/responses请求会直接吃 404 或协议解析失败。
原文给出的解法是在本机跑一个 CLIProxyAPI 做协议转换:Codex CLI 把请求发给http://127.0.0.1:8080/v1,代理把 Responses 转成 Chat Completions 再转发给智谱。这套方案能跑通,但代价是你得自己下载二进制、维护 YAML 配置、盯着 8080 端口的进程,机器重启或换环境就要重来一遍。
这篇换一个思路:不再本地维护代理,而是把 Codex CLI 的模型通道直接接到 TaoToken(官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end )。TaoToken 在这里只做两件事——给你一个 Key、给你一个 Base URL,剩下的协议适配由通道侧处理。Codex CLI 的config.toml里保留[model_providers.glm-proxy]这个结构,只把base_url从http://127.0.0.1:8080/v1换成https://taotoken.net/api,env_key继续指向 shell 里导出的变量,变量值填你在官网创建的 Key。改完运行codex提一个读项目结构的问题,请求能走通就说明通道配好了。
需要先说清楚边界:TaoToken 不替 Codex CLI 读文件、不替它执行命令,它只负责模型请求的转发。Codex CLI 本身的文件读写、命令执行能力完全由本地 CLI 决定,和通道无关。
前置准备:拿到 Key 和 Base URL
在动手改config.toml之前,先把两样东西准备好。
第一样是 Key。打开 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 注册账号,进入控制台后创建 API Key。这个 Key 就是后面要写进 shell 环境变量的值,形如YOUR_API_KEY的位置会被它替换。创建后先复制保存,页面刷新后不一定还能完整看到。
第二样是 Base URL。Codex CLI 的model_providers段里base_url填https://taotoken.net/api。注意这里不要带 UTM 参数——官网首页那个带?utm_source=...的地址是给人看的落地页,不是 API 端点。把带 UTM 的完整地址填进config.toml,请求会打到错误路径上。
环境要求方面,Node.js 建议 22 及以上,Codex CLI 用npm install -g @openai/codex@latest装最新版。旧版本(0.80.0 一类)在 macOS 上可能被 Gatekeeper 拦截未签名二进制,直接用最新版可以绕开这个坑。
如果你还想在终端里用 TaoToken 的 CLI 工具做辅助,可以装:
npm i -g @taotoken/taotoken taotoken cc -k YOUR_API_KEY -u https://taotoken.net/api -m MODEL_ID不过这篇的主线是 Codex CLI 自己的config.toml,CLI 工具只是可选补充。
改写 ~/.codex/config.toml 的 model_provider
Codex CLI 的配置文件在~/.codex/config.toml。原文 6.1 节给出的结构可以直接沿用,核心改动只有一处:base_url。
先看改完后的完整配置:
# 交互风格 personality = "pragmatic" # 模型提供商和模型名称 model_provider = "glm-proxy" model = "glm-5.1" # MCP 服务器配置(可选,按需保留) [mcp_servers] [mcp_servers.sequential-thinking] type = "stdio" command = "npx" args = ["-y", "@modelcontextprotocol/server-sequential-thinking"] [mcp_servers.memory] type = "stdio" command = "npx" args = ["-y", "@modelcontextprotocol/server-memory"] # 自定义模型提供商 [model_providers.glm-proxy] name = "GLM via TaoToken" base_url = "https://taotoken.net/api" env_key = "CODEX_GLM_KEY" wire_api = "responses" # 项目信任级别 [projects."/Users/你的用户名"] trust_level = "trusted"几个字段逐个说明:
model_provider = "glm-proxy"指向下面[model_providers.glm-proxy]这个段,名字可以自定义,只要两处一致即可。
model = "glm-5.1"是请求里带的模型标识。Codex CLI 启动时如果提示Model metadata for 'glm-5.1' not found,这是正常警告——CLI 本地没有这个模型的元数据定义,会退回默认参数,不影响请求发送。
base_url = "https://taotoken.net/api"是这篇最关键的改动。原文这里是http://127.0.0.1:8080/v1,指向本地 CLIProxyAPI;现在指向 TaoToken 的 API 端点。注意结尾不要多加/v1,Codex CLI 会自己在后面拼路径。
env_key = "CODEX_GLM_KEY"告诉 Codex CLI:去读名为CODEX_GLM_KEY的环境变量,把它的值当作 API Key 发出去。这里填的是变量名,不是 Key 本身。
wire_api = "responses"保持 Responses 协议不变,Codex CLI 仍然按它熟悉的方式发请求,协议适配在通道侧完成。
改完config.toml后,把 Key 写进 shell 环境变量。以 zsh 为例:
echo 'export CODEX_GLM_KEY="YOUR_API_KEY"' >> ~/.zshrc source ~/.zshrc echo $CODEX_GLM_KEY最后一条echo应该打印出你刚填的 Key。如果打印为空,说明变量没生效,后面 Codex CLI 会报Missing environment variable。
这里有个容易踩的点:env_key的值、shell 里导出的变量名、config.toml里写的字符串,三者必须完全一致。原文 6.2 节强调过env_key指定的变量值要和代理配置里的api-keys匹配;换成 TaoToken 后,不再有本地代理的api-keys列表,但env_key和 shell 变量名的一致性要求没变。
验证请求:跑一个读项目结构的问题
配置改完,先确认环境变量和文件都对:
# 确认环境变量 echo $CODEX_GLM_KEY # 确认 config.toml 里的 base_url grep base_url ~/.codex/config.toml然后进入一个项目目录,启动 Codex CLI:
cd /path/to/your/project codex在交互模式里提一个轻量问题,比如「列出这个项目的目录结构,并说明每个顶层目录的作用」。这个问题会触发 Codex CLI 读取文件系统,同时向模型发一次请求。
如果通道配通,你会看到 Codex CLI 正常读取目录、把结构信息组织成回答返回。整个过程中,请求路径是:Codex CLI 读取env_key拿到 Key → 向https://taotoken.net/api发 Responses 请求 → 通道侧完成协议适配 → 返回结果给 CLI。
也可以用非交互方式快速验证:
codex "解释这个项目的架构"或者指定工作目录:
codex --cwd /path/to/project "分析代码质量"只要能看到模型返回内容,就说明model_provider配通了。如果卡住不动或直接报错,进入下一节的排查。
本篇常见错排查
Missing environment variable: CODEX_GLM_KEY
这是最常见的报错,含义是 Codex CLI 按env_key去找环境变量,但没找到。
排查顺序:
# 1. 当前 shell 里变量是否存在 echo $CODEX_GLM_KEY # 2. 如果为空,检查 shell 配置文件里有没有写进去 grep CODEX_GLM_KEY ~/.zshrc # 3. 手动导出后重试 export CODEX_GLM_KEY="YOUR_API_KEY" codex注意一个细节:如果你在 A 终端窗口source ~/.zshrc,然后在 B 窗口启动 Codex CLI,B 窗口不会自动继承。要么在每个窗口都 source 一次,要么把导出写进 shell 配置后重开终端。
401 Unauthorized
401 说明请求发出去了,但 Key 没通过校验。可能的原因:
一是env_key指向的变量值不是你在官网创建的那个 Key,比如复制时漏了字符,或者填成了别的项目的 Key。重新echo $CODEX_GLM_KEY核对。
二是config.toml里env_key写的变量名和 shell 里导出的变量名不一致。比如配置里写CODEX_GLM_KEY,shell 里导出的是CODEX_KEY,Codex CLI 读不到值,就会以空 Key 发请求,返回 401。
三是 Key 本身在控制台被删除或重置过。回 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 的 API Keys 页面确认 Key 状态。
请求打到错误地址 / 404
如果base_url填成了带 UTM 的官网地址,比如https://taotoken.net/?utm_source=...,请求会打到落地页而不是 API 端点,返回 404 或 HTML 内容导致解析失败。
正确写法是base_url = "https://taotoken.net/api",不带任何查询参数。改完config.toml后重新启动 Codex CLI。
Model metadata for 'glm-5.1' not found
这是警告不是错误。Codex CLI 本地没有glm-5.1的元数据定义(比如上下文窗口大小、定价信息),会使用默认值。请求照常发送,不影响使用。原文 8.5 节也提到过这一点。
stream disconnected before completion
流式响应中途断开。原文场景下这是本地代理的流式兼容问题,换用 TaoToken 通道后,协议适配在通道侧处理,这类问题通常不再出现。如果仍然遇到,先确认网络到https://taotoken.net/api是通的,再检查是不是项目太大导致单次请求超时。
macOS 提示「恶意软件已阻止」
这是旧版 Codex CLI 二进制未签名导致的,和通道配置无关。用npm install -g @openai/codex@latest装最新版即可。如果必须用旧版,可以手动签名:
codesign --force --deep -s - /path/to/codex/binary配通之后:把通道固定下来
到这里,Codex CLI 的model_provider已经指向 TaoToken,终端里的 GLM-5.1 编程会话会按这条通道发请求。回顾一下改动清单:
~/.codex/config.toml里[model_providers.glm-proxy]段的base_url从本地代理地址换成https://taotoken.net/api,env_key保持指向CODEX_GLM_KEY,wire_api保持responses。shell 里导出CODEX_GLM_KEY,值填官网创建的 Key。不再需要下载 CLIProxyAPI 二进制、不再需要维护cliproxy-config.yaml、不再需要盯着 8080 端口的进程。
如果你后续要在多台机器上复用这套配置,把config.toml的model_providers段和 shell 导出这两处同步过去就行。Key 建议按机器或按项目分开创建,方便在控制台单独吊销。
需要回查 Key 状态或创建新 Key,走 API Keys 页面;接入细节和字段说明看接入文档;想先在网页里试一下模型对话是否正常,可以用模型对话入口;如果打算长期在终端里跑编码任务、需要更稳定的调用额度,可以了解 Coding Plan。
- API Keys 与控制台:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=codex_cli_glm51&utm_campaign=rewrite
- 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=codex_cli_glm51&utm_campaign=rewrite
- 模型对话:https://taotoken.net/console/chat?utm_source=taotoken_aicg_blog_end&utm_content=codex_cli_glm51&utm_campaign=rewrite
- Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=codex_cli_glm51&utm_campaign=rewrite