Bug:切到第三方模型后,多轮对话报 400:reasoning_text must be passed back #1780
freespace8
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
切到第三方模型后,多轮对话报 400:reasoning_text must be passed back
遇到个报错想反馈一下。
我在 dsh Web 里自定义了一个第三方供应商(走
llm-pi-ai,openai-responses 协议,deepseek-v4 系列模型,开了思考模式)。在一个会话里,我把模型从官方 DeepSeek 切到了这个第三方供应商,继续往下跑,结果带工具调用的那一步直接 400 了:比较奇怪的是:
我排查的经过
我把失败的请求从会话日志里还原出来,原样发给网关,能稳定复现这个 400。然后一个一个删消息试,最后定位到:只要请求里有一个「完整工具轮」(assistant 调了工具、工具返回了结果),而这一轮的思考内容没回传,就会 400;反过来,给每一轮都补上
{"type":"reasoning","content":[{"type":"reasoning_text","text":"..."}]}再发,就通过了。翻了翻代码,我的理解是:pi-ai 的 openai-responses 序列化只回传带它自己签名的 thinking 块(
openai-responses-shared.ts),官方deepseek-official生成的轮次没有这个签名,就被悄悄丢掉了。所以切到第三方供应商后,历史里所有官方轮次的思考内容都没了,工具轮不满足网关"必须回传 reasoning_text"的校验。官方适配器llm-deepseek是正确回传的(serialize.ts里只在工具轮带reasoning_content),llm-pi-ai这边没对齐。修改方案(代码)
①
llm-pi-ai:无签名的 reasoning 块也要回传(本贴核心,已实测通过)packages/llm/llm-pi-ai/src/replay.ts的foreignAssistant——对带工具调用的轮次,给 reasoning 块合成一个thinkingSignature(pi-ai 序列化时会把签名解析成reasoning条目原样回传):replayedAssistant里 reasoning 分支的thinkingSignature缺失时也做同样的兜底(有签名仍优先用原签名)。②
llm-deepseek:兼容 vLLM 的思考流字段(对应 #199)packages/llm/llm-deepseek/src/translate.ts一行:③ #231 的持久化丢失:还没定位到具体模块,需要对比 Web UI 和 headless 两条会话路径,确保都写入 reasoning 块和
replayState.blocks[].thinkingSignature。④ 建议加个发送前校验(防回归):思考模式开启且请求含完整工具轮时,每个工具轮必须带 reasoning 条目,否则直接报错而不是静默丢。
和 #199、#231 的关系
搜了下发现 deepseek 思考模式文档 里写了:带 tools 的请求,后续必须完整回传 reasoning_content。而 #199(vLLM 把思考流成
delta.reasoning,llm-deepseek读不到)和 #231(Web UI 会话不持久化 reasoning)报的是同一个 400,但我感觉不是同一个 bug:replayState签名都在),是序列化阶段丢的,跟 Bug: Web UI multi-turn sessions drop reasoning blocks — 400 "reasoning_text must be passed back" (openai-responses custom provider) #231 机制不一样;不过修法可以一起做,正好把整条链路补上:流解析(#199)→ 持久化(#231)→ 回传(本贴)各修一处,再加上面那个发送前校验兜底。
All reactions