快速结论:当 Open WebUI 的聊天历史里残留一条“空助手占位消息”(content: ""、done: false、无 output、无 tool_calls)时,后端重建历史会把它当作正常 assistant 消息重放给上游,严格的 OpenAI 兼容提供商会因此拒绝本次及之后所有请求,导致该会话被永久卡死。优先排查历史链路上是否被写入过空助手节点。
适用环境:Open WebUI v0.9.5(Docker,官方 ghcr.io/open-webui/open-webui:main 镜像,Docker Desktop);上游 dev 分支 5d9a09a88a9094ebfcd249340be3aaee544b34d0 复现相同行为;macOS Sonoma 14(Darwin 25.4.0);使用 OpenAI 兼容提供商(非 Ollama 侧问题,Ollama 版本不适用)。
最快修复方案:Issue 中报告者明确指出这是历史重建路径的缺陷,临时绕过办法是改走 LiteLLM 代理接入上游,让 LiteLLM 侧处理空 assistant 消息。数据库层面的修复(直接编辑 webui.db,从 chat.history.messages 删除空助手消息并修补相邻节点的 childrenIds / currentId)属于极端自救手段,并不适合普通终端用户。
注意事项:Issue 中 #23176 曾于 2026-04-14 关闭,但同样的空占位持久化行为在 v0.9.5 和上游 dev 上依然存在,说明该关闭并未真正阻止空行被写入或被上游重放。#29169 相关改动在最新 dev(7e6c8d7b6)上测试时,空 assistant 消息仍会被发送给上游;虽然报告者测试的三个提供商的四个模型都没有拒绝,但并不代表严格校验的提供商会放行。LiteLLM 绕过方式仅在 Issue 中被提及,未提供详细配置验证。
问题场景
在 Open WebUI(Docker 部署,v0.9.5)中与本地 Ollama 模型对话时,如果在模型开始输出任何文本之前点击 Stop,该条被中断的回复会以空内容(无错误状态)保存为 assistant 消息。之后把该会话切换到某个 OpenAI 兼容连接下的模型并继续发送消息时,后端在重建聊天历史时会沿着 currentId 的父链走,把这条空占位消息作为 {"role": "assistant", "content": ""} 重放给上游提供商。严格的 OpenAI 兼容上游(服务端 schema 拒绝空 content 且无 tool_calls 的 assistant 消息)会直接拒绝该请求。由于空占位每次都会被重放,会话中后续每一次补全请求都会以同样方式失败,聊天实际上被永久破坏。
报错原文
bug: empty assistant placeholders are replayed to the provider and permanently break the chat
the message at position 15 with role 'assistant' must not be empty
原因分析
最可能的原因在聊天历史重建路径(load_messages_from_db() 相关代码路径):后端在组装发送给上游的消息数组时,只过滤掉带有 error 状态的空 assistant 消息,而没有过滤掉“无可用载荷”的 assistant 消息——即 content 为空、没有 output items、也没有 tool_calls 的节点。被中断或孤立产生的 assistant 占位节点会持久化进 chat.history.messages,并在每次重建历史时被重新纳入 payload。因为该节点位于 currentId 行走的父链上,从更早轮次重新生成也无法绕过它。Issue 交叉引用的 #23176 描述了同一类空占位(前端观察角度),本次 Issue 是其后端后果;#22327 涉及同一 load_messages_from_db() 路径但属于不同 bug 类别,仅说明该历史重建路径测试覆盖不足。
环境排查
- 确认 Open WebUI 版本,Issue 中确认受影响版本为 v0.9.5,上游
dev于5d9a09a88a9094ebfcd249340be3aaee544b34d0亦复现;后续在dev(7e6c8d7b6)复测时空消息仍被发送。 - 确认部署方式:Docker,官方
ghcr.io/open-webui/open-webui:main镜像。 - 确认宿主操作系统:macOS Sonoma 14(Darwin 25.4.0),Docker Desktop。
- 确认上游提供商类型:问题出现在 OpenAI 兼容提供商,与 Ollama 自身版本无关(Issue 中标注 Ollama 版本不适用)。
- 检查会话数据库
webui.db中对应 chat 的chat.history.messages,重点找content为空且无tool_calls、无output的 assistant 节点,以及其相邻节点的childrenIds/currentId指向。 - 浏览器无影响,症状在服务端(发往上游的 payload),与浏览器类型无关。
解决步骤
- 先确认症状模式:该会话切到严格 OpenAI 兼容提供商后,是否每一次新提交都以同样的“position N with role ‘assistant’ must not be empty”报错失败,且从更早轮次重新生成也无济于事。这是空占位被反复重放的典型特征。
- 临时绕过(可优先尝试):按 Issue 中报告者的建议,改经 LiteLLM 接入该上游,由 LiteLLM 侧承担消息适配,避免严格 schema 直接拒绝空 assistant 消息。注意这是绕过而非修复。
- 数据库层面自救(仅限能直接访问数据的自托管场景):定位
webui.db,在对应 chat 的chat.history.messages中移除空 assistant 占位消息,并同步修补相邻节点的childrenIds与currentId,使父链不再经过该节点。操作前务必备份数据库。Issue 明确指出这不是普通终端用户可以使用的恢复路径。 - 跟踪代码修复:本 Issue 相关改动见 PR #29169。但在最新
dev(7e6c8d7b6)上,空 assistant 消息仍会被发送给上游;报告者测试的三个提供商的四个模型未拒绝,因此该 PR 是否彻底解决严格提供商的拒绝行为尚无定论。 - 如果正在评估是否升级:由于 #23176 关闭后问题仍在 v0.9.5 与上游 dev 上出现,不要仅凭该 Issue 已关闭判断问题已修复,应以实际使用的严格上游是否仍报错为准。
验证方法
复现路径:在与本地 Ollama 模型的新会话中,在模型输出任何文本之前点击 Stop,使该回复以空内容保存;然后把会话切换到 OpenAI 兼容连接下的模型,再发送一条消息。如果后端仍把空 assistant 作为 {"role": "assistant", "content": ""} 发送,严格提供商会再次以“must not be empty”拒绝。要验证问题是否被修复,应确认该空占位不再出现在发往上游的 payload 中,并确认后续请求能够正常获得补全响应;仅凭某个提供商未报错不足以下结论,因为部分提供商并不会拒绝空 assistant 消息。
参考来源
相关:#23176、#22327、#22882、#24157、#24714;相关 PR:#29169
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。
![RuntimeError: Worker failed with error 'MLA kv_data_type torch.uint8 is not supported. Supported dtypes: [torch.float16, torch.bfloat16, torch.float8_e4m3fn].', please check the stack trace abov](https://www.chat-gpts.plus/wp-content/uploads/2026/10/57713-741c6632-768x403.jpg)

