面试时 Codex 疯狂报错——CCX 接国产模型的 500 错误排查实录

面试官让我用 Codex 做 AI Coding 环节,结果 API 一直报 500。我当场切模型,发现旧对话还是走老模型。那一刻的尴尬,希望你不用经历。


目录


那个面试下午

面试到 AI Coding 环节,面试官说"你用 Codex 写个 XX 功能吧"。我打开终端,启动 Codex,输入需求,等回复。

然后就看到一行红字:500 Internal Server Error

我以为是偶发,重试了一下,还是 500。换了 gpt-5.4 的映射名,500。换成 codex,500。这时候面试官开始看我屏幕了。

我想着先切到 DeepSeek 救场,用 ccswitch 切了模型,显示"已激活"。但开新请求,还是 500——而且去 Mimo 的 API 控制台一看,请求量还在涨。ccswitch 说切了,CCX 根本没动。

更惨的是,我在旧对话里切模型,Codex 还是用的之前的模型名。得开新对话才生效。

那天面试的结果不重要。重要的是事后我把这个问题彻底搞清楚了,写下来,让你少踩几个坑。


CCX 是什么,为什么需要它

Codex CLI 是 OpenAI 的命令行 AI 编程工具,它默认只认 OpenAI 的 API 格式。但国内用 OpenAI 的 API 不太方便,大家更常用 DeepSeek、小米 Mimo、通义千问这些国产模型。

问题是:这些国产模型的 API 接口虽然大多兼容 OpenAI 格式,但细节上有差异——参数名不同、有些字段不支持、限流策略不一样。

CCX(CCProxy) 就是解决这个问题的。它是一个 API 网关,坐在 Codex 和模型供应商之间,做三件事:

  • 协议转换:把 Codex 发出的 OpenAI 标准请求转成各供应商能认的格式
  • 路由分发:按优先级把请求发到不同的供应商(比如 Mimo 优先,DeepSeek 备用)
  • 参数适配:过滤掉供应商不支持的参数,避免报错

三件套的分工:Codex 负责写代码,CCX 负责转请求,国产模型负责生成。缺一环都不行。


问题长什么样

具体症状:

  • 通过 CCX 发送的所有请求都返回 500 Internal Server Error
  • 涉及所有模型映射:gpt-5.4codexmimo-v2.5-pro 全挂
  • CCX 日志显示连接成功,但在"首字生成"阶段失败
  • 请求目标是 https://token-plan-cn.xiaomimimo.com

三个信息很关键:

  1. 所有模型都挂 → 不是某个模型的问题,是 CCX 转发层的问题
  2. 连接成功但生成失败 → 不是网络不通,是请求内容被拒绝
  3. 目标是小米的 API → 小米的参数校验可能比较严格

排查四步走

第一步:确认 API 本身没问题

先排除小米 API 自身的故障。直接绕过 CCX,用 curl 直接调小米的 API。

这里有个坑:Windows 下 curl 的行为和 Linux 不一样。

  • CMD 不支持 \ 换行和单引号,命令会被拆成多行单独执行
  • PowerShell 里 curlInvoke-WebRequest 的别名,参数语法完全不同
  • Git Bash 最省事,完全兼容 Linux 语法

推荐用 curl.exe(加 .exe 后缀强制调原生 curl),整行粘贴:

curl.exe -X POST https://token-plan-cn.xiaomimimo.com/v1/chat/completions -H "Content-Type: application/json" -H "Authorization: Bearer tp-你的API密钥" -d "{\"model\": \"mimo-v2.5-pro\", \"messages\": [{\"role\": \"user\", \"content\": \"你好\"}], \"temperature\": 0.7}"

如果这条命令返回了正常的对话响应,说明小米 API 没问题,毛病在 CCX 的转发逻辑里。

第二步:定位 CCX 配置问题

API 没问题,那问题出在 CCX 转发请求时带了小米不认的参数。

CCX 默认会把 Codex 发来的所有 OpenAI 标准参数原样转发。但小米 Mimo 的 API 对参数校验很严格——它不认识的参数不会忽略,而是直接返回 500。

