Windows 下要把 Codex CLI 和 OpenClaw 装在同一台机器上,我是真没想到能把四个错误串成一条龙来排查。先是 codex 命令都敲不动,接着 OpenClaw 网关进程起不来,再往后 Codex 的 endpoint /responses 接口直接报错,最后模型通道也彻底断掉。如果你也在 Windows 上折腾 Codex CLI、部署 OpenClaw 网关,或者正被 WSL 状态、Node 路径、端口占用这类问题反复折磨,这篇实录应该能帮你省下大半天时间。整个过程涉及命令行工具排查、网关服务检查、模型通道恢复三个层面,我会把每一条命令的用途、每一步改动的理由都讲清楚,照着走基本不会迷路。
1. 故障全景与排查思路设计
1.1 这套组合为什么会连环出问题
Codex CLI 是 OpenAI 推出的命令行编程助手,核心工作方式是在终端里读取你的问题,然后把请求发到模型服务端点,再把返回的内容渲染成操作建议或代码补丁。它本质上是一个 Node.js 全局包,靠 npm 安装,运行时依赖认证信息、配置文件、模型端点指向,还依赖 Node 运行时和 PATH 环境变量。
OpenClaw 则是一个开源的 AI 助手调度网关,它做的事情更接近“总机”:把各类消息通道(比如 Teams、Obsidian 笔记、本地终端)收到的指令,统一转发到不同的大模型后端去处理,再把处理结果送回原通道。它同样是 Node.js 生态下的项目,有自己的配置文件、进程模型和端口监听逻辑。
这两个东西叠在同一台 Windows 机器上,问题就来了。它们共享 Node.js 运行时,共享 npm 全局目录,共享环境变量,甚至某些端口和本地转发链路也有重叠。Codex 启动失败,很可能导致 OpenClaw 里依赖 Codex 通道的模块一起挂掉;OpenClaw 网关起不来,又会反过来让 Codex 的模型端点请求无路可走。这就是“连环故障”的本质:不是四个独立的问题,而是一条依赖链上的四个环节依次断裂。
1.2 排查前的环境快照与故障清单
在动手之前,我先把当前环境摸了一遍底。这样做的好处是避免改了半天才发现问题根本不在你怀疑的那一层。我当时记录的要点如下:
- 操作系统:Windows 11 专业版,版本号比较新
- Node.js:一开始是 v18.16.0,后来为了兼容升级到了 v20.x
- npm 全局目录:默认的 %APPDATA%\npm
- Codex CLI:通过 npm 全局安装,最新版
- OpenClaw:克隆源码到本地后 npm install 方式部署
- WSL2:已安装,但状态一直不太对,后面发现这是模型恢复的关键
- 远程模型服务:本地开发环境里配置了一个自建的模型端点
故障现象按照时间顺序记录如下:
- 在 PowerShell 里敲 codex,提示找不到命令,只有一堆红色的报错
- 强行找到 codex.cmd 后双击运行,窗口闪退,什么信息都没留下
- 好不容易让 codex 能启动了,又报出类似“unable to locate the codex cli binary or required runtime components”的错误
- 接着 OpenClaw 启动时直接失败,日志里提到本地转发失败,Codex endpoint /responses 返回异常
- 最后想恢复模型通道,OpenClaw 又提示“无法安全验证 WSL2 环境,请在 PowerShell 中运行 wsl --status”
这一串现象看起来毫无头绪,但拆开看就清晰了:第 1 到第 3 个问题是“命令行启动层”,第 4 个是“网关连接层”,第 5 个是“模型运行环境层”。所以排查顺序就定为:先把命令行跑起来,再修网关链路,最后恢复模型通道。别倒着来,否则工具都没法启动,后面全白搭。
2. CLI 先死:Codex 命令行启动失败排查
2.1 “codex 找不到命令”的三种典型原因
先处理第一个阻塞点:在 PowerShell 里执行 codex --version,直接返回“codex 不是内部或外部命令,也不是可运行的程序或批处理文件”。这个错误在 Windows 上太经典了,九成情况下是下面三种原因之一。
第一种是 PATH 环境变量里根本没有 npm 全局目录。npm 安装全局包时会把可执行文件放到 %APPDATA%\npm 下,如果这个路径没加到系统 PATH 里,PowerShell 自然找不到。验证方法很简单,先执行 echo $env:PATH 看输出里有没有 C:\Users\你的用户名\AppData\Roaming\npm 这一项,没有就加上。
第二种是 npm 全局安装的 prefix 被改过,导致全局包装到了奇怪的位置。你可以执行 npm config get prefix 看看输出路径是不是默认值,如果指向了某个自定义目录,那 PATH 里对应的也要改成那个目录,或者干脆把 prefix 改回来。
第三种是用户 PATH 和系统 PATH 重复设置,但顺序有问题。Windows 系统里用户变量和系统变量是拼接生效的,如果系统 PATH 里的内容覆盖了用户 PATH 的优先级,也会出现明明装了却找不到的情况。最简单的方法是把 %APPDATA%\npm 放到用户 PATH 的最前面。
我当时的解决过程是:先在 PowerShell 里执行 Get-Command codex 看是否真的找不到,再执行 where.exe codex 看 Windows 命令搜索器能否找到,结果两个都返回空。随后检查 $env:PATH,发现 %APPDATA%\npm 确实不在里面。于是通过“系统属性 -> 环境变量 -> 用户变量 -> Path -> 新建”把 C:\Users<用户名>\AppData\Roaming\npm 加了进去,重启 PowerShell 后执行 codex --version,终于输出了版本号。
2.2 从“unable to locate the codex cli binary”看运行时依赖缺失
解决了 PATH 问题后,我以为万事大吉,结果 codex --version 带来的不是版本号,而是一条更具体的错误:
unable to locate the codex cli binary or required runtime components. check your installation.
这个报错的意思很直白:命令能找到了,但 Codex 真正的入口程序或它依赖的运行时组件丢了。在 Windows 上,npm 全局包会生成一个 codex.cmd 脚本放在 npm 目录里,脚本内部会去调用 node_modules 里的实际 JS 文件。如果 npm 安装过程中断、磁盘空间不足、杀毒软件拦截,或者 Node.js 版本不兼容,都会导致运行时文件不完整。
我先检查了 npm 全局包里有没有 codex 目录:npm ls -g --depth=0,确认包是存在的。接着看 Node.js 版本是否满足要求:node -v 和 npm -v。Codex CLI 对 Node.js 版本有要求,太老的版本会跳过部分依赖的安装,太新的版本偶尔也会遇到原生模块编译失败。我当时用的是 Node v18.16.0,个别依赖提示不支持,干脆直接升级到 v20.x,然后重新执行 npm install -g @openai/codex。
这里有个 Windows 特有的细节:重装全局包后,旧的 codex.cmd 可能还在,但指向的 node_modules 内容已经被更新,这时候需要确认 cmd 文件里的路径是否正确。可以直接用记事本打开 C:\Users<用户名>\AppData\Roaming\npm\codex.cmd 看一眼,正常情况下里面引用的是 node_modules@openai\codex 下的入口文件。如果路径不对,就手动删掉整个 npm 目录下的 codex 相关文件,再重新装一遍。重装完成后,建议顺手执行 npm cache verify 清一遍缓存,避免后续安装别的东西时又遇到损坏包。
2.3 Windows 特有坑:路径空白、脚本闪退与执行策略
Codex 命令行能正常输出版本号之后,我准备正式使用,结果在 PowerShell 里执行 codex 交互命令,出现了两种新情况。第一次是窗口停顿几秒后直接闪退,跟之前双击 .cmd 文件一样,完全看不到错误信息。第二次是在 VS Code 的终端里执行,提示当前脚本运行被禁用了。
闪退的本质原因是 .cmd 文件里执行 Node.js 脚本时报错,但在双击或窗口自动关闭的情况下错误信息一闪而过。解决方法是不要在窗口里直接双击,而是打开 PowerShell 后手动执行 cmd /c codex 或者直接 powershell -NoExit -Command "& codex",强制窗口不要关。我最后是在普通 PowerShell 里用 cmd /c codex 2>&1 把错误输出重定向出来,才看到真正的报错是内部引用了一个不存在的路径,原因是 Node.js 装在 C:\Program Files 下,路径里有空格,而某个依赖没有正确加引号。
执行策略是另一个高频坑。PowerShell 默认的 Restricted 策略不允许执行任何脚本文件,codex.cmd 作为脚本自然也会被拦。检查当前策略用 Get-ExecutionPolicy,如果是 Restricted,就改成 RemoteSigned:Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser。注意这一步只需要对当前用户生效,不要动系统级策略,否则安全风险太大。
还有一个容易被忽略的细节:如果 Windows 系统用户名是中文或者包含空格,某些 Node.js 库在解析路径时会出问题。最稳妥的做法是检查一下系统临时目录 TEMP 和 TMP 这两个环境变量是否指向了带中文的路径,如果指向了,就把它们改成 C:\Windows\Temp 或者新建一个纯英文路径,然后重启终端。我当时就是在这个地方卡了快半小时,改了临时目录后一切流畅。
到这一步,codex 命令终于能正常启动了。但下一个问题紧随而至:OpenClaw 网关在启动时挂掉,日志里直接指向 Codex 的模型端点。
3. 网关层连环故障:Codex endpoint 与转发链路恢复
3.1 Codex endpoint /responses 异常的本质
OpenClaw 启动失败的日志里有一行非常关键,大致意思是:本地转发模块在处理 Codex endpoint /responses 请求时失败。这里需要先解释一个背景:Codex CLI 向模型服务发送请求,通常不是直接访问外部地址,而是先经过本机的一个转发链路,把请求重新包装、指向你在配置里指定的模型提供方。这个“本地转发”一旦配置不对,就会出现 endpoint 请求发不出去或者返回异常。
我在这一点上踩过的坑是:配置文件里同时存在两套端点指向。一遍是 Codex 自己的 config.toml 里写的模型服务地址,另一遍是 OpenClaw 里配置的模型路由规则。两个地址不一致时,OpenClaw 把请求转到 Codex 指定的地址,而 Codex 又按自己配置的地址向外发,两边互相不认,最终表现出来就是 /responses 接口要么超时要么返回 4xx 状态码。
排查这个问题的顺序应该从内向外:先确认 Codex 侧配置有没有问题,再确认 OpenClaw 侧路由有没有问题,最后确认模型服务本身是否存活。我当时的做法是先看 Codex 的配置文件,Windows 下一般位于 C:\Users<用户名>.codex\config.toml,打开后检查 model_provider、model 和 endpoint 三个字段是否指向同一个服务地址。同时检查认证文件 auth.json 是否存在、内容是否完整,认证信息缺失会导致 endpoint 返回 401,日志里就表现为转发失败。
3.2 OpenClaw 网关起不来的排查姿势
OpenClaw 作为 Node.js 项目,启动方式一般是先安装依赖,再运行启动命令。我在 Windows 下遇到的情况是:npm install 顺利完成,没有任何红字,但是执行启动命令后,进程立刻退出,控制台只打出一行日志就没了。
第一步一定是看日志文件,别猜。OpenClaw 的日志通常放在项目目录下的 logs 文件夹,或者用户目录下的 .openclaw 目录里。打开日志会发现两种情况:一种是 EADDRINUSE,也就是端口被占用;另一种是 ENOENT,也就是某个配置文件路径不存在。我当时遇到的是端口占用:OpenClaw 默认监听的端口被另一个后台进程占着。
这里就用到 Windows 端口排查三板斧。第一板斧:netstat -ano | findstr :端口号,看是谁占了这个端口,最后一列是 PID。第二板斧:tasklist /FI "PID eq 进程号",看这个 PID 对应哪个程序。第三板斧:如果确认是无用的僵尸进程,执行 taskkill /PID 进程号 /F 强杀。注意千万别杀错了,我就曾经把本机一个数据库服务当成占用端口的东西直接杀了,结果后面模型那块又出幺蛾子。
端口清干净之后,OpenClaw 能启动,但日志里又报了一个新错误:某个内部路由初始化失败。这个错误看起来复杂,实际是配置文件的格式校验没过。YAML 或 TOML 这类配置文件里只要有一个 Tab 键写错了位置,或者中文字段名被当作键值解析,整个文件就会失效。我的建议是:用 VS Code 打开配置文件,右下角确认格式是 TOML 对应 .toml、YAML 对应 .yaml,千万别用 .txt 编辑器乱改。改完之后可以先用代码库自带的配置校验命令跑一遍,能过校验再启动服务。
3.3 网关配置里最典型的三个坑
网关服务能起来,但不代表链路通了。我在恢复网关的过程中,前前后后掉进过三个典型坑,这三个坑在 Windows 环境下的概率非常高,值得单独列出来。
第一个是监听地址绑定错误。OpenClaw 配置文件里如果监听地址写的是 127.0.0.1,那么只有本机能访问;如果写成 0.0.0.0,局域网里其他机器也能访问,但 Windows 防火墙会弹窗拦截。两种写法各有用途,但如果你在配置里把两者混着填,比如页面写 127.0.0.1,内部路由写 0.0.0.0,就会出现外部请求进不来、内部请求出不去的诡异现象。排查方法是打开一下监听端口,看实际监听地址是本地还是全部接口。
第二个是防火墙拦截。Windows Defender 防火墙默认在首次监听时弹窗问你是否允许通信,很多人随手点了取消,后面服务就再也无法被其他进程访问。解决方式是到“控制面板 -> Windows Defender 防火墙 -> 高级设置 -> 入站规则”手动新增一条允许规则,把对应端口和程序放行。
第三个是环境变量差异。PowerShell 和 CMD 读环境变量的语法完全不同,PowerShell 是 $env:KEY,CMD 是 %KEY%。如果你在配置文件里写死了某个环境变量名,而它实际不存在于系统环境中,Node.js 会静默采用空字符串,导致请求地址变成不完整的 URL。我当时就是这个原因,请求发到了空的 host 上,日志里显示连接被拒绝,查了一个多小时才发现是某个环境变量没设。
3.4 网关和本地端点连通性验证步骤
网关这类服务,验证起来要分层,不要只盯着启动成功就算完。我的验证顺序是这样的:
第一层,验证本地端点在不在监听:curl http://localhost:端口号/health 或者 curl http://127.0.0.1:端口号/。如果返回 JSON 格式的健康状态,说明服务已经在跑。
第二层,验证 Codex endpoint /responses 是否可达。这个接口是动态的,直接 GET 大概率返回 404 或 405,但只要能收到状态码而不是连接超时,就说明网关层已经能把请求传到位。我当时用 curl -X POST http://localhost:端口号/responses -H "Content-Type: application/json" -d "{}" 试了一下,返回 400 表示参数校验没过,但至少链路是通的。
第三层,验证模型端点的真实状态。Codex 和 OpenClaw 都指向同一个模型服务,那么模型服务必须自身健康。我这边是本地起了一个模型服务,监听 11434 之类端口,用 curl http://localhost:11434/api/tags 看看能不能列出模型列表,能列出说明模型层正常。
到这一步,“网关与转发链路”算是彻底打通了。剩下的最后一环是模型通道恢复,也就是把模型成功挂到 OpenClaw 上,让它能把请求分发到本地模型去处理。
4. 模型恢复与 WSL2 环境校验
4.1 OpenClaw 报“无法安全验证 WSL2 环境”的真相
OpenClaw 走到恢复模型这一步时,突然又拦了一道,错误提示大概是“无法安全验证 WSL2 环境,请在 PowerShell 中运行 wsl --status”。这个提示本身不是说模型坏了,而是 OpenClaw 里面某些功能依赖 WSL2 来调用 Linux 下的子进程或脚本,它启动时会先检查 WSL 环境是否正常。
检查 WSL 状态的标准动作是:在 PowerShell 里执行 wsl --status,然后执行 wsl --version 看版本号,再执行 wsl -l -v 看当前发行版是 V1 还是 V2。如果 wsl --status 提示“尚未安装”或者“默认版本为 1”,那就需要先设置默认版本:wsl --set-default-version 2,再更新 WSL 内核:wsl --update。更新之后重新启动终端,让环境变量重新加载。
这里有一个 Windows 上常见的细节:WSL 未初始化时,PowerShell 里执行 wsl --status 可能没有任何输出,容易误判为命令不存在。实际应该执行 wsl --help 确认命令能运行,再依次执行上述检查项。如果系统里装了多个 WSL 发行版,还得注意默认发行版是不是你配置模型时用的那一个,可以用 wsl --set-default <发行版名称> 指定。
我当时把 WSL2 默认版本设置好、内核更新到最新后,OpenClaw 里的“无法安全验证”报错就消失了。这个步骤看起来和模型恢复没关系,但实际它是模型服务能否被 OpenClaw 正常调用的前置条件,跳过它的话,OpenClaw 在启动模型路由时依然会失败。
4.2 把本地模型接入 OpenClaw(qwen2.5-3b 参考流程)
WSL 环境恢复正常后,接着把模型直接挂到 OpenClaw 上。我当时的模型是 qwen2.5-3b,它通过一个本地推理服务暴露 API,监听 11434 端口,兼容 OpenAI 风格的 /v1/chat/completions 接口。OpenClaw 基本都支持配置兼容 OpenAI 接口的模型服务,所以流程比较统一。
先确认模型服务是通的:curl http://localhost:11434/api/tags,返回的列表里能看到 qwen2.5-3b 这个名字,说明模型已经加载。如果这里返回空列表,需要先把模型拉下来,通常用拉取命令把模型下载到本地。
然后在 OpenClaw 的配置里增加一个模型提供方。核心配置项包括:模型服务的基础地址、API 认证方式(一般是空或无认证)、默认模型名。配置写完保存后,重启 OpenClaw 让新配置生效。我重启后特意在 OpenClaw 提供的一个调试命令里发起了一条测试消息,看到它返回了一个正常回答,说明模型通道已经恢复。
这条链路完全跑通的标志是:Codex CLI 发起的请求,经过 OpenClaw 网关,转发到本地模型服务,处理的最终结果能回到 Codex 的界面里。如果中途任何一跳断了,错误不一定直接显示在 Codex 里,而是先出现在 OpenClaw 的日志里,所以看日志的习惯一定要养成。
4.3 模型恢复后的连通性验证清单
整理一份验证清单,每一条都有明确的命令和预期输出,照着跑一遍就知道整个系统是否健康。
- 验证 Codex CLI 可执行:codex --version,预期返回版本号
- 验证 OpenClaw 进程在监听:curl http://localhost:OpenClaw端口/health,预期返回 JSON 健康信息
- 验证模型服务在监听:curl http://localhost:模型服务端口/api/tags,预期返回模型列表
- 验证 WSL2 状态:wsl --status,预期显示默认版本为 2,内核正常
- 验证端到端链路:在 OpenClaw 里发一条测试消息给 qwen2.5-3b,预期返回语义完整的回复
这份清单是我整个排查过程中最底层也最管用的工具。每次改完配置、重启完服务,不用凭感觉去试,直接用命令做检查,哪里断了就去修哪里。
5. 易错点速查与 Windows 实战经验
5.1 我已经替你踩过的坑
这一节是把前面所有教训压缩成清单,每一条都是真实踩过坑的经验,按优先级排序。
Windows 环境变量修改后,必须开新的终端窗口,别在旧窗口里继续操作,否则读到的还是旧值。这个坑出现频率极高,几乎每次改 PATH 都会有人中招。新窗口再执行 echo $env:PATH 确认。
Node.js 全局包安装完命令找不到,先查 %APPDATA%\npm 是否在 PATH 里,再查 npm config get prefix 是否被改动过,别一上来就重装系统或换 Node 版本。
OpenClaw 启动失败优先看日志,日志文件路径通常在项目目录的 logs 文件夹或者用户目录下的 .openclaw 目录里,不要在控制台输出上反复猜。
端口被占用时,用 netstat -ano | findstr :端口号 锁定 PID,再用 tasklist 查进程名,确认无误再 taskkill。杀错进程的后果往往比端口冲突更严重。
配置文件里出现诡异行为时,可能是文件格式不对。YAML 配置文件用 Tab 缩进必炸,TOML 文件用全角引号必炸,改配置前先确认编码格式是 UTF-8。
PowerShell 脚本执行策略 Restricted 会拦截大量命令行工具,先执行 Get-ExecutionPolicy 检查,再按需用 Set-ExecutionPolicy 调整到当前用户级别,别全局放开。
WSL2 报错优先执行 wsl --update 和 wsl --set-default-version 2,这两条命令能解决八成 WSL 环境异常问题。更新完记得重启终端。
5.2 排查命令速查表
| 目标 | 命令 | 说明 |
|---|---|---|
| 检查 PATH | echo $env:PATH | 查看当前终端读取到的路径列表 |
| 检查命令位置 | where.exe codex | 按 PATH 顺序搜索可执行文件 |
| 检查全局包 | npm ls -g --depth=0 | 列出全局安装的顶层包 |
| 检查 Node 版本 | node -v 和 npm -v | 确认运行环境版本 |
| 检查端口占用 | netstat -ano | findstr :端口号 | 查看哪个进程占用端口 |
| 查看进程名 | tasklist /FI "PID eq 进程号" | 根据 PID 查对应程序 |
| 强制结束进程 | taskkill /PID 进程号 /F | 关闭无用进程释放端口 |
| 检查 PowerShell 策略 | Get-ExecutionPolicy | 查看当前脚本允许级别 |
| 修改执行策略 | Set-ExecutionPolicy RemoteSigned -Scope CurrentUser | 允许本地脚本运行 |
| 检查 WSL 状态 | wsl --status | 查看 WSL 整体状态 |
| 更新 WSL | wsl --update | 更新 WSL 内核与组件 |
| 查看 WSL 发行版 | wsl -l -v | 列出所有发行版及版本标记 |
| 检查本地服务健康 | curl http://localhost:端口/health | 快速验证服务是否存活 |
| 检查模型服务 | curl http://localhost:模型端口/api/tags | 验证模型服务及模型列表 |
这些命令不复杂,但组合起来可以覆盖整个排查链路。我建议把它们存成一个备忘单,出问题的时候按顺序执行,比瞎猜效率高得多。
5.3 排障思路与个人经验
整套问题走完之后,我最大的感受是:Windows 下排障,最忌讳多人协作时各改各的却不留记录。我这次中间至少有两次进度回退,原因就是前面改过一个配置,后面忘了,重启服务后又变回旧状态。后来我强制自己在每改一处配置之后,把改动内容和验证结果写到一个临时文档里,才从混乱里走出来。
另外一个很有用的经验是:链路越靠底层,越要先恢复。命令行工具、环境变量、端口、进程、配置文件,这些东西是基础设施。它们不恢复,上层服务再折腾都是白费。你可以把它们想象成水管:只有主管道通了,末端的每一个水龙头才都有水。
最后再补充一个小技巧:Windows 下执行完一条命令后,如果输出一闪而过,可以在命令前加 cmd /k,比如 cmd /k codex --version,这样窗口会停在输出界面,方便截图或记录错误信息。我这次很多错误信息都是靠这种方式截下来的,不然根本没机会慢慢分析。
这套组合链路,现在在我机器上跑得很稳定。Codex CLI 能正常启动,OpenClaw 网关能把请求转发到 qwen2.5-3b,模型回答通过网关回到 Codex 交互界面,整个过程一气呵成。期间踩过的那一串连环坑,回头看其实没什么神秘可言:就是环境变量、端口、进程、WSL 状态这些老朋友们在捣乱。把这几个点一个个理顺,Windows 下跑这套组合完全可行。