OpenClaw 通过自定义 openai-completions Provider 接入 DeepAI API 中转站、model-router 或自建 OpenAI-compatible wrapper 时,最隐蔽的问题之一是:上游日志显示请求成功、curl 也能返回标准 JSON,但 OpenClaw 界面就是不显示回复。很多时候,根因不是模型没回答,而是 stream:true 场景下响应格式不对。

stream:true,OpenAI-compatible 服务应返回 text/event-stream 和 chat.completion.chunk,最后以 data: [DONE] 结束。GitHub Issue 背景:curl 正常,OpenClaw 界面沉默
这个问题来自 OpenClaw Issue #14262。用户实现了一个本地 model-router:核心路由器负责选择模型,OpenAI wrapper 暴露 /v1/chat/completions。使用 curl 测试时,接口能返回标准 chat.completion JSON;OpenClaw 也确实把请求打到了 wrapper,wrapper 日志也显示已经返回响应,但 UI 没有任何输出。
经过加日志后,用户发现 OpenClaw 请求体里包含:
{
"model": "auto",
"stream": true,
"stream_options": {...}
}
而 wrapper 返回的是单个 JSON 对象:
{
"id": "chatcmpl-123",
"object": "chat.completion",
"choices": [
{
"message": {
"role": "assistant",
"content": "Hello world"
}
}
]
}
这解释了为什么界面沉默:OpenClaw 在等 SSE 流式 chunk,但服务端给了一个非流式 JSON。
正确做法:stream=true 返回 SSE,stream=false 返回 JSON
OpenAI-compatible 服务应该根据请求里的 stream 参数分支处理:
stream: true:返回Content-Type: text/event-stream,逐段发送chat.completion.chunk。stream: false:返回普通application/json的chat.completion对象。
一个简化的 SSE 响应应该像这样:
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant"}}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Hello"}}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":" world"}}]}
data: [DONE]
Issue 中用户实现 SSE 后,curl -N 能看到流式输出,OpenClaw UI 也恢复正常显示。
DeepAI API 中转站或自建代理怎么排查
- 在中转站日志里确认 OpenClaw 请求是否带
stream:true。 - 用
curl -N手动请求同一接口,观察是否实时输出data:chunk。 - 检查响应头是否为
Content-Type: text/event-stream。 - 确认每个 chunk 的 object 是
chat.completion.chunk,内容放在choices[].delta.content。 - 确认最后一定发送
data: [DONE],并以空行结束。
curl 测试模板
流式测试建议使用 -N 或 --no-buffer:
curl -N -X POST https://api.deepai.wang/v1/chat/completions \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "your-model",
"messages": [{"role":"user","content":"你好"}],
"stream": true
}'
非流式测试则应该返回单个 JSON:
curl -X POST https://api.deepai.wang/v1/chat/completions \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "your-model",
"messages": [{"role":"user","content":"你好"}],
"stream": false
}'
常见坑位
- curl 默认看起来成功:非流式 curl 成功不代表 stream=true 场景兼容。
- SSE 头不对:没有
text/event-stream时,客户端可能不按流式解析。 - chunk 对象类型不对:流式应是
chat.completion.chunk,不是chat.completion。 - 使用 message 而不是 delta:SSE chunk 内容应放在
delta字段。 - 忘记 [DONE]:客户端会继续等待,表现为卡住或不收尾。
为什么这对 API 中转站 SEO 有价值
很多站长搭 API 中转站时,只验证非流式 JSON,就认为 OpenAI-compatible 已经完成。但 Agent 客户端、IDE 插件、Web UI 往往默认流式输出。DeepAI API 中转站如果能同时兼容 stream:true 和 stream:false,并在日志中清楚记录请求模式、响应耗时和中断原因,就能显著减少“上游有回复但前端不显示”的支持成本。
上线前验证清单
- 对每个模型路由分别测试
stream:false普通 JSON。 - 对每个模型路由分别测试
stream:trueSSE。 - 确认代理不会把上游完整 JSON 直接塞进一个 SSE chunk 里破坏字段结构。
- 确认异常时也能发送可读错误,而不是让客户端无限等待。
- 用 OpenClaw、Cherry Studio、n8n、Dify 等客户端做端到端验证。
参考资料
- OpenClaw Issue #14262:custom provider returns responses but OpenClaw does not display them
- OpenClaw stream_options include_usage 与 token 统计排查
- OpenClaw parallel_tool_calls 400 工具调用排查
- DeepAI API 中转站教程导航
总结
OpenClaw 接入 DeepAI API 中转站或自定义 model-router 时,如果请求成功但界面不显示回复,优先检查请求是否带 stream:true。带流式参数时,服务端必须返回 text/event-stream、chat.completion.chunk、choices[].delta 和最终 data: [DONE];只有 stream:false 才返回单个 JSON。把流式和非流式都实现完整,才是真正可用的 OpenAI-compatible API 中转站。