解决办法是用 CCX 的 stripParams 配置项,告诉 CCX “这些参数发给小米之前先剥掉”。stripParams 的意思是"剥离参数",即在请求转发到上游之前,删除指定的请求体字段。

需要剥掉的参数:

"stripParams": [
  "stream_options",
  "tools",
  "function_call",
  "max_tokens",
  "presence_penalty",
  "frequency_penalty",
  "top_p",
  "n",
  "stop",
  "logprobs",
  "echo",
  "store",
  "output_config"
]

除了参数过滤,还要控制并发。小米免费套餐有 QPS(每秒请求数)限制,CCX 默认没有限流,多个请求同时打过去会触发小米的限流机制,也会返回 500。

"maxConcurrent": 2,
"qps": 1,
"retryCount": 1,
"retryDelay": 2000,
"disableTools": true
  • maxConcurrent: 2:最多同时 2 个请求在处理
  • qps: 1:每秒最多 1 个请求
  • retryCount: 1:失败重试 1 次
  • retryDelay: 2000:重试间隔 2 秒
  • disableTools: true:禁用工具调用,小米 API 暂不支持

第三步:修复 CCX 启动失败

改完配置文件,双击 ccx.exe,没反应。进程一闪就没了。

这种情况 99% 是配置文件的 JSON 语法有问题。几个常见原因:

JSON 里写了注释。标准 JSON 不支持注释,///* */ 都会导致解析失败。CCX 用的是严格 JSON 解析器,不接受任何注释。

排查步骤

  1. Ctrl+Shift+Esc 打开任务管理器,结束所有 ccx.execcproxy.exe 进程
  2. 用 VS Code 打开配置文件,看有没有红色波浪线报语法错误
  3. 或者去 jsonlint.com 粘贴配置内容,确认显示 “Valid JSON”
  4. 检查文件编码:用记事本打开 → 另存为 → 编码选 “UTF-8”(不要 UTF-8 BOM)
  5. 检查端口占用:netstat -ano | findstr ":3000",如果有进程占了 3000 端口,先结束它
  6. 右键 ccx.exe → 以管理员身份运行

第四步:密钥安全

排查过程中你可能把 API 密钥贴到了聊天记录、日志文件、甚至公开的论坛里。

如果密钥暴露过,立刻去小米 AI 开放平台重新生成。旧密钥删掉,新密钥妥善保存。API 密钥相当于你的钱包钥匙,谁拿到都能用你的额度调接口。


一份可以直接复制的完整配置

以下是经过验证的 CCX 标准配置。把 apiKeys 里的值换成你自己的密钥,其他字段直接用:

{
  "upstream": [],
  "responsesUpstream": [
    {
      "baseUrl": "https://api.deepseek.com",
      "apiKeys": [
        "sk-你的DeepSeek密钥"
      ],
      "serviceType": "openai",
      "name": "deepseek-o3mlh5",
      "normalizeNonstandardChatRoles": true,
      "priority": 2,
      "status": "suspended",
      "autoBlacklistBalance": true,
      "normalizeMetadataUserId": true
    },
    {
      "baseUrl": "https://token-plan-cn.xiaomimimo.com/v1",
      "apiKeys": [
        "tp-你的小米Mimo密钥"
      ],
      "serviceType": "openai",
      "name": "xiaomimimo-o1c0ll",
      "modelMapping": {
        "codex": "mimo-v2.5-pro",
        "gpt": "mimo-v2.5-pro",
        "gpt-5": "mimo-v2.5-pro",
        "gpt-5.2": "mimo-v2.5-pro",
        "gpt-5.2-codex": "mimo-v2.5-pro",
        "gpt-5.3-codex": "mimo-v2.5-pro",
        "gpt-5.4": "mimo-v2.5-pro",
        "gpt-5.5": "mimo-v2.5-pro"
      },
      "reasoningParamStyle": "reasoning",
      "textVerbosity": "medium",
      "fastMode": true,
      "normalizeNonstandardChatRoles": true,
      "codexToolCompat": false,
      "priority": 1,
      "status": "active",
      "autoBlacklistBalance": true,
      "normalizeMetadataUserId": true,
      "stripParams": [
        "stream_options",
        "tools",
        "function_call",
        "max_tokens",
        "presence_penalty",
        "frequency_penalty",
        "top_p",
        "n",
        "stop",
        "logprobs",
        "echo",
        "store",
        "output_config"
      ],
      "maxConcurrent": 2,
      "qps": 1,
      "retryCount": 1,
      "retryDelay": 2000,
      "disableTools": true
    }
  ],
  "geminiUpstream": [],
  "fuzzyModeEnabled": true,
  "stripBillingHeader": true
}

