Windows 已开启代理,Codex 为什么仍然回复慢?一次 WebSocket 超时排障记录
排查日期:2026 年 10 月 15—16 日,时间均为北京时间(UTC+8)。
本文记录 Windows 上使用 v2rayN 后,Codex 桌面端仍长时间等待回复的一次排障。处理办法在本次环境中验证有效,不代表所有版本、所有慢请求都由同一个问题导致。
本次问题最明显的特征是:浏览器可以正常使用 ChatGPT,桌面端却经常迟迟没有输出。检查日志后,发现其中一次请求在 WebSocket 上反复超时,重试 5 次才切换到 HTTP;随后很快开始回复。
最终采用的办法是:通过一个专用快捷方式启动应用,只为该应用及其子进程设置 HTTP_PROXY 和 HTTPS_PROXY。重新启动后,WebSocket 正常复用,没有再出现本轮连接重试和 HTTP 回退。
1. 问题是怎么被发现的
最初的判断来自使用体验:本地桌面端有时等待数分钟,而网页端体感更快。

图 1:另一段历史桌面端对话的截图,用于说明“等待很久”的现象。界面标注为 9 分 54 秒,下方聊天分析又使用了 6 分 45 秒的口径,两者不一致;本文不把这张图当作精确计时或 WebSocket 超时的原始证据。

图 2:网页端另一段对话显示“思考了 54 秒”。它与图 1 的问题、任务和计时口径不同,只说明使用体验上的差异,不能据此计算桌面端比网页端慢了多少倍。
排查时需要先分清三种时间:
| 指标 | 含义 | 本文如何使用 |
|---|---|---|
| 界面的“总用时” | 可能包含思考、查资料、执行工具和生成回复 | 作为现象记录,不直接归因 |
| 界面的“思考了多久” | 产品界面展示的思考耗时 | 不与另一任务的总用时直接比较 |
| 请求开始到首条助手消息的记录间隔 | 从会话中的 task_started 到首条助手消息记录 |
用于比较本次排查前后的首次回复等待 |
最后一项也不是严格的网络首字节时间(TTFB),更不是完整任务耗时。本文的 103.425 秒和 7.310 秒都采用这个会话记录口径。
2. 当时的运行环境
| 项目 | 本次实际检查结果 |
|---|---|
| 系统 | Windows 桌面环境 |
| 应用 | Windows 商店安装的 OpenAI.Codex,包版本 26.1007.9446.0 |
| 主程序 | 安装包内的 app/ChatGPT.exe |
| 模型设置 | gpt-6.1-sol,推理强度 high |
| 代理软件 | v2rayN 7.16.6,运行 Xray 核心 |
| 本地代理入口 | 127.0.0.1:20171,核心配置中的协议为 mixed |
| Windows 系统代理 | 已开启,地址为 127.0.0.1:20171 |
| TUN | 关闭 |
| 用户级、系统级代理环境变量 | 排查时均未设置 HTTP_PROXY、HTTPS_PROXY |

