AI从入门到精通【1】OpenClaw配置踩坑:一次 Provider、协议和 Transport 层排障复盘
AI从入门到精通【1】OpenClaw配置踩坑:一次 Provider、协议和 Transport 层排障复盘
前言
这次问题的表象很简单:
中转站 API 单独测试是通的,但把
baseURL、apiKey、models写进openclaw.json后,OpenClaw WebUI 里输入“你好”仍然无法正常输出。
一开始这个问题很容易被误判成“Key 写错了”“baseURL 写错了”“模型名写错了”。但实际排查下来,核心并不是单个字段填错,而是 OpenClaw 这种 Agent 运行时并不是简单读取一段 OpenAI-compatible 配置后直接转发请求。它中间至少经过:
- WebUI
- Gateway
- Provider 配置解析
- Model Catalog 模型目录
- 协议选择
- 请求体转换
- 流式响应解析
- 网络代理/Transport 层
- 本地 session 状态
最终能调通,不是因为只把 Key 换了,也不是因为单纯升级了版本,而是把以下几层对齐了:
- 把中转站文档里的
baseURL、apiKey、model name正确映射到 OpenClaw 的models.providers结构; - 明确区分“WebUI 能看到模型列表”和“Gateway 能成功调用模型”是两件事;
- 明确让模型走
openai-responses协议,而不是泛泛地写一个 OpenAI-compatible provider; - 给 Provider 声明兼容性能力,避免 OpenClaw 发送中转站不支持或不稳定支持的字段;
- 在 Provider 请求层配置显式代理,让 Gateway 进程和手动
curl测试走同一条网络出口; - 在 OpenClaw 的 Responses Transport 路径里补齐显式代理下的直连流式请求逻辑;
- 清理/规整测试过程中残留的旧 provider、旧模型目录和旧会话状态,避免 WebUI 继续命中脏状态。
本文只复盘“中转站 API 接入 OpenClaw 并完成模型调用”这一件事。
文中所有供应商名称、API Key、Gateway Token、真实域名、代理端口等敏感信息均已脱敏,统一使用 *** 或 <...> 表示。
名词解释
OpenClaw
OpenClaw 是一个本地 AI Agent 运行时。它不只是一个聊天页面,也不是一个简单的 API 转发工具。
它负责:
- 管理本地 Gateway;
- 管理 WebUI/TUI/CLI 多种入口;
- 管理模型 Provider;
- 管理会话 session;
- 管理工具调用;
- 管理权限和设备认证;
- 管理模型目录和模型能力;
- 把用户消息转换成具体模型 API 请求;
- 读取模型流式输出并回写到界面。
所以,当 OpenClaw 调不通模型时,不能只看 baseURL 和 apiKey,还要看它内部最终组装出来的 provider、model、protocol、payload 和 network transport 是否一致。
OpenClaw Gateway
Gateway 是 OpenClaw 的本地核心服务。WebUI 页面本身不会直接请求中转站 API,而是先把用户输入发给本机 Gateway,再由 Gateway 调用模型 Provider。
本次环境中的 Gateway 地址类似:
http://127.0.0.1:<gateway-port>
常见检查命令:
openclaw gateway status
openclaw gateway run
openclaw gateway stop
openclaw doctor
openclaw config validate
openclaw models list
如果 Gateway 的运行状态、配置文件、权限状态或网络环境不对,WebUI 页面即使能打开,也可能无法真正调用模型。
OpenClaw WebUI
WebUI 是浏览器里的 OpenClaw 控制界面。用户在 WebUI 输入消息后,请求链路大致是:
用户输入
-> WebUI
-> 本机 Gateway
-> OpenClaw Provider
-> 中转站 API
-> 大模型
-> 中转站流式返回
-> Gateway
-> WebUI 展示输出
所以 WebUI “没输出”并不一定代表前端坏了,更多时候是后端 Gateway 或 Provider 调用失败。
TUI
TUI 是终端里的 OpenClaw 聊天界面。它和 WebUI 一样,本质上也走 Gateway。
因此,排障时让 WebUI 和 TUI 都测一遍很有价值。如果两边都失败,优先看 Gateway、Provider 和网络请求;如果只有 WebUI 失败,再重点看浏览器端状态。
Provider
Provider 是 OpenClaw 对“模型供应方”的抽象。
OpenAI 官方、Anthropic、本地 Ollama、中转站、自定义 OpenAI-compatible 服务,都可以是一个 Provider。
本次文章中真实 provider 名称已脱敏,统一写成:
***-responses
需要注意:Provider 名称不是随便给界面展示用的字符串,它会参与模型完整 ID 的拼接。例如:
***-responses/gpt-5.4
如果配置文件里 provider 名称、当前模型引用、session 里保存的旧模型引用不一致,就可能出现“配置改了但实际调用的还是旧模型/旧 provider”的情况。
Model Catalog
Model Catalog 可以理解成 OpenClaw 的“模型目录”。
不是把模型名写进 JSON 就一定能被 OpenClaw 用到。OpenClaw 需要把 provider 下的模型解析成 catalog entry,WebUI/TUI 才能正确展示、选择和调用。
本次出现过一类典型干扰:旧配置里生成过一些测试 provider 和测试模型,后面即使配置调整了,WebUI/session 仍可能残留旧引用。因此排障后期需要清理旧模型目录和测试状态,确保只保留已验证可用的模型。
中转站 API
中转站 API 指的是第三方提供的、兼容 OpenAI API 形式的模型转发服务。
用户请求的不是 OpenAI 官方域名,而是类似:
https://***.***/v1
它通常提供类似 OpenAI 的接口:
/v1/models
/v1/chat/completions
/v1/responses
但是“兼容 OpenAI”不等于“所有 OpenAI SDK、所有参数、所有协议都百分百兼容”。尤其是新模型、Responses API、reasoning effort、流式输出、store、metadata、prompt cache、tool schema 等参数,中转站可能只支持其中一部分。
OpenAI-compatible
OpenAI-compatible 是一个宽泛说法,意思是“请求格式大体兼容 OpenAI API”。
但这个词容易造成误会。它并不是一个精确协议名。
在 OpenClaw 里,真正影响底层请求格式的是模型配置中的 api 字段,比如:
{
"api": "openai-responses"
}
或者:
{
"api": "openai-completions"
}
也就是说:
- OpenAI-compatible 是供应商对外宣称的兼容类型;
openai-responses/openai-completions是 OpenClaw 内部实际采用的请求协议;- 两者不是同一个层面的概念。
Responses API
Responses API 是 OpenAI 新一代响应接口,路径通常是:
/v1/responses
典型请求体长这样:
{
"model": "gpt-5.4",
"input": "hi",
"stream": true,
"max_output_tokens": 1024
}
它的核心特征是使用 input 字段承载输入,输出也按 Responses API 的事件类型流式返回。
本次最终采用的是:
openai-responses
Chat Completions API
Chat Completions 是更早的聊天接口,路径通常是:
/v1/chat/completions
典型请求体长这样:
{
"model": "gpt-5.4",
"messages": [
{
"role": "user",
"content": "hi"
}
],
"stream": true,
"max_completion_tokens": 1024
}
它的核心特征是使用 messages 字段承载对话。
openai-responses 和 openai-completions 的区别
这两个字段在 OpenClaw 配置里看起来只是 api 值不同,但底层差别很大:
| 对比项 | openai-responses |
openai-completions |
|---|---|---|
| HTTP 路径 | /v1/responses |
/v1/chat/completions |
| 输入字段 | input |
messages |
| 输出 token 字段 | max_output_tokens |
常见为 max_completion_tokens 或 max_tokens |
| 流式事件 | Responses API 事件 | Chat Completions delta |
| 新模型能力 | 更适合新一代 GPT/Reasoning 模型 | 更像传统聊天兼容层 |
| OpenClaw 转换逻辑 | buildOpenAIResponsesParams |
buildOpenAICompletionsParams |
你记得“配置文件大体没动”是对的:两种协议在 openclaw.json 里的外层骨架都还是 models.providers,不是完全换一套配置文件格式。
真正变化的是:
- provider 或 model 里的
api字段; - model 的
compat兼容性声明; - OpenClaw 运行时根据
api选择的请求构造函数; - 最终发到中转站的 HTTP endpoint 和 JSON payload。
所以不是说 openclaw.json 里会直接写出 input 或 messages 两套完整请求体,而是 OpenClaw 根据 api 自动生成不同请求体。
显式代理
“显式代理”这几个字比较抽象。结合你的环境,可以把它理解成:
明确告诉 OpenClaw Gateway:“你请求中转站 API 的时候,要走我本机这个代理出口。”
这里的代理通常就是你说的“科学上网的梯子”在本机开的 HTTP/SOCKS 代理端口。
这里最容易困惑的是 127.0.0.1。
127.0.0.1 不是外网服务器地址,而是本机回环地址,意思是“访问我自己这台电脑”。很多代理软件的工作方式是:
本机应用
-> 127.0.0.1:<proxy-port>
-> 本机代理客户端
-> 代理软件连接远端节点
-> 中转站 API
所以配置里的:
http://127.0.0.1:<proxy-port>
不是让请求停在本地,而是让 OpenClaw 先把请求交给本机代理客户端。代理客户端再负责把请求转发到外网。
如果后面换了梯子,需要不要改这个 URL,取决于新梯子的本地监听地址是否变化:
- 如果新梯子仍然监听同一个本机 HTTP 代理端口,比如仍然是
127.0.0.1:<proxy-port>,OpenClaw 配置不用改; - 如果新梯子的本地端口变了,比如从
<old-port>变成<new-port>,就要修改request.proxy.url; - 如果新梯子只提供 SOCKS 端口,而这里配置的是 HTTP 代理端口,也要改成 OpenClaw/底层运行时支持的代理形式;
- 如果你关掉了代理软件,但 OpenClaw 仍配置了显式代理,Gateway 会继续请求
127.0.0.1:<proxy-port>,此时如果本地没有服务监听,就会连接失败; - 如果你的网络以后能直连中转站,可以移除
request.proxy,让 Gateway 直连。
但要注意三个概念不要混在一起:
- 浏览器能走代理,不代表 Gateway 进程一定走代理;
- 终端里
curl --proxy ...能通,不代表 OpenClaw 的 Node.js 进程也自动走同一条代理; - 系统代理开了,不代表所有后台服务都继承系统代理。
本次手动测试中,中转站通过代理能通,但 Gateway 直接请求时出现过 Connection error、fetch failed、超时等问题。因此最终在 Provider 请求配置里显式写入代理:
{
"request": {
"proxy": {
"mode": "explicit-proxy",
"url": "http://127.0.0.1:<proxy-port>"
}
}
}
这不是让浏览器走代理,而是让 OpenClaw 调模型的后端请求走代理。
Transport 层
Transport 层可以理解成“真正把 HTTP 请求发出去、再把流式响应读回来”的代码层。
对于本次问题,配置文件只是告诉 OpenClaw:
- provider 是谁;
- baseUrl 是什么;
- apiKey 是什么;
- 协议用
openai-responses; - 需要走显式代理。
但最终能不能成功,还要看 OpenClaw 的 Responses Transport 是否真的把这些信息用于请求:
- 是否请求了
<baseUrl>/responses; - 是否带了正确的
Authorization: Bearer ***; - 是否带了
Accept: text/event-stream; - 是否真的用了显式代理;
- 是否能正确解析 SSE 流式响应。
本次真正的关键补丁就在这一层。
SSE
SSE 是 Server-Sent Events,常用于大模型流式输出。
中转站流式返回时,不是一次性返回完整 JSON,而是不断返回类似事件块。OpenClaw 要一边读取这些事件,一边把增量输出推回 WebUI。
如果 SSE 解析、代理转发或 SDK 封装不兼容,就可能出现:
- WebUI 卡住;
- Gateway 超时;
- 模型已经返回但前端没有显示;
- OpenClaw 认为模型调用失败。
Agent
Agent 是具备上下文管理、工具调用、模型选择、状态保存能力的 AI 执行单元。
普通 API Demo 只需要“发一个请求,拿一个回复”。Agent 系统还要处理:
- 当前 session 用哪个模型;
- 是否有历史上下文;
- 是否启用工具;
- 是否有模型 fallback;
- 是否保存 reasoning 信息;
- 是否压缩上下文;
- 是否从旧 session 里读取了旧 provider。
这也是为什么这次不是“复制一段配置就完事”。
Codex
Codex 是本次协助排障的代码 Agent。它负责读取本地配置、查日志、修改配置、验证命令输出、定位 OpenClaw dist 包里的请求路径。
Codex 不是问题根因,只是排查工具。
MCP
MCP 是 Model Context Protocol,中文可以理解为“模型上下文协议”。它让 Agent 能够连接外部工具、服务和资源。
本次中转站调用失败不是 MCP 导致的,但 OpenClaw/Codex 这类 Agent 系统通常会同时涉及 MCP、工具调用和本地服务,因此理解 MCP 有助于理解“Agent 运行时为什么比普通聊天 API 更复杂”。
过程总结
这次排障可以压缩成一条主线:
用户提供中转站配置
-> 提取 baseURL/apiKey/model name 写入 openclaw.json
-> WebUI 能看到模型列表,但输入消息后无法调用
-> 确认中转站 API 本身可访问
-> 确认问题已经不是“模型列表未生效”,而是“模型调用链路失败”
-> 日志里出现 403/Connection error/timeout/fetch failed
-> 对比 openai-completions 与 openai-responses 协议
-> completions 路径能返回 200 和内容,但最终坚持打通较新的 responses 路径
-> 给模型补 compat 能力声明,避免不兼容字段
-> 给 provider 增加显式代理
-> 补齐 Responses Transport 在显式代理下的直连 SSE 请求路径
-> 清理测试 provider、旧模型目录和旧 session 干扰
-> WebUI/TUI 可以正常输入输出
最开始的问题不是“中转站不能用”,而是:
中转站 API 可用,但 OpenClaw Gateway 最终发出去的请求,没有和手动测试时可用的请求保持一致。
这里的“不一致”不是说模型列表完全没有生效。恰恰相反,模型列表能显示,说明 OpenClaw 已经读到了部分配置。真正的问题发生在更后面:Gateway 按这个模型发起真实请求时,协议、payload、网络出口和流式 transport 没有完全对齐。
过程详细说明
1. 最开始的配置为什么看起来生效了,但模型调用不生效
最初并不是把中转站文档里的整段配置原样复制进 OpenClaw,而是从中提取关键信息:
baseURLapiKeymodel name- 模型上下文和输出限制
- 模型推理强度档位
然后把这些信息手动写入:
/Users/<user>/.openclaw/openclaw.json
这个过程里,原始中转站文档给出的信息大致类似:
{
"provider": {
"openai": {
"options": {
"baseURL": "https://***.***/v1",
"apiKey": "sk-***"
},
"models": {
"gpt-5.4": {
"name": "GPT-5.4",
"limit": {
"context": 1050000,
"output": 128000
},
"variants": {
"low": {},
"medium": {},
"high": {},
"xhigh": {}
}
}
}
}
},
"$schema": "https://opencode.ai/config.json"
}
这段配置对某些 OpenAI-compatible 客户端或 opencode 风格配置来说可能是正确的,但 OpenClaw 不能直接照搬这一整段。需要把其中的信息映射到 OpenClaw 自己的模型配置结构中。
OpenClaw 当前读取自定义模型的核心位置是:
/Users/<user>/.openclaw/openclaw.json
其中关键结构是:
{
"models": {
"mode": "merge",
"providers": {
"***-responses": {
"baseUrl": "https://***.***/v1",
"apiKey": "sk-***",
"api": "openai-responses",
"models": []
}
}
}
}
注意几个差异:
- 原配置是
provider.openai.options.baseURL; - OpenClaw 需要的是
models.providers.<provider>.baseUrl; - 原配置的模型是对象 map;
- OpenClaw 当前更稳定的方式是 provider 下的
models数组; - 原配置的
variants.low/medium/high/xhigh不等于 OpenClaw 运行时一定会按这些 reasoning effort 发请求; - 原配置没有明确告诉 OpenClaw 使用
openai-responses还是openai-completions; - 原配置里
baseURL是大写 URL,而 OpenClaw 当前模型 provider 里使用的是baseUrl。
但这还不是最关键的失败点。
真正让人困惑的是:后来 WebUI 已经能看到对应模型列表,说明 openclaw.json 至少已经被 OpenClaw 读到了,模型目录也已经部分生效。也就是说,问题不是停留在“配置完全没读到”。
更准确的判断应该是:
模型列表生效,只能证明 OpenClaw 解析到了 provider/model 元数据;不能证明 Gateway 用这个模型发出的真实 API 请求一定成功。
本次最开始的核心问题就是这个:
配置看起来生效
-> WebUI 能看到模型
-> 但点击发送后,Gateway 调模型失败
2. 第一次改成 OpenClaw Provider 结构后,为什么还是调不通
后面把配置改成了 OpenClaw 能识别的 provider 结构,并能在模型列表里看到模型。
但看到模型不代表模型调用一定成功。
OpenClaw 的模型列表展示主要依赖本地配置和模型目录;真正调用模型时,Gateway 还要继续完成:
- 选择协议;
- 组装请求体;
- 注入鉴权头;
- 选择网络出口;
- 处理流式响应;
- 把结果写回 session 和 WebUI。
日志里出现过几类关键信号:
provider=<provider> model=gpt-5.5 error=403 Your request was blocked
LLM request failed: network connection error
rawError=Connection error
rawErrorPreview=fetch failed
low context window: <provider>/gpt-5.5 ctx=4000
这些信号说明:
- OpenClaw 已经进入模型调用流程;
- 不是纯粹的“配置文件没读取”;
- 失败发生在 Provider 真实请求或运行时模型参数阶段;
- 早期测试 provider 还带着错误的上下文窗口等模型元数据;
- 有些请求被中转站或网络出口拦截成 403;
- 有些请求没有成功建立网络连接或流式读取。
也就是说,问题从“配置有没有被读到”升级成了“读到之后发出去的请求是否正确”。
3. 为什么要试 openai-completions 和 openai-responses
中转站一般会说自己兼容 OpenAI,但它可能同时提供多个接口:
/v1/chat/completions
/v1/responses
OpenClaw 不能只知道“这是 OpenAI-compatible”,它还要知道具体走哪条 API。
如果配置成:
{
"api": "openai-completions"
}
OpenClaw 会更倾向于构造 Chat Completions 请求,请求体核心是:
{
"messages": []
}
如果配置成:
{
"api": "openai-responses"
}
OpenClaw 会构造 Responses 请求,请求体核心是:
{
"input": []
}
这就是你问的“两个分支下配置文件格式是不是不同”的答案:
外层格式基本还是同一个 OpenClaw provider 配置格式,主要区别是
api字段和模型兼容性字段;真正不同的是 OpenClaw 运行时生成出来的 HTTP 路径和 JSON 请求体。
排查时两个方向都试过:
openai-completions分支:直接请求测试能返回 HTTP 200,并且能拿到内容,说明中转站的 Chat Completions 兼容层本身是可用的;openai-responses分支:早期能拿到 HTTP 200,但没有稳定得到 OpenClaw WebUI 需要的完整流式输出效果,因此问题不在“HTTP 状态码是否为 200”,而在 Responses 协议的 payload、流式事件解析和 transport 链路是否真正打通。
最终坚持使用 openai-responses,不是因为 openai-completions 完全不可用,而是因为 Responses API 是更新的接口形态,更适合这批 GPT/Reasoning 模型的长期使用。也就是说,本次最终目标不是“找一个能返回 200 的接口”,而是:
让 OpenClaw WebUI 通过
openai-responses协议完成真实模型输入输出。
4. 为什么要加 compat 能力声明
OpenClaw 会根据 provider、api、model id 推断模型能力。但中转站不是 OpenAI 官方 endpoint,即使模型名看起来像官方模型,也不代表所有高级字段都能原样透传。
因此在模型配置里加了类似这样的兼容性声明:
{
"id": "gpt-5.4",
"name": "GPT-5.4",
"api": "openai-responses",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 1050000,
"maxTokens": 128000,
"compat": {
"supportsStore": false,
"supportsDeveloperRole": true,
"supportsReasoningEffort": true,
"supportsUsageInStreaming": true,
"thinkingFormat": "openai",
"supportedReasoningEfforts": ["low", "medium", "high", "xhigh"]
}
}
这一步的意义不是“美化 WebUI 展示”,而是告诉 OpenClaw:
- 这个模型走 Responses API;
- 这个模型支持 reasoning effort;
- 这个模型的 reasoning 格式按 OpenAI 风格处理;
- 不要假定中转站完整支持
store等高级字段; - 流式 usage 能力按兼容配置处理。
OpenClaw 的相关逻辑在安装目录的 dist 文件里,例如:
/opt/homebrew/lib/node_modules/openclaw/dist/provider-model-compat-*.js
/opt/homebrew/lib/node_modules/openclaw/dist/openai-transport-stream-*.js
这些文件会根据 compat 决定是否调整 developer role、reasoning、store、streaming usage 等行为。
5. 为什么要配置显式代理
手动测试 API 时,如果使用了类似:
curl --proxy http://127.0.0.1:<proxy-port> \
-H "Authorization: Bearer sk-***" \
-H "Content-Type: application/json" \
https://***.***/v1/responses \
-d '{"model":"gpt-5.4","input":"hi","stream":true}'
这个测试只能证明:
终端里的 curl 在指定代理后,可以访问中转站。
但它不能证明:
OpenClaw Gateway 这个后台 Node.js 进程也会自动使用同一个代理。
从日志里的 Connection error、fetch failed、timeout 看,Gateway 当时的网络出口和手动 curl 并不完全一致。
所以最终在 Provider 下加入:
{
"request": {
"proxy": {
"mode": "explicit-proxy",
"url": "http://127.0.0.1:<proxy-port>"
},
"allowPrivateNetwork": true
}
}
这一步的核心作用是把“网络出口”从隐式环境变成显式配置。
一句话解释:
不是让你打开梯子就完了,而是要让 OpenClaw Gateway 这个进程明确知道该走哪个本机代理端口。
6. 真正关键的补丁:Responses Transport 显式代理直连
只在配置里写代理还不够,运行时 transport 层也必须真的使用这个代理。
本次关键代码路径在:
/opt/homebrew/lib/node_modules/openclaw/dist/openai-transport-stream-*.js
当前安装包里能看到与本次问题直接相关的几个函数:
buildOpenAIResponsesUrl(model)
createDirectOpenAIResponsesStream(...)
iterateDirectOpenAIResponsesSse(...)
createOpenAIResponsesTransportStreamFn()
它们解决的是同一个问题:
当 provider 配置了显式代理时,不完全依赖 OpenAI SDK 的默认请求路径,而是用 OpenClaw 自己的 undici/ProxyAgent 路径直接请求
<baseUrl>/responses,并自己读取 SSE 流。
关键逻辑可以概括为:
读取模型 provider request 配置
-> 如果发现 request.proxy.mode = explicit-proxy
-> 构造 ProxyAgent
-> POST 到 <baseUrl>/responses
-> 设置 Authorization / Content-Type / Accept
-> 读取 text/event-stream
-> 逐块解析 SSE
-> 交给 OpenClaw 的 Responses stream processor
在代码层面,createOpenAIResponsesTransportStreamFn() 里会优先尝试:
createDirectOpenAIResponsesStream(...)
如果没有显式代理,再回退到:
client.responses.create(...)
这就是这次最值得关注的“补丁点”:它让 OpenClaw Gateway 发模型请求时,终于和手动验证成功的 curl --proxy ... /v1/responses 路径对齐。
7. Provider request 配置如何传到 Transport
另一个关键代码路径是:
/opt/homebrew/lib/node_modules/openclaw/dist/provider-request-config-*.js
这里负责把配置文件里的:
{
"request": {
"proxy": {
"mode": "explicit-proxy",
"url": "http://127.0.0.1:<proxy-port>"
}
}
}
解析成 transport 层能使用的 dispatcher policy。
可以理解为:
openclaw.json
-> request.proxy
-> provider request config
-> dispatcher policy
-> undici ProxyAgent
-> 真实 HTTP 请求
如果只在配置文件里写了代理,但 transport 层没有消费这个配置,请求仍然不会走代理。
8. 最终可用的配置骨架
最终保留的是类似下面的配置骨架,敏感信息已脱敏:
{
"models": {
"mode": "merge",
"providers": {
"***-responses": {
"baseUrl": "https://***.***/v1",
"apiKey": "sk-***",
"auth": "api-key",
"authHeader": true,
"api": "openai-responses",
"request": {
"proxy": {
"mode": "explicit-proxy",
"url": "http://127.0.0.1:<proxy-port>"
},
"allowPrivateNetwork": true
},
"models": [
{
"id": "gpt-5.4",
"name": "GPT-5.4",
"api": "openai-responses",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 1050000,
"maxTokens": 128000,
"compat": {
"supportsStore": false,
"supportsDeveloperRole": true,
"supportsReasoningEffort": true,
"supportsUsageInStreaming": true,
"thinkingFormat": "openai",
"supportedReasoningEfforts": ["low", "medium", "high", "xhigh"]
}
}
]
}
}
}
}
如果你的网络环境不需要代理,可以不写 request.proxy。但在本次环境里,手动测试和 Gateway 调用的网络出口不一致,所以显式代理是必要条件之一。
9. 为什么要清理测试 provider 和旧状态
这一步不是最终调通的根因,但它很重要。
排障过程中试过多个 provider 名称、多个协议、多个模型配置。OpenClaw 又会保存 session 状态和模型目录状态,所以容易出现:
- WebUI 还引用旧 provider;
- session 里还保存旧模型;
- 旧模型上下文窗口错误;
- fallback 链路里还有测试模型;
.bak或临时文件让人误判当前配置。
因此后期做了收敛:
- 删除测试分支 provider;
- 删除测试中不可用模型;
- 只保留验证可用模型;
- 清理旧模型目录缓存;
- 确认
openclaw config validate通过; - 确认
openclaw models list只展示可用模型; - 确认 WebUI/TUI 可以真实输入输出。
这一步的目的不是“让 API 能通”,而是让验证结果可信,避免继续被旧状态误导。
核心问题复盘
最开始真正的问题是什么
最开始不是单纯的 Key 错,也不是中转站本身不可用。
更准确地说,问题是:
WebUI 已经能读取到自定义模型配置,但 Gateway 按该模型发起真实调用时,协议、网络出口和 Responses Transport 没有完全对齐。
进一步拆开是五层:
- 配置映射层:中转站文档里的
baseURL、apiKey、model name需要映射到 OpenClaw 的models.providers,但“模型列表显示”只代表这一层基本通过; - 协议层:必须明确选择
openai-responses,否则请求 endpoint 和 payload 可能不对; - 兼容性层:中转站不等于官方 OpenAI endpoint,不能默认发送所有高级字段;
- 网络层:手动 curl 走代理能通,不代表 Gateway 进程自动走代理;
- 运行时层:Responses API 在显式代理下需要 transport 层真正使用 ProxyAgent 并正确解析 SSE。
为什么别人改下配置文件就能用,我这里要改这么多
这里的“别人”不是泛指官方 OpenAI 用户,而是同样使用这个自定义中转站的朋友。
你的朋友也是从同一个中转站里拿到 baseURL、apiKey、model name,再写进 OpenClaw 配置;他的 WebUI 直接能调用,而你的 WebUI 虽然能显示模型列表,但发送消息失败。
这说明根因不应该简单归结为:
中转站文档错了
也不应该简单归结为:
模型名称或 API Key 一定错了
因为同一个中转站、同一类配置,在朋友环境里已经证明可以工作。更合理的解释是:你的本地 OpenClaw 运行链路和朋友不完全一样。
这类差异可能出现在:
- 朋友的 Gateway 网络环境可以直接访问中转站,而你的 Gateway 需要显式代理;
- 朋友的代理软件刚好被系统环境或启动环境继承了,而你的 OpenClaw Gateway 没有继承;
- 朋友使用的协议路径刚好是中转站兼容较好的路径,而你最终希望打通
openai-responses; - 朋友的 OpenClaw 本地状态更干净,没有多次测试 provider、旧模型目录、旧 session 干扰;
- 朋友的 OpenClaw 版本或 dist 包里的 transport 行为刚好没有触发这次 Responses + 显式代理的坑;
- 朋友没有走到需要 OpenClaw 自己处理 Responses SSE 流式读取的那条问题路径。
本次环境叠加了多个变量:
- 自定义中转站;
- 非官方 OpenAI endpoint;
- 多个 GPT 新模型;
- Responses API;
- reasoning effort;
- 流式 SSE;
- Gateway 网络出口和手动测试网络出口不一致;
- 旧 provider 和旧 session 干扰;
- OpenClaw Responses Transport 对显式代理路径的处理需要补齐。
所以它不是“朋友配置对、我的配置一定错”,而是:
朋友的三项配置刚好足以覆盖他的运行环境;你的环境在“模型列表生效”之后,还额外卡在 Gateway 调用模型时的网络出口、Responses 协议和 Transport 处理上。
这也解释了为什么本次排障不能只停留在 openclaw.json 表面字段,而必须继续看 Gateway 日志和 OpenClaw transport 代码。
是协议问题吗
是,但不只是协议问题。
协议问题体现在:
openai-completions和openai-responses生成的请求体完全不同;openai-completions在直接测试中能返回 200 和内容,说明它可以作为一条可用兼容路径;openai-responses是本次最终坚持要打通的新协议路径;- OpenClaw 必须知道当前模型到底应该走哪一种 API。
但如果只改协议,不解决显式代理和 transport 层,openai-responses 仍然可能出现 Connection error、超时,或者 HTTP 200 但 WebUI 没有拿到可展示输出。
所以更准确的结论是:
openai-completions可用不等于openai-responses自动可用;协议选择是必要条件,Transport 网络路径和流式解析对齐才是把 Responses 真正打通的关键条件。
是系统脏数据问题吗
脏数据不是最初的根因,但它会放大排障难度。
旧 provider、旧 session、旧模型目录会让人产生错觉:
我明明改了配置,为什么 WebUI 还是像没改?
这种情况下,必须用命令验证当前运行时看到的模型,而不是只看配置文件:
openclaw config validate
openclaw models list
openclaw gateway status
必要时再清理旧 session、旧模型缓存和测试 provider。
是我之前改坏了系统配置吗
从这次排障看,更像是“配置迁移和多次试错后产生了叠加问题”,而不是某一个系统设置被彻底改坏。
早期日志里出现过安全告警、token 缺失、测试 provider、403、网络连接失败、上下文窗口过低等多类信息。这说明环境里同时存在:
- 初始 OpenClaw 配置不完整;
- WebUI/Gateway 授权状态需要重新确认;
- 自定义 provider 多次试验;
- 网络出口不稳定或不一致;
- 模型元数据不准确。
最终通过收敛配置、修正协议、补齐 transport、清理状态,可以恢复到健康可用状态。
后续遇到类似问题,应该怎么更快排查
第一步:先证明中转站 API 本身可用
不要一上来就在 WebUI 里反复点。
先用最小请求验证:
curl --proxy http://127.0.0.1:<proxy-port> \
-H "Authorization: Bearer sk-***" \
-H "Content-Type: application/json" \
https://***.***/v1/responses \
-d '{"model":"gpt-5.4","input":"hi","stream":false}'
如果这一步不通,先解决 Key、baseURL、模型名、余额、供应商权限、网络代理。
第二步:确认 OpenClaw 是否读到了 provider 和模型
配置写完后不要只看 JSON 文件,要看 OpenClaw 运行时实际识别结果:
openclaw config validate
openclaw models list
如果 models list 看不到你的模型,说明还停留在配置解析问题。
如果 models list 已经能看到模型,但 WebUI 发送消息失败,就不要继续纠结“模型有没有写进去”,而要进入下一层:协议、payload、网络出口和 Gateway 日志。
第三步:确认协议
如果中转站支持 Responses API,就明确写:
{
"api": "openai-responses"
}
不要只写“openai compatible”这种概念描述。OpenClaw 需要的是可执行的协议字段。
第四步:确认 Gateway 的网络出口
如果手动 curl --proxy 能通,而 OpenClaw 不通,要立刻怀疑 Gateway 没走同一条代理。
检查 provider 里是否有:
{
"request": {
"proxy": {
"mode": "explicit-proxy",
"url": "http://127.0.0.1:<proxy-port>"
}
}
}
第五步:查 Gateway 日志,不要只看 WebUI
重点搜索这些关键词:
403
Connection error
fetch failed
provider error
timeout
model fallback
low context window
WebUI 的“没有输出”只是结果,Gateway 日志里的错误才更接近原因。
第六步:最后再清理旧状态
当确认配置和代码路径都正确后,再清理旧 provider、旧模型目录、旧 session。
顺序不要反过来。否则容易陷入“删来删去但根因还在”的循环。
小结
这次问题的核心不是“中转站 API 不通”,也不是“OpenClaw 完全坏了”。
真正的核心是:
WebUI 能显示模型列表,只说明本地模型配置被识别;真正能不能输出,取决于 Gateway 运行时是否能按正确协议、正确网络出口和正确 Transport 路径完成模型调用。
最终最关键的修复点是:
- 配置层把中转站文档里的
baseURL、apiKey、model name映射到 OpenClaw 的models.providers; - 认知层明确区分“模型列表已生效”和“模型调用已打通”;
- 协议层最终坚持打通
openai-responses,而不是停留在openai-completions已经能返回 200 和内容; - 模型层补充
compat,让 OpenClaw 按中转站能力发请求; - 网络层给 provider 配置显式代理;
- 代码层让 Responses Transport 在显式代理下直接请求
<baseUrl>/responses并解析 SSE; - 状态层清理测试 provider 和旧 session 干扰。
以后再遇到类似问题,不要从 WebUI 反复试起,而应该按这条链路排查:
curl 直连/代理验证
-> OpenClaw 配置结构
-> models list 运行时模型目录
-> 如果模型列表已生效,继续查真实调用链路
-> api 协议字段
-> compat 能力声明
-> Gateway 网络出口
-> Transport 日志
-> session/缓存清理
这样能更快判断问题到底在配置、协议、网络、代码还是本地状态,而不是花一整天在“看起来都改了,但就是不生效”的循环里消耗精力。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)