如果你最近在用 Codex CLI 干活大概率撞见过这个画面网络稍微抖一下终端就卡在Reconnecting to service...的状态里光标一直转敲什么都没反应运气差点的重启两三次还是卡。我一开始也以为是密钥过期、会话文件坏了折腾了两三天最后才发现根子压根不在密钥上——是客户端那个近乎苛刻的请求超时和重试策略在互相打架把一个正常的慢响应放大成了长时间假死。今天这篇不聊概念就写我怎么从日志里把这条路径摸出来以及最终落在config.toml里的那一行配置。这篇东西适合所有用 Codex 做日常开发、尤其习惯在远程开发机或长任务场景下跑 Codex 的人。你不需要懂 Rust也不需要会改源码只要会看日志、会编辑一个配置文件五分钟后就能自己复现一遍完整的排查过程。1. 先搞清楚重连卡半天到底卡在哪1.1 复现症状卡住的时候网络其实没有断我最早遇到这个问题的场景很典型办公网在下午高峰期偶尔抖动无线信号也不稳定Codex 在处理一个比较大的重构任务跑到一半终端突然不再输出新内容左下角出现Reconnecting之类的状态提示。第一次遇到时我以为只是网断了等它自己恢复就好结果等了十来分钟还是那个转圈状态。后来我换了有线网络、重启了 Codex、重新登录了好几次问题照样出现。最诡异的一点是系统网络明明正常浏览器开网页、拉代码都没问题唯独 Codex 一直在重连。这时候我才意识到它卡住不是因为物理断网而是客户端自己进入了一个反复重试的循环。这个循环一旦启动界面只显示一个重连中没有进度、没有日志、没有超时倒计时用户能做的只有干等。注意它的触发时机通常不是刚开始对话就卡而是发生在某个请求已经发出、且长时间没有返回的时候。换句话说Codex 不是在连不上而是在等一个响应但迟迟等不到。1.2 原因一请求超时太短重试退避变成了无限循环Codex CLI 调用模型服务走的是 HTTP 请求而大模型推理本身就不是一个秒回的操作。你把一段很长的上下文丢给它它需要先消化所有这些内容再开始生成这个阶段完全没有任何输出返回。第一次 token 返回之前客户端只能干等。问题在于客户端对等多久算超时的判断非常保守。我这边实际观察到的场景是当某个请求的处理时间超过客户端内部设定的等待窗口它就会判定这次请求失败然后自动进入重连流程——不是直接报错让你看到而是先等一个退避间隔再重新发起连接。如果第二次还是超时退避间隔会翻倍1 秒、2 秒、4 秒、8 秒……连试几轮之后单次等待就已经到了分钟级。你从用户界面看就是那个转圈状态一直转但从客户端内部看它其实是在一次次休眠和重试之间来回切换。生活里找个类比的话就像你在餐厅等位服务员告诉你还有 5 分钟结果每 5 分钟她又说一次还有 5 分钟你走也不是、留也不是坐那儿干耗着。1.3 原因二认证会话过期后刷新流程在非交互环境下卡死第二种常见原因和网络无关纯粹是认证问题。Codex 的登录态保存在~/.codex/auth.json这类文件里access token 是有有效期的过期之后客户端会尝试用 refresh token 去换新的。换 token 的过程中如果服务端响应慢或者当前环境不能弹出交互式确认比如你是在 SSH 会话里跑的 Codex客户端就会卡在等待登录确认的状态上。这种卡死有个特征你切到别的终端看进程Codex 还活着CPU 占用也不高但它就是不再处理任何请求。检查认证文件也看不出明显问题因为文件存在、权限也正常纯粹是刷新流程没有一个可行的出口。提示遇到重连卡顿先判断是请求超时还是认证过期。最简单的区分方式就是看日志里重试的间隔——如果是 1 秒、2 秒、4 秒这样翻倍增长基本是请求超时如果是反复出现refreshing token之类字样但没有任何进展基本是认证刷新流程被卡住。2. 一行配置的落点看懂 Codex 的配置文件2.1 配置入口与基本结构Codex CLI 的配置入口是用户目录下的~/.codex/config.toml如果你设置过CODEX_HOME环境变量那么路径会跟着变。这个配置文件是 TOML 格式和 Python 的pyproject.toml、Rust 的Cargo.toml是一路货色结构上就是区块加键值对。一个最基本的配置文件长这样model gpt-4.1 # 指定默认模型 model_provider openai # 指定默认供应商 approval_policy onRequest # 权限审批策略model决定默认用哪个模型model_provider指定走哪套接口配置approval_policy控制 Codex 在执行命令前需不需要征求你同意。日常用的话前三行一般不用动真正容易出问题的反而是后面那些关于超时、重试、会话恢复的细节配置。在动手改之前我强烈建议先把原始文件备份一份cp ~/.codex/config.toml ~/.codex/config.toml.bak这样后面不管怎么折腾一条命令就能还原不至于改坏了之后连 CLI 都起不来。2.2 最关键的一行把请求超时从秒级调到分钟级我最终解决问题用的配置就是在配置文件里给当前使用的模型供应商增加一个请求超时设置。不同小版本的 Codex 对超时配置的命名不完全一致我这边验证过的写法是在[model_providers.xxx]段里加一行[model_providers.openai] timeout_ms 600000600000的单位是毫秒换算过来就是 10 分钟。为什么选 10 分钟先看一个典型的大请求耗时假设上下文里有几万 token模型需要读完这些内容再开始推理普遍需要 30 秒到 2 分钟才能返回第一个 token如果后面再叠加工具调用、多轮生成整个请求走完 3 到 5 分钟非常正常。Codex 客户端默认的等待窗口我实测下来偏小经常在 60 秒上下就触发超时判定。你想想一个明明需要 3 分钟的请求客户端 60 秒就判定它失败了然后开始退避重试这不光解决不了问题反而把一次正常请求拆成了好几轮失败—等待—重试的死循环。把超时调到 10 分钟等于告诉客户端别急给它点时间它不是在装死是真的在算。注意这个字段名在不同版本里可能有差异。如果你的 Codex 启动时提示unknown field说明当前版本不认这个写法这时候先看看codex --version的输出再根据错误提示去掉或调整字段名。配置文件里少一行配置最多是不生效但多一个版本不认识的字段可能会导致整个配置文件加载失败。2.3 配套项别让重试变成雪上加霜光调大超时还不够我顺手把重试次数也调低了。原因很简单退避重试机制本身是好东西但它在大模型请求本来就慢的场景下帮不上忙反而会把问题放大。本来只需要等一次 3 分钟的请求结果因为超时判得太早变成等 60 秒失败、等 2 秒重试、再等 60 秒失败、等 4 秒重试……这种无限循环。我当时在配置顶层加了一行request_max_retries 1意思是请求失败后最多再重试一次不要陷入不断翻倍等待的深渊。这一项配合 10 分钟超时效果立竿见影大多数情况下第一次请求就能正常走完根本轮不到重试万一真的失败也能快速报错让我知道是模型服务端的问题而不是在终端前干等。还有一个可选项是启动超时如果你发现 Codex 启动阶段也经常卡很久可以在配置里加上startup_timeout 300单位是秒限制启动阶段的等待时间。这个字段不是每个版本都有没有的话直接忽略就行不影响其他配置生效。2.4 不想改文件环境变量一样能解决问题如果你不想动配置文件或者你是在 CI/CD 这种临时环境里跑 Codex环境变量是更轻量的选择。把 API 密钥通过环境变量注入避免走交互式登录流程这类问题也能绕开一大部分。比如配置文件里对应供应商的密钥字段用的是env_key那你可以这样指定export MY_PROVIDER_API_KEY你的密钥这样 Codex 启动时会直接从这个环境变量读取密钥不会去走 token 刷新那套流程。至于超时相关的环境变量不同构建的 Codex 命名不统一我建议先用codex --help看一眼当前版本支持哪些变量。如果你不想折腾直接用第一节说的配置文件方案就行它适用于绝大多数场景。3. 实操记录从卡死到恢复的三步排查3.1 第一步打开日志定位触发点很多人在遇到重连卡顿的时候习惯直接去翻配置文件或者干脆重装但我建议先开日志。Codex 底层是 Rust 写的支持通过RUST_LOG环境变量控制日志输出级别。启动命令就是RUST_LOGcodextrace codex然后复现一次刚才卡住的场景切到另一个终端看日志输出。重点观察两个地方一是是否存在retrying或者backoff之类的关键字二是每次重试之间的时间间隔。如果间隔呈现出 1 秒、2 秒、4 秒这种翻倍规律那就实锤了——客户端一直在退避重试而不是在真正尝试连网。我当时截取到的日志大概是这种感觉[codex] request failed after 60s: timeout [codex] retrying in 2s... [codex] request failed after 60s: timeout [codex] retrying in 4s... [codex] request failed after 60s: timeout [codex] retrying in 8s...看到这段日志的时候我就明白了它卡住期间根本没有在请求服务端而是自个儿在数秒。你以为它在重连其实它在睡觉。提示RUST_LOG的日志级别可以按模块细化比如只想看网络相关的日志可以试试RUST_LOGcodexdebug或者RUST_LOGcodexinfo。日志级别越高输出越详细但也越刷屏排查时建议先用debug不够再看trace。3.2 第二步备份配置安全修改定位到问题之后修改就很简单了。先把原始配置备份cp ~/.codex/config.toml ~/.codex/config.toml.bak然后编辑配置vim ~/.codex/config.toml在文件合适的位置加入超时配置和重试次数配置。以我的环境为例最终生效的配置长这样model gpt-4.1 model_provider openai [model_providers.openai] timeout_ms 600000 request_max_retries 1这里有个小细节在不同的版本里request_max_retries有些放在顶层有些放在指定的 provider 段下面。如果你加了之后启动报错就根据错误提示调整位置如果完全不报错但也不生效多半是字段名不对查一下当前版本的配置说明再改。3.3 第三步复测确认一行配置真的生效改完配置后重启 Codex用之前最容易卡住的同一个任务做复测。我当时做了一个简单的对比同样是一个长上下文重构任务场景修复前修复后首次响应耗时约 2 分钟约 2 分钟客户端是否触发超时是否从开始到结束总耗时超过 15 分钟多次重连约 2 分半全程无中断界面状态Reconnecting转圈正常输出修复前总耗时 15 分钟以上其中绝大部分都耗在了退避重试上真正的模型计算时间只有那 2 分钟修复后整个流程一口气跑完没有再出现Reconnecting状态。这就是流程对不上节奏导致的假死——不是模型慢了是客户端没耐心等。4. 改了配置之后还会遇到哪些坑4.1 改了配置还是卡先看看上下文是不是撑爆了有一次我改了超时配置之后某个任务还是卡了很久。后来一查根本不是客户端超时的问题而是我一次性在 Codex 里引用了太多文件。上下文越长模型需要处理的内容越多首次响应时间自然就越长。哪怕我把超时调到了 10 分钟如果一个请求本身就需要 15 分钟那客户端还是会判定超时。这种情况的解决办法不是继续调大超时而是精简输入少引用几个无关文件把大任务拆成几个小任务分开做。Codex 这类工具和搜索引擎不一样不是输入越多越好输入越精炼响应越快也越不容易触发重连机制。4.2 不卡了但错误响应变慢超时要和重试配合着调把超时调到 10 分钟之后我发现一个新的问题当模型服务端真的出故障时Codex 要等满 10 分钟才会报错这个故障响应速度就太慢了。解决办法是让超时和重试次数配合起来不要单独拉一个。我最终采用的组合是请求超时 10 分钟重试次数只留 1 次。这样正常请求有足够时间跑完真正出问题时也不会在故障里反复横跳太久。你还可以在启动 Codex 的终端外面套一层timeout命令给整个会话设一个硬性上限防止极端情况下进程真的挂死timeout 3600 codex这样即使 Codex 内部配置出了问题最多 1 小时后也会被强制结束不会真的卡半天。4.3 配置不生效先检查路径再检查版本如果你按上面的方法改完配置发现重启后完全没有变化大概率是下面两种原因之一。一是配置路径不对。如果你设置了CODEX_HOME环境变量Codex 会从这个变量指向的目录读取配置而不是从默认的~/.codex读。你先执行echo $CODEX_HOME看看是不是指向了其他位置如果是就把配置复制过去或者把环境变量清掉恢复默认路径。二是字段名版本不支持。Codex 的版本更新比较快配置字段时有调整。你可以用codex --version看版本号然后在启动时留意有没有关于配置解析的错误输出。遇到不认识的字段安全做法是先去掉只保留确定生效的那几行配置。毕竟我们真正需要的可能就那一行超时配置其他都是锦上添花。我在实际使用中还有一个习惯遇到重连卡顿先看日志里到底有没有请求在发再决定改什么。很多时候你以为的卡死其实是客户端在退避等待这时候去怀疑密钥、删掉重装都不对症。先把上面那两个配置改好大多数卡半天的场景都能直接消失。希望这篇排障记录能帮你少走两天弯路。
阅读完成 · 觉得有帮助?