Errors in tool-call/code-interpreter continuation rounds are silently swallowed (empty assistant message, no error shown)

在 Open WebUI 中,当模型在多轮原生工具调用(tool-call)或代码解释器(code-interpreter)的“续聊轮次”(continuation round)中抛出异常时,错误会被 silently swallowed(静默吞掉),导致聊天以空的助手消息结束,前端不显示任何错误,

快速结论:在 Open WebUI 中,当模型在多轮原生工具调用(tool-call)或代码解释器(code-interpreter)的“续聊轮次”(continuation round)中抛出异常时,错误会被 silently swallowed(静默吞掉),导致聊天以空的助手消息结束,前端不显示任何错误,数据库也不会记录错误字段。优先排查后端 streaming_chat_response_handler 中 continuation 循环的 except 块是否吞掉了异常。

适用环境:Docker 官方镜像(ghcr.io/open-webui/open-webui);Open WebUI v0.10.2(Issue 作者确认当前 dev 分支代码未变动);OpenAI 兼容后端(通过代理,如 LiteLLM + AWS Bedrock);Linux(容器化部署,AWS ECS)。Ollama 不适用(n/a)。

最快修复方案:暂无确认的一步修复方案。Issue 已关闭并标记为“应在 dev 分支修复”的 PR(#27426),该 PR 覆盖了“异常被抛出”的场景,但 Issue 作者在其后的评论中确认:当 OpenAI 兼容提供商返回 HTTP 错误(而非抛出异常)时,代码走的是 else: break 分支,except 不会执行,空消息问题依旧存在。此新问题已另开 Issue #28633 追踪。

注意事项:PR #27426 的修复只覆盖“异常被抛出”的情况,不覆盖“上游返回 HTTP 错误但不抛异常”的情况。如果你在代理场景(如 LiteLLM/Bedrock)遇到此问题,升级到包含 #27426 的 dev 版本可能无法完全解决,需关注 #28633 的后续修复。

问题场景

用户通过 Docker 镜像部署 Open WebUI,使用 OpenAI 兼容后端(经由 LiteLLM + AWS Bedrock 代理),并启用了原生函数调用(native function calling)和工具(如内置 web search)。当模型在首轮触发工具调用后,第二轮(continuation round)的模型请求被代理拒绝(例如 Bedrock guardrail 返回 HTTP 400),导致聊天最终以 content=''done=true 的“静默空消息”结束,前端无任何错误提示,数据库也无 error 字段,除非开启 GLOBAL_LOG_LEVEL=DEBUG 否则日志无任何输出。

报错原文

Errors in tool-call/code-interpreter continuation rounds are silently swallowed (empty assistant message, no error shown)
content=''
done=true
{type: "message", status: "completed", text: ""}
except Exception as e:
    log.debug(e)
    break

原因分析

根本原因位于 backend/open_webui/utils/middleware.pystreaming_chat_response_handler 函数中,原生工具调用(tool-call)continuation 循环将 generate_chat_completion / stream_body_handler 包裹在如下代码块内:

except Exception as e:
    log.debug(e)
    break

因此,continuation 轮次(第 2 轮及以后)中抛出的任何异常都会被吞掉。代码解释器(code-interpreter)的 continuation 逻辑(约第 5133 行和 5336 行附近的 except 块)也存在相同模式。首轮(工具调用前)生成的文本会保留,导致失败看起来像“模型回答了空内容”,且无任何诊断线索。

此外,Issue 作者在评论中补充了第二种路径:当 OpenAI 兼容提供商返回 HTTP 错误(而非抛出异常)时,代码会走 else: break 分支,except 永远不执行,因此即便修复了“异常被抛出”的场景,空消息问题在 HTTP 错误场景下依然存在。这属于一个独立但同源的问题。

环境排查

  • 确认 Open WebUI 版本是否为 v0.10.2 或更早(Issue 作者确认当前 dev 分支代码未变);若为新版本,需确认 streaming_chat_response_handler 中 continuation 循环的 except 块是否已修改。
  • 确认部署方式是否为 Docker(官方镜像 ghcr.io/open-webui/open-webui),以及是否使用 OpenAI 兼容后端(非 Ollama)。
  • 确认代理层(如 LiteLLM、AWS Bedrock guardrail)是否会返回 4xx/5xx 错误;该错误是否会被上层代码当作文本流而非异常处理。
  • 体验时建议开启 GLOBAL_LOG_LEVEL=DEBUG,观察是否在日志中看到 log.debug(e) 输出的被吞异常内容。
  • 检查聊天数据库,确认最终消息的 error 字段是否为空。

解决步骤

  1. 定位问题:在聊天触发工具调用后,打开后端日志(设置 GLOBAL_LOG_LEVEL=DEBUG),确认是否有被 log.debug(e) 吞掉的异常信息;同时检查聊天记录中最终助手消息的 contenterror 字段是否为空。
  2. 临时规避(可优先尝试):如果代理层(如 Bedrock guardrail)触发拒绝,可考虑调整代理策略或关闭相关防护规则,避免对 continuation 请求返回 HTTP 400;或者暂时关闭原生函数调用,改用非原生工具调用模式。
  3. 升级验证:如果当前版本低于 dev,可尝试升级到包含 PR #27426 的 dev 构建(commit 31d08d5 之前,已包含 8ab44ed3b),该 PR 修复了“异常被抛出”的场景。
  4. 注意残留问题:升级后若仍遇到空消息(尤其是代理返回 HTTP 错误时),请确认是否命中 #28633 描述的“else: break”分支——该场景未被 PR #27426 覆盖,需关注后续修复或讨论。
  5. 反馈:如果在新版本中仍复现,请补充代理返回的具体 HTTP 状态码和响应内容,便于后续追踪。

验证方法

重现触发步骤(启用原生函数调用 + 工具 => 让代理在 continuation 轮次拒绝请求),确认以下三点均为真即可认定问题已解决:

  • 前端聊天界面显示明确的错误消息,而非空内容结尾;
  • 数据库中的助手消息带有 error 字段;
  • 即使不开启 DEBUG 日志,也能在默认日志级别下看到异常记录(log.exception 或类似输出)。

参考来源

open-webui/open-webui #27411

相关 Issue/PR:#27426(修复“异常被抛出”场景)、#28633(HTTP 错误未覆盖的后续问题)、#27363(同类症状)、#19943(Code Interpreter 相关问题)。

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 18743

发表回复

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