图 3:当时的托盘环境。托盘图标只能说明相关应用存在,不能单独证明代理连接正常。表中的端口、核心类型和 TUN 状态来自对本机进程、监听端口及配置文件的只读检查。
这里容易产生一个误解:“系统代理已经开启”并不等于“所有程序的每一种连接都已通过代理”。
v2rayN 的系统代理功能是把遵循系统代理设置的软件流量引导到核心入口;系统代理和核心内部的路由分流是两个环节。参见 v2rayN 官方 Wiki:系统代理和路由。
3. 关键证据:WebSocket 超时后才回退 HTTP
为避免仅凭聊天截图下结论,排查时读取了 Codex 的本地日志数据库和会话记录。
下面是 2026 年 10 月 15 日其中一次请求的脱敏时间线:
| 时间 | 事件 | 数据来源 |
|---|---|---|
| 23:40:53.556 | 任务开始,task_started |
会话记录 |
| 23:40:56 左右 | 本轮上下文准备完成 | 会话记录 |
| 23:41:12 | 第 1 次超时重试 | 连接日志 |
| 23:41:27 | 第 2 次超时重试 | 连接日志 |
| 23:41:42 | 第 3 次超时重试 | 连接日志 |
| 23:41:58 | 第 4 次超时重试 | 连接日志 |
| 23:42:15 | 第 5 次超时重试 | 连接日志 |
| 23:42:33 | 回退 HTTP,falling back to HTTP |
连接日志 |
| 23:42:36.981 | 首条助手回复消息记录 | 会话记录 |
从任务开始到首条助手消息,间隔为 103.425 秒。从回退 HTTP 到首条助手消息,只有约 4 秒。
连接日志中的关键片段如下。为方便阅读,已移除线程标识、目录、跟踪信息等无关字段;时间转换为北京时间,保留原始事件措辞:
23:41:12 stream disconnected - retrying sampling request (1/5 in 217ms)...
23:41:27 stream disconnected - retrying sampling request (2/5 in 429ms)...
23:41:42 stream disconnected - retrying sampling request (3/5 in 875ms)...
23:41:58 stream disconnected - retrying sampling request (4/5 in 1.584s)...
23:42:15 stream disconnected - retrying sampling request (5/5 in 2.9s)...
23:42:33 falling back to HTTP
原始重试记录还包含 sampling_error=request timed out。括号中的 217ms、429ms 等是下一次重试前的退避等待,不是每次连接尝试的完整耗时。
这组记录能直接支持的结论是:本轮首次回复前的大段等待与连接超时重试有关,不能全部归因于模型思考或查资料。它不能反向证明图 1 中另一轮数分钟的等待也一定出于相同原因。
4. 为什么浏览器正常,桌面端却会慢
4.1 Codex 的两种通信方式
本次日志显示,Codex 先尝试 WebSocket,失败后回退到 HTTP。这里切换的是通信方式,不代表换了模型。
| 方式 | 通信特点 |
|---|---|
| HTTP | 客户端发起请求,服务端返回响应;响应可以流式传输,文字逐步出现 |
| WebSocket | 建立持续连接,在同一连接上双向交换消息,适合多轮模型与工具交互 |
“HTTP 客户端”指应用内部负责 HTTP 通信的网络组件,不是另外安装的软件。WebSocket 的持续连接可以降低多次交互的开销,参见 OpenAI 官方说明:WebSocket Mode。该说明用于解释机制,不能代替对具体桌面版本的验证。
4.2 需要区分事实与原因推断
本机已验证的事实:
- Windows 系统代理中已经存在
127.0.0.1:20171。 - 这一次 WebSocket 超时重试 5 次,随后回退 HTTP 并成功输出。
- 显式设置代理变量、重新启动应用后,WebSocket 正常复用,本轮不再出现重试和 HTTP 回退。
最符合这些事实的解释:
浏览器、Codex 的 HTTP 网络组件和 WebSocket 网络组件可能使用不同的代理解析逻辑。本次 WebSocket 路径很可能没有正确采用 Windows 系统代理,而显式环境变量让它获得了可用的代理配置。
Codex 项目中的 Issue #29958 也记录了“Windows 系统代理下 WebSocket 超时,显式设置 HTTP_PROXY、HTTPS_PROXY 后正常”的现象。这是同类用户报告,不是本机故障的源码级证明,也不表示所有版本必然存在该问题。
本次尚未直接证明的部分:
- 失败的 WebSocket 请求是否实际尝试了直连。
- 回退后的 HTTP 组件是否读取了 Windows 注册表中的系统代理。
- 哪一段具体版本的源码导致了代理处理差异。
我们没有抓包,也没有调试对应版本的源码。因此,不应把“HTTP 组件读取系统代理,WebSocket 组件没有读取”写成已经观察到的原始日志。
浏览器访问正常,只能证明浏览器对应的访问路径可用;不能证明桌面应用使用了相同的接口、连接方式或代理路径。
5. 本地代理端口与服务端端口有什么区别
20171 不是 HTTP 的默认端口,也不是 Codex 的固定端口,它来自本机 v2rayN 的配置。
| 地址或端口 | 含义 |
|---|---|
127.0.0.1:20171 |
本机 Xray 的代理入口 |
https://chatgpt.com:443 |
HTTPS 服务端入口的表示方式 |
wss://chatgpt.com:443 |
安全 WebSocket 服务端入口的表示方式 |
HTTPS 和 WSS 在未写端口时通常使用 443。二者都可以先经过本地 20171 代理入口,再连接服务端。
本次 20171 是 HTTP/SOCKS 混合入口:核心可以识别不同代理协议。没有发现需要将端口拆开的证据,也没有为了处理本问题去拆分端口。
下面的配置含义是“访问 HTTPS 目标时,使用本地 HTTP 代理入口”:
HTTPS_PROXY=http://127.0.0.1:20171
变量名中的 HTTPS 描述目标连接类型,值中的 http:// 描述连接代理的协议,因此并不矛盾。这里不要凭目标使用 HTTPS,就直接把本地代理地址改成 https://。
另外,把 http://127.0.0.1:20171/ 当作普通网页打开,不能验证代理是否能正确转发目标连接;它首先是代理入口,不是一个必须提供首页的网站。
6. 解决办法:创建应用专用的代理启动入口
6.1 为什么选择应用级设置
把 HTTP_PROXY、HTTPS_PROXY 永久写成 Windows 用户环境变量比较方便,但其他读取这些变量的程序也可能受到影响。例如 Python 网络请求和依赖下载可能开始依赖本地代理是否运行。
本机有数据采集及开发工具,因此这次选择只在启动应用时设置变量。其他独立启动的软件不会因此继承它们;应用启动的工具和子进程则仍可能继承,不能理解为只影响应用界面本身。
6.2 操作步骤
以下步骤适用于本次检查到的商店安装包 OpenAI.Codex,其主程序为 app/ChatGPT.exe。CLI、独立安装包或不同包结构应先确认实际启动路径,不要直接套用。
- 在桌面空白处右键,选择 新建 → 快捷方式。
- 在“对象的位置”粘贴下面完整的一行。
20171要替换为自己实际的 HTTP 或混合代理端口。
powershell.exe -NoProfile -WindowStyle Hidden -Command "$env:HTTP_PROXY='http://127.0.0.1:20171'; $env:HTTPS_PROXY='http://127.0.0.1:20171'; $p=Get-AppxPackage -Name OpenAI.Codex; Start-Process -FilePath (Join-Path $p.InstallLocation 'app\ChatGPT.exe')"
- 点击“下一步”,命名为 ChatGPT(代理),然后完成。
- 保存工作,通过应用菜单或托盘菜单彻底退出 ChatGPT/Codex。只关闭窗口可能仍保留后台实例,已有进程不会因为再次点击快捷方式就自动获得新的环境变量。
- 确认 v2rayN 已运行、代理端口正确,再点击新建的快捷方式。
- 后续使用这个新入口。原来的开始菜单或任务栏入口不会自动附带上述变量。