需要改的地方:

  • apiKeys 里的 sk-你的DeepSeek密钥tp-你的小米Mimo密钥 换成你自己的
  • DeepSeek 通道的 statussuspended(暂停),Mimo 是 active(激活)。平时用 Mimo,Mimo 挂了再切 DeepSeek
  • modelMapping 里的映射关系按你实际需要调整

验证:确认一切正常

配置改好后,按顺序做这三步验证。

第一步:看启动日志

启动 CCX 后,控制台应该输出类似这样的信息:

INFO[0000] CCX started successfully on port 3000
INFO[0000] Loaded 2 upstream providers
INFO[0000] Active provider: xiaomimimo-o1c0ll

如果没看到这些,回头看第三步的排查。

第二步:检查模型列表

浏览器打开 http://localhost:3000/v1/models,确认页面返回的 JSON 里包含 mimo-v2.5-pro

第三步:实际调用

curl.exe -X POST http://localhost:3000/v1/chat/completions -H "Content-Type: application/json" -d "{\"model\": \"gpt-5.4\", \"messages\": [{\"role\": \"user\", \"content\": \"你好\"}]}"

注意这里 model 填的是 gpt-5.4(Codex 会用这个名字发请求),CCX 会根据 modelMapping 转成 mimo-v2.5-pro 发给小米。如果返回了正常的对话响应,配置就对了。


你还会遇到的几个坑

切换模型要开新对话

在 Codex 里切模型后,旧对话还是走老模型。这是 Codex 的会话机制——每轮对话锁定创建时的模型名。切完模型记得开新对话,别在旧对话里继续聊。

偶发 500

如果大部分请求正常但偶尔报 500,大概率是并发限流没卡住。把 maxConcurrent 降到 1,qps 降到 0.5,进一步压低请求频率。

ccswitch 切了但 CCX 没动

ccswitch 改的是 Codex 配置文件(~/.codex/config.toml)里的 model 字段——这是一个模型名称字符串。CCX 路由看的是自己的通道 priority——这是一个数字优先级。两者不在一个维度上,ccswitch 切了模型名,CCX 的路由优先级纹丝不动。

这个问题的根因和解决思路,我在另一篇文章里详细写过:ccswitch 说切了,ccx 却没动——我给 Codex 国产模型切换造了一座桥


标准排障清单

遇到问题时,按这个表从上往下排查:

问题现象 解决方案
所有请求返回 500 1. 确认 stripParams 配置完整;2. 检查 API 密钥是否正确;3. 用 curl 直接测试 API 可用性
CCX 启动后秒退 1. JSON 不能有注释;2. 去 jsonlint.com 校验语法;3. 检查文件编码为 UTF-8
端口 3000 被占用 执行 netstat -ano | findstr ":3000" 找到 PID,在任务管理器中结束该进程
提示"API 密钥无效" 重新生成密钥,确认配置文件中密钥没有多余空格或换行
偶发 500 maxConcurrent 改为 1,qps 改为 0.5
ccswitch 切换不生效 参考 CCX-Bridge 文章

紧急备用方案:切到 DeepSeek

如果小米 API 彻底不可用,临时切到 DeepSeek 救急:

  1. 把 DeepSeek 通道的 status"suspended" 改为 "active"
  2. 把 Mimo 的 priority 改为 2,DeepSeek 的 priority 改为 1
  3. 重启 CCX

改完后所有请求自动走 DeepSeek,Mimo 变成备用。


排查这类问题的核心思路就一条:先确认问题在哪一层。是 API 本身挂了?是 CCX 转发的参数不对?还是配置文件语法有错?逐层排除,比盲目改配置有效得多。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