一個(gè)由 gateway 版本未同步引發(fā)的漫長(zhǎng) Debug
鯨小子你崛起吧。
0. TL;DR
DeepSeek V4(deepseek-v4-flash / deepseek-v4-pro)在 OpenClaw 2026.4.24 以上版本中已經(jīng)可以正常使用,包括 thinking mode 和帶 tool call 的多輪對(duì)話。如果你升級(jí)了 OpenClaw 但發(fā)現(xiàn) V4 仍然用不了,檢查一下 gateway 版本有沒有同步——這是一個(gè)很容易忽略的坑。
1. 背景
DeepSeek 2026 年初發(fā)布了 V4 系列,同時(shí)保留舊模型 ID(deepseek-chat / deepseek-reasoner)做向后兼容。V4 最大的變化是默認(rèn)啟用 Thinking Mode,并且修改了 Chat Completions API 的 stream chunk 結(jié)構(gòu):
- stream chunk 中
delta.content在 thinking 階段返回null,思維鏈內(nèi)容放在delta.reasoning_content - 涉及 tool call 的多輪對(duì)話必須回傳
reasoning_content(否則返回 400) - thinking mode 下
temperature、top_p等參數(shù)無(wú)效(不會(huì)報(bào)錯(cuò))
這些變化導(dǎo)致很多基于 OpenAI SDK 的工具出現(xiàn)兼容性問題。
2. 之前踩過的坑
在最終解決之前,嘗試過三種方案都失敗了:
用 anthropic-messages 路徑:配置 api: "anthropic-messages" + baseUrl: "https://api.deepseek.com/anthropic"。結(jié)果全部返回 400 "reasoning_content must be passed back"。原因:DeepSeek 的 Anthropic 兼容端點(diǎn)要求嚴(yán)格回傳 reasoning 內(nèi)容,pi-ai 的 anthropic.js 沒有實(shí)現(xiàn)這個(gè)邏輯。
用 openrouter thinking format:配置 compat.thinkingFormat: "openrouter",手動(dòng)改了 pi-ai 的 openrouter 分支。結(jié)果第一次能工作,后續(xù)失敗。原因:多輪對(duì)話中 reasoning_content 回傳未正確處理。
設(shè) reasoning: false 跑 V4:V4 Flash/Pro 都設(shè)成 reasoning: false,想繞開 thinking 模式。結(jié)果首次能響應(yīng),但出現(xiàn)固定模式——"一次無(wú)響應(yīng),后續(xù)全部無(wú)響應(yīng)",必須切回 V3.2 Chat 才能恢復(fù)。原因當(dāng)時(shí)搞不清楚,也是這次測(cè)試想解決的核心問題。
3. 配置
最終正常工作的配置很簡(jiǎn)單——不需要任何特殊的 compat 配置,pi-ai 的自動(dòng)檢測(cè)已經(jīng)處理好了一切:
{
"models": {
"providers": {
"deepseek": {
"baseUrl": "https://api.deepseek.com",
"api": "openai-completions",
"models": [
{ "id": "deepseek-chat", "name": "DeepSeek V3.2 (Chat)", "reasoning": false, "maxTokens": 8192 },
{ "id": "deepseek-reasoner", "name": "DeepSeek V3.2 (Reasoner)", "reasoning": true, "maxTokens": 65536 },
{ "id": "deepseek-v4-flash", "name": "DeepSeek V4 Flash", "reasoning": true, "maxTokens": 65536 },
{ "id": "deepseek-v4-pro", "name": "DeepSeek V4 Pro", "reasoning": true, "maxTokens": 65536 }
]
}
}
}
}
關(guān)鍵點(diǎn):V4 模型的 reasoning 設(shè)為 true。pi-ai 的 detectCompat 會(huì)自動(dòng)檢測(cè) DeepSeek 并啟用 thinkingFormat: "deepseek" 和 requiresReasoningContentOnAssistantMessages: true。
4. 測(cè)試A:直連 API(curl)
用 curl 直接調(diào) DeepSeek Chat Completions API,繞過 pi-ai / OpenClaw,目的是確認(rèn) V4 API 本身是否正常。
4.1 Non-streaming,不傳 thinking 參數(shù)
結(jié)果:HTTP 200,正常返回 content 和 reasoning_content(124 個(gè) reasoning tokens)。說明 API 本身正常,默認(rèn)進(jìn)入 thinking mode。
4.2 Non-streaming,主動(dòng)開啟 thinking
加了 reasoning_effort: "high" 和 thinking: { type: "enabled" },結(jié)果一樣:HTTP 200,正常。
4.3 多輪對(duì)話,不回傳 reasoning_content
第一輪:user "回復(fù)數(shù)字 42" → assistant "42"(有 reasoning_content)。第二輪直接發(fā)新請(qǐng)求,不傳第一輪的 reasoning_content。結(jié)果:HTTP 200,正常返回 content: "7"。沒有 tool call 時(shí) reasoning_content 確實(shí)不需要回傳。
4.4 Streaming,默認(rèn) thinking mode
這是最關(guān)鍵的一個(gè)測(cè)試。V4 默認(rèn) thinking mode 下的 stream chunk 結(jié)構(gòu)非常特殊:
第一個(gè) chunk:
{delta: {role: "assistant", content: null, reasoning_content: ""}}
thinking 過程(content 始終是 null):
{delta: {content: null, reasoning_content: "嗯"}}
{delta: {content: null, reasoning_content: "用戶"}}
{delta: {content: null, reasoning_content: "只"}}
...(繼續(xù) reasoning_content tokens)
結(jié)束 chunk:
{delta: {content: "", reasoning_content: null}, finish_reason: "stop"}
最后: data: [DONE]
結(jié)果:curl 可以完整接收所有 chunk,包括 [DONE]。
4.5 Streaming,禁用 thinking
加了 thinking: { type: "disabled" }。chunk 結(jié)構(gòu)與標(biāo)準(zhǔn) OpenAI 格式一致:content: "" → content: "好的" → ... → finish_reason: "stop"。正常。
4.6 測(cè)試 A 小結(jié)
V4 API 本身在 5 種場(chǎng)景下都正常。問題不出在 API 端。
5. 測(cè)試B:走 OpenClaw 調(diào)用(4.22 版)
5.1 第一次嘗試(reasoning: false 的舊配置)
在 OpenClaw WebChat 中選擇 V4 Flash 標(biāo)簽,發(fā) "回復(fù)OK"。
結(jié)果:? 徹底卡死。assistant 開始 tool call 然后掛起,沒有任何輸出。之后所有消息都無(wú)法響應(yīng),必須切回 V3.2 Chat 才恢復(fù)。
5.2 第二次嘗試(改成 reasoning: true)
改配置后重啟 gateway,再試一次。
結(jié)果:? 同樣卡死。
到這里我們花了大量時(shí)間分析 pi-ai 的 openai-completions.js 源碼,發(fā)現(xiàn) stream parser 中處理 delta.content 的代碼(line 157-159)對(duì) content: null 和 content: "" 都不做處理——但 V4 thinking mode 全程發(fā)的就是 content: null。這看起來(lái)就是根因。
5.3 逆天的是
我發(fā)現(xiàn)——我的 gateway 版本不對(duì)。
運(yùn)行 openclaw --version 顯示 2026.4.24,但這是全局 npm CLI 的版本。實(shí)際跑著的 gateway 進(jìn)程(systemd user service)指向的是 /home/openclaw/openclaw-cn/dist/index.js——本地源碼目錄的 2026.4.22 版本。更糟的是,這個(gè) gateway 最早是 2026.2.23-cn 的配置,中間升級(jí)源碼到 4.22 但 systemd unit 的路徑?jīng)]變,等于一直跑著舊的 gateway。
而 OpenClaw 2026.4.24 的 CHANGELOG 明確寫著:
"DeepSeek V4 Flash and V4 Pro are in the bundled catalog, V4 Flash is the onboarding default, and DeepSeek thinking/replay behavior is fixed for follow-up tool-call turns."
5.4 切到 4.24 后
修改 systemd unit,把 ExecStart 指向全局 4.24 安裝路徑:
/root/.nvm/versions/node/v22.17.0/lib/node_modules/openclaw/dist/index.js
重啟后,切 V4 Flash 標(biāo)簽,發(fā) "回復(fù)OK"。? 正常響應(yīng)。
然后連續(xù)做了 web_search(失敗但沒卡死)、web_fetch 獲取 DeepSeek API 文檔、exec 獲取系統(tǒng)信息——全部正常完成。包括帶 tool call 的多輪對(duì)話也沒有任何問題。
6. 結(jié)果匯總
| 測(cè)試 | 環(huán)境 | 結(jié)果 |
|---|---|---|
| Non-streaming API | curl 直連 | ? |
| Streaming API | curl 直連 | ? |
| 多輪 + tool call | curl 直連 | ? |
| WebChat session | OpenClaw 4.22 + pi-ai 0.70.2 | ? 卡死 |
| WebChat session | OpenClaw 4.24 + pi-ai 0.70.2 | ? 正常 |
7. 原因分析
這次踩坑有兩個(gè)層面:
- V4 默認(rèn) thinking mode 下,stream chunk 的
delta.content全程為null(thinking 階段)或""(結(jié)束)。pi-ai 0.70.2 的detectCompat已經(jīng)為 DeepSeek 做了 thinking 適配(thinkingFormat: "deepseek"、requiresReasoningContentOnAssistantMessages: true),但 stream parser 中對(duì)delta.content的判空邏輯(line 157-159)沒有考慮到 V4 入?yún)?thinking: { type: "disabled" }仍可能在某些版本返回 thinking 格式的 chunk。OpenClaw 4.24 修復(fù)了這個(gè)——CHANGELOG 中的描述是 "thinking/replay behavior is fixed for follow-up tool-call turns"。具體修復(fù)在 OpenClaw 層面而非 pi-ai 層面(兩個(gè)版本使用的 pi-ai 都是 0.70.2)。
- 更大的教訓(xùn)是 gateway 版本和 CLI 版本是兩個(gè)不同的東西:
-
openclaw --version顯示的是全局 npm 安裝的 CLI 版本 - gateway 進(jìn)程跑的是 systemd unit 中
ExecStart指向的路徑 - 更新源碼目錄或安裝新版 npm 包后,必須手動(dòng)更新 systemd unit 的路徑
- systemd unit 中還有
Environment=OPENCLAW_SERVICE_VERSION=2026.2.23-cn這種靜態(tài)配置,升級(jí)了也不會(huì)自動(dòng)變
8. 教訓(xùn)
- 升級(jí) OpenClaw 后,用
/status或session_status確認(rèn) gateway 的實(shí)際版本,不要只看openclaw --version - 檢查 systemd unit 的
ExecStart是否指向正確的安裝路徑 - 如果 gateway 和 CLI 版本不一致,先停下所有分析,把版本對(duì)齊了再說
9. 附錄
pi-ai 相關(guān)代碼位置(openai-completions.js,0.70.2)
streamOpenAICompletions()
├── delta.content 處理 line 157-174
├── reasoning_content 處理 line 176-207
└── finish_reason 處理 line 119-125
buildParams()
├── thinkingFormat: "deepseek" line 411-415
└── reasoningEffort line 429-431
detectCompat() line 814-878
getCompat() line 880-902
convertMessages()
├── thinking block 回傳 line 598-631
└── requiresReasoningContent line 669-672
systemd unit 路徑
/root/.config/systemd/user/openclaw-gateway.service
ExecStart 需要指向你的 OpenClaw 安裝路徑。如果從 npm 全局安裝,路徑為:
ExecStart=/root/.nvm/versions/node/v22.17.0/bin/node \
/root/.nvm/versions/node/v22.17.0/lib/node_modules/openclaw/dist/index.js \
gateway --port 18789
檢查 gateway 版本
session_status() # 會(huì)話信息中的版本號(hào)
ps aux | grep gateway # 看實(shí)際跑的 node 進(jìn)程
systemctl --user cat openclaw-gateway.service # 看 ExecStart 指向
測(cè)試腳本
# 直連 API 測(cè)試
curl -s https://api.deepseek.com/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"回復(fù)OK"}],"stream":false,"max_tokens":200}'
# Streaming 測(cè)試
timeout 10 curl -s -N https://api.deepseek.com/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"回復(fù)OK"}],"stream":true,"max_tokens":100,"stream_options":{"include_usage":true}}'
10. 結(jié)論
DeepSeek V4 在 OpenClaw 4.24+ 下已經(jīng)可以正常工作。如果你也遇到類似問題,先檢查 gateway 版本。不要像我一樣花了一下午分析代碼,最后發(fā)現(xiàn)只是版本沒升級(jí)到位。