issue: Consecutive tool calls are merged across steps, breaking Gemini continuation

当 Open WebUI 在原生工具调用流程里连续触发多次 tool call(尤其是“先并行搜索、再基于结果追加一次搜索”)时, convert_output_to_messages() 会把后一次的 tool call 合并进上一条 assistant 消息,导致该 call 与其 reason

快速结论:当 Open WebUI 在原生工具调用流程里连续触发多次 tool call(尤其是“先并行搜索、再基于结果追加一次搜索”)时,convert_output_to_messages() 会把后一次的 tool call 合并进上一条 assistant 消息,导致该 call 与其 reasoning_details 分离、对话顺序错乱,最终向 Gemini 发起的下一次请求被上游以 HTTP 400 拒绝。优先排查后端消息转换逻辑,而不是模型或网络本身。

适用环境:Issue 已确认的环境为 Open WebUI v0.11.4、Docker(镜像 ghcr.io/open-webui/open-webui:latest-slim)、操作系统 Debian 12;上游为 openai-compatible 网关 https://ai-gateway.vercel.sh/v1,模型 google/gemini-3.8-flash。Issue 未提供 Ollama、Python、CUDA 或显卡版本的确认信息。

最快修复方案:暂无确认的一步修复方案。Issue 中提出并在本地回放中验证有效的方向是:在 backend/open_webui/utils/misc.py 收集新的有效 call 之前,先 flush 上一步的 tool 输出,即在 function_call 分支里调用 flush_tool_outputs() 和 flush_tool_images();评论中维护者标注该问题已在 dev 分支修复(test dev / fixed in dev),未说明具体版本号。

注意事项:上述补丁作者的验证属于精简的、非流式的回放(minimal search_web 声明,并非完整 WebUI 请求抓取),只能证明“续接恢复、模型会继续请求工具调用”,尚未完成从浏览器完整跑到最终回答的端到端验证。不要把回放中的 HTTP 200 直接等同于线上问题已完全消除。另外该 issue 被标记为可能与 #31588 重复。

问题场景

用户在 Open WebUI 中运行原生工具调用(native tool calling)工作流,模型为 Gemini 系列(google/gemini-3.8-flash),触发条件是模型先发起并行的多个 web search,再在读取这些结果后追加第三次搜索。工具本身全部执行成功,但随后的下一步模型请求失败,报 HTTP 400。

触发提示词原文为:

Tell me about Claude Opus 5.5 and compare it with GPT 6 Astra.

该问题在最新 release 和提交时的 dev 分支上均可复现。

报错原文

Upstream openai-compatible request failed: HTTP 400 (upstream_error)
url=https://ai-gateway.vercel.sh/v1 model=google/gemini-3.8-flash
code=AI_APICallError message=Request contains an invalid argument.

本地可复现的最小断言失败如下(同一 issue 提供的 snippet):

from open_webui.utils.misc import convert_output_to_messages


def call(id):
    return {"type": "function_call", "call_id": id, "name": "search_web",
            "arguments": '{}', "status": "completed"}


def result(id):
    return {"type": "function_call_output", "call_id": id,
            "output": [{"type": "input_text", "text": "result " + id}]}


messages = convert_output_to_messages(
    [call("A"), result("A"), call("B"), result("B")], raw=True
)
print(messages)
assert [c["id"] for c in messages[0]["tool_calls"]] == ["A"]

# AssertionError: 第一条 assistant 消息中同时包含 A 和 B

原因分析

核心原因是 convert_output_to_messages() 在重建消息历史时的边界处理有误:当上一步的 tool result 仍处于缓冲状态时,后续出现的 function_call 会被合并进上一条 assistant 消息,而不是开启一条新的 assistant 消息。

这带来两个后果:

  • 后一个 call(示例中的 C)被搬到错误的 assistant 消息里,与其对应的 reasoning_details(示例中的 S2)分离;
  • 对话序列被改变,Gemini 严格的请求校验不接受这种 assistant/tool 配对,于是返回 Request contains an invalid argument.。

换句话说,这不是模型或网关的偶发错误,而是 Open WebUI 侧重组历史后产生的非法请求结构。模型行为本身是非确定性的,但 issue 提供的 snippet 可以在无网络、无 reasoning metadata 的情况下稳定复现边界 bug。

可能相关(issue 评论中机器人列出的关联 issue):

  • #31588:连续 tool call 被合并进更早的 assistant 消息,破坏 prompt cache,属于同一类消息边界 bug;
  • #24758:convert_output_to_messages 在 function_call_output 缺失时产生 orphan tool_calls;
  • #28385:Gemini function calling 场景下中间 reasoning 与 tool-call 内容的处理问题。

环境排查

  • 确认 Open WebUI 版本与部署方式:issue 中为 v0.11.4、Docker、ghcr.io/open-webui/open-webui:latest-slim;如使用其他版本请对照是否已包含 dev 分支的修复。
  • 确认是否运行在 Debian 12(或同类 Linux 环境)。
  • 确认上游网关地址与模型名称,issue 中为 https://ai-gateway.vercel.sh/v1 + google/gemini-3.8-flash。
  • 确认是否使用原生工具调用(native tool calling)且存在“并行调用 + 基于结果再次调用”的连续调用模式。
  • 检查后端 backend/open_webui/utils/misc.py 中 convert_output_to_messages() 的 function_call 分支实现。
  • Issue 未确认 Ollama、Python、CUDA、PyTorch、显卡版本,这些不必作为必要排查项,除非你的环境另有差异。

解决步骤

  1. 先确认问题定位:在后端 Python 环境运行 issue 给出的 convert_output_to_messages snippet。若 assert [c["id"] for c in messages[0]["tool_calls"]] == ["A"] 失败(第一条 assistant 消息含 A 和 B),说明命中的就是本 issue 的消息合并边界 bug。
  2. 升级或切换到包含修复的构建。issue 评论中维护者标注该问题“test dev / fixed in dev”,即修复已进入 dev 分支但未给出具体发布版本号;可优先尝试 dev 构建或后续包含该修复的正式版本。
  3. 如暂时无法升级,可优先尝试 issue 提出的补丁方向:在 backend/open_webui/utils/misc.py 的 function_call 分支中,在收集新的有效 call 之前先 flush 上一步的输出,即加入:
             elif item_type == 'function_call':
                 if item.get('call_id') not in function_call_ids:
                     continue
    
    +            flush_tool_outputs()
    +            flush_tool_images()
    
                 # Collect tool calls to batch into assistant message

    该 diff 来自 issue 作者,属于“可优先尝试”的修复思路,不是官方发布的确认方案。

  4. 修改后重启 Open WebUI 服务,重复触发同类工作流(并行搜索后再追加一次搜索),观察是否仍出现 HTTP 400。

验证方法

分两层验证:

  • 单元层:重新运行 issue 的 snippet,断言通过,即第一条 assistant 消息的 tool_calls 只包含 A,说明后一个 call 不再被合并到上一条消息。
  • 接口层:复现相同的用户消息、工具结果与 reasoning metadata,再次向同一网关和模型发起请求。issue 作者的回放结果显示:Original converter 返回 HTTP 400(Request contains an invalid argument.),Patched converter 返回 HTTP 200 且模型继续请求工具调用。
  • 端到端:issue 明确指出“完整浏览器驱动、跑到最终回答”的验证在报告时仍待完成。若你在自己的环境修复,建议走完整 UI 流程直到模型给出最终回答,确认不再出现 400,才视为完全验证。

参考来源

open-webui/open-webui #31854

关联讨论:#31588、#24758、#28385

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 27088

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注