图 4:创建后的桌面入口。该截图展示图标,具体参数以快捷方式属性和上面的命令为准。
这条命令先在临时 PowerShell 进程中设置两个变量,再启动应用;它没有使用 setx,也没有写用户或系统环境变量。Get-AppxPackage 会查询当前安装位置,避免把带版本号的安装目录写死,但仍依赖安装包名称和内部程序路径保持兼容。
如果没有启动成功,可先用 Windows PowerShell 做下面的只读检查,确认包和主程序存在:
$p = Get-AppxPackage -Name OpenAI.Codex
$p | Select-Object Name, Version, InstallLocation
if ($p) {
Test-Path -LiteralPath (Join-Path $p.InstallLocation 'app\ChatGPT.exe')
}
不要通过反复启动应用来排查路径问题;先确认现有实例状态和命令是否适用于自己的安装方式。
7. 如何确认这次修改生效
重新启动后,不能只凭“感觉快了”下结论,还需要核对下面几项:
| 检查项 | 本次验证结果 |
|---|---|
| 应用启动的工具进程是否收到变量 | HTTP_PROXY、HTTPS_PROXY 均为 http://127.0.0.1:20171 |
| WebSocket 是否正常使用 | 本轮日志出现连接复用记录 |
| 是否再次超时重试 | 核查窗口内,本聊天没有 responses_retry 记录 |
| 是否回退 HTTP | 核查窗口内,本聊天没有 falling back to HTTP |
| 模型列表是否仍刷新超时 | 本次重开后的核查窗口内没有发现 |
| 是否修改了 Windows 全用户设置 | 用户级、系统级两个代理变量仍为空 |
本次复核以 2026 年 10 月 16 日 00:37:42 为重开后观察窗口的起点,统计结果记录于约 00:39:40。其间当前聊天有 5 条 WebSocket 连接复用记录;这些是多次请求的记录,不代表建立了 5 条独立连接。
对应的首次回复时间如下:
| 对照请求 | 任务开始 | 首条助手消息记录 | 间隔 |
|---|---|---|---|
| 调整前,10 月 15 日 | 23:40:53.556 | 23:42:36.981 | 103.425 秒 |
| 调整后,10 月 16 日 | 00:37:51.882 | 00:37:59.192 | 7.310 秒 |
两次不是相同任务的严格基准测试,也没有控制服务器负载、上下文等全部变量。因此,不能把数值差直接当成普遍提速比例。更有说服力的是:显式代理变量生效的同时,本轮不再出现原先的连接超时重试和 HTTP 回退。

图 5:重开后检查结果的会话摘要。界面显示整个检查任务用时 1 分 53 秒,正文中的约 7.3 秒指首次回复等待;两者不冲突。截图本身是结果摘要,WebSocket 状态和计时结论来自另外读取的本机日志及会话记录。
8. 仍然慢时,接下来检查什么
按下面的顺序继续判断,不必一开始就更换模型或开启 TUN:
- 确认实际入口。 是否从新的代理快捷方式启动?应用是否彻底退出过?是否仍在复用先前的后台实例?
- 确认代理可用。 v2rayN 是否运行?端口是否变更?是否出现节点、TLS 或连接稳定性问题?
- 重新看日志。 若仍有 WebSocket 超时和 HTTP 回退,继续检查代理路径;若已没有这些事件,则检查模型处理和工具执行耗时。
- 区分首次回复与整个任务。 查网页、读取文件、执行命令都可能拉长总用时;
high推理强度和较长上下文也可能增加处理时间。 - 必要时做同条件对照。 保持模型、推理强度和问题一致,分别记录首次回复间隔及连接错误,避免只比较不同截图上的总时间。
本次匿名连接探测也曾出现 TLS 失败,说明不能宣称代理链路永远稳定;而匿名请求快速得到 403,只能证明某次访问获得了 HTTP 响应,不能证明带登录状态的完整 WebSocket 流程一定可用。
如何恢复原来的启动行为
先通过应用菜单正常退出,再从原来的启动入口打开即可。专用快捷方式不写全用户代理变量,退出相关进程后,不会留下这两个持久设置。恢复后是否再次出现延迟,需要另行观察;本次没有为了做反向试验而再次中断用户应用。
附录:可复查的位置与命令
A. Windows 系统代理
以下命令只读取设置,不修改注册表:
Get-ItemProperty -LiteralPath 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' |
Select-Object ProxyEnable, ProxyServer, AutoConfigURL
本次读到 ProxyEnable = 1、ProxyServer = 127.0.0.1:20171。这证明系统代理配置存在,不证明每个应用都采用了它。
B. 本地代理是否在监听
Get-NetTCPConnection -State Listen -LocalPort 20171 |
Select-Object LocalAddress, LocalPort, OwningProcess
监听存在只证明该端口上有程序接收连接,不代表节点和所有外部目标都可达。本次进一步核对了进程归属,确认为 Xray。
C. 当前进程与持久环境变量
# 只查看当前 PowerShell 进程收到的值。
$env:HTTP_PROXY
$env:HTTPS_PROXY
# 只查看用户级、系统级是否设置,不修改环境。
foreach ($scope in @('User', 'Machine')) {
foreach ($name in @('HTTP_PROXY', 'HTTPS_PROXY')) {
[pscustomobject]@{
Scope = $scope
Name = $name
Configured = [bool][Environment]::GetEnvironmentVariable($name, $scope)
}
}
}
普通独立终端中的 $env: 只能说明那个终端的环境,不能用来判断另一个应用是否收到变量。本次是在应用启动的工具进程中核对值,再结合应用连接日志验证。
D. 本次读取的 Codex 本地记录
本次环境的状态目录为 %USERPROFILE%\.codex,其中:
logs_2.sqlite:连接日志数据库;排查时以 SQLite 只读模式查询,不修改或清理应用数据库。sessions\2026\10\15\rollout-*.jsonl:本聊天的会话记录。本聊天创建于 10 月 15 日,跨日后仍写入原会话文件,不应只查 10 月 16 日目录。- 搜索关键词:
responses_retry、request timed out、falling back to HTTP、responses_websocket、auth_connection_reused。
这些路径、文件名及字段属于本次版本的实现,不是跨版本稳定接口。读取时应限定聊天和时间范围,并区分重开前的历史错误;不要把数据库当普通文本日志全文打印,也不要公开登录令牌、认证文件或完整请求内容。
参考资料
- v2rayN 官方 Wiki:系统代理和路由:用于理解系统代理与核心分流的区别。
- OpenAI 官方说明:WebSocket Mode:用于理解持续连接和多轮工具交互。
- Codex Issue #29958:Windows 系统代理下的 WebSocket 超时报告:同类用户报告,不能代替对本机版本的验证。
- OpenAI 官方说明:Environment variables:配置与环境变量的相关背景;该页不是本次代理兼容问题的直接证据。
本文使用的 5 张图片均为本次整理提供的截图,保留原文件名,通过相对路径引用。一起移动 codex-proxy-troubleshooting.md 和 images/codex-proxy/,即可保留文图关系。
还没有评论,来第一个吧