快速结论:当你在 Open WebUI 中挂载多个外部知识库(Qdrant / Milvus / pgvector)并开启 RAG 查询改写时,外部检索会按“每个生成查询串行 + 每个知识库串行”执行,延迟按知识库数 × 查询数 × 单次检索耗时线性叠加。核心报错描述为 perf: external knowledge bases fetch every generated query but keep only the first query’s results,优先排查检索调度链路是否仍是串行循环,而不是单个后端性能问题。
适用环境:Open WebUI(Issue 讨论涉及 dev 分支与 v0.13.2 部署);外部知识库为 Qdrant,另有 Milvus / pgvector 同一签名路径;检索后端使用 llama.cpp(--parallel 8)并叠加 cross-encoder 重排。Issue 未明确给出 Python、CUDA、显卡型号,故不补写。
最快修复方案:暂无确认的一步修复方案。Issue 中给出的参考补丁是在 backend/open_webui/retrieval/external.py 对生成的查询用 asyncio.gather 并发检索,并在 backend/open_webui/retrieval/utils.py 的 get_sources_from_items 中按位置调度各知识库检索后统一 gather;可优先尝试,但需自行验证。
注意事项:该补丁无新增配置开关、无新增 import,对外语义要求保持结果顺序、引用顺序与首个失败即中断的行为不变;Issue 明确说明本仓库代码 PR 需维护者明确要求,未经请求的 PR 会被机器人自动关闭,因此建议先在本地部署验证并把前后耗时对比作为评论提交到 Issue,而不是直接提 PR。
问题场景
用户在 Open WebUI 中同时挂载多个外部知识库,并启用默认的 RAG 查询改写(一条用户消息生成多条改写查询)。同一请求中,内置(internal)collection 路径已经是并发的,但外部知识库路径存在两层串行:
retrieve_external_knowledge_for_connection(backend/open_webui/retrieval/external.py)对每条生成查询依次执行:embed → 从外部向量库拉取 → 下一条。get_sources_from_items(backend/open_webui/retrieval/utils.py)对每个挂载的知识库依次await,前一个检索完成才开始下一个。
结果是检索延迟按 len(knowledge_bases) × len(queries) × per-call latency 放大,并完全落在首 token 的关键路径上。Issue 在 2026-10-25 的生产部署上测得:单次外部检索(query embedding + 向量库拉取 + 重排)约 0.6 s,4 个并发合计约 1.0 s;3 个知识库 × 5 条生成查询串行约 9–15 s,并发约 2–4 s。维护者后续给出的对比数据为:3 库场景 1.62 s 对比串行基线 4.49 s,5 库压测 4.01 s 对比串行 14.72 s,且无重排回退。
报错原文
perf: external knowledge bases fetch every generated query but keep only the first query's results
原因分析
最可能的原因是检索调度方式而非后端能力不足:外部知识库路径在“每条生成查询”和“每个知识库”两个层级都是串行循环,而同一请求中的内置 collection 路径已使用 asyncio.gather 并发扇出(query_collection 一次性 embed 全部查询并对 collection × query 组合 gather;query_collection_with_hybrid_search 并发预取 collection 并并发执行所有组合)。Issue 的测量也表明嵌入模型、向量库和重排后端本身可以近乎零成本地吸收并发。注意:问题标题中的“keep only the first query’s results”其字面含义在讨论中未被单独复现或确认,可能原因指向检索循环的调度结构,具体以你部署中的实际日志和返回结果为准。
环境排查
- 确认 Open WebUI 版本:讨论中出现
dev分支与 v0.13.2 部署,不同版本对外部检索调度实现可能不同。 - 确认是否加载了 #33704 相关修复(维护者称 v0.13.2 已包含)。
- 确认外部知识库类型与数量,以及是否同时混挂内置 collection。
- 确认 RAG 查询改写是否开启及生成的查询条数。
- 确认后面检索后端(llama.cpp 的
--parallel设置、向量库、cross-encoder 重排)是否已能承受并发请求。 - 接口层面可检查
retrieval/external.py与retrieval/utils.py是否仍为串行for循环 + 逐个await。 - Python、CUDA、PyTorch、显卡型号在 Issue 中无明确证据,不做要求。
解决步骤
- 先在自有部署上建立基线:挂载多个外部知识库、开启查询改写,记录从检索开始到首 token 的耗时,以及单次外部检索耗时,作为前后对比基准。
- 记录当前返回结果与引用顺序(citation order),作为并发改造后的回归对照。
- 参考 Issue 中的补丁:在
retrieve_external_knowledge_for_connection中对全部生成查询使用asyncio.gather调用 provider 的 retrieve 函数(Qdrant / Milvus / pgvector 共享同一签名),再按原始查询顺序拼接 chunk 列表。 - 在
get_sources_from_items中,在循环位置为每个外部检索创建 task 并放入query_results占位,循环结束后统一 gather,按记录位置回填结果。 - 保持
asyncio.gather不带return_exceptions,使首个失败与原串行代码一样中止整个检索。 - 按仓库贡献政策,不要直接提交未经请求的代码 PR;把验证结果与耗时数据作为评论发到 Issue,待维护者明确要求后再向
dev提 PR。
验证方法
在相同的知识库数量与查询条数下重复测试:确认检索总耗时明显下降(参照 Issue 中 3 库 1.62 s 对比 4.49 s、5 库 4.01 s 对比 14.72 s 的量级);确认返回的 chunk 内容与串行版本逐字节一致、引用顺序与 extracted_collections 顺序不变;注入一次检索失败,确认整体行为为首次失败即中止;检查重排是否出现回退。若耗时未改善,说明改动未生效或并发仍在其他层级被串行化,应回到环境排查逐项确认。
参考来源
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。


![[eager MOE] Selected expert IDs should probably not be treated as 0-d GPU tensors](https://www.chat-gpts.plus/wp-content/uploads/2026/11/49190-31d17efb-768x403.jpg)