feat: web pages are downloaded twice when the model fetches or attaches them

当 Open WebUI 通过 fetch_url 抓取普通 HTML 网页时,每次抓取会对同一 URL 发两次 GET:一次只读 Content-Type,丢弃响应后又由 Web loader 完整下载一遍;Attach Webpage 路径会再多一次检查,因此同一页面可被请求三次。该问题属于确认

快速结论:当 Open WebUI 通过 fetch_url 抓取普通 HTML 网页时,每次抓取会对同一 URL 发两次 GET:一次只读 Content-Type,丢弃响应后又由 Web loader 完整下载一遍;Attach Webpage 路径会再多一次检查,因此同一页面可被请求三次。该问题属于确认的性能/行为缺陷,不是配置错误,优先关注抓取链路与版本是否包含修复。

适用环境:Open WebUI v0.12.2(Docker,使用 safe_web / 默认 web loader)。Issue 中提及 retrieval/utils.py 与 retrieval/web/utils.py 在 v0.12.2 和 dev 上内容一致,但报告者只实际运行了 v0.12.2,未在 dev 上验证。未提供操作系统、Python、CUDA、显卡、PyTorch 等环境信息。

最快修复方案:暂无确认的一步修复方案。Issue 中给出的方向是:对默认 loader 复用首次探测响应,在流式读取到 Content-Type 后直接走 HTML 解析路径;该修复仍在开发中,未在 Issue 内确认完成。可优先尝试升级到包含相关 PR 修复的版本,但 Issue 未给出已验证的版本号。

注意事项:复用探测响应只能适用于默认 safe_web loader。Playwright、Firecrawl、Tavily、Exa、Web IQ 和外部 loader 由浏览器或第三方服务自行抓取,首次请求仍需保留。不能简单把探测请求的响应直接当作页面内容复用,因为探测请求可能不带 USER_AGENT 和浏览器类请求头,也忽略 SSL 校验、代理与超时设置;例如 Wikimedia 对探测请求返回 403,而 loader 自己的请求返回 200。正确的是让单次请求成为 loader 自身配置下的请求,并以流式方式读到 Content-Type 后再决定 HTML 或文档提取路径,同时保留大小限制。

问题场景

在 Open WebUI 中使用模型调用 fetch_url 抓取网页,或在聊天中 Attach Webpage 附加网页时触发。普通 HTML 页面会先由 get_content_from_url 发起一次流式 GET,仅用于读取 Content-Type(_get_content_from_url_sync),响应随后被丢弃;如果判定为文本,loader 再完整下载同一页面。Attach Webpage 还会在前置检查中多发一次请求,因此同一附加页面可能被请求三次。报告者在 otel trace 中观察到 10 个不同 URL 中有 8 个被请求两次,另外 2 个在探测阶段返回 400。

报错原文

feat: web pages are downloaded twice when the model fetches or attaches them

fetch_url does two GET requests to the same URL for normal html pages.
get_content_from_url does a streamed GET first just to read the Content-Type
(_get_content_from_url_sync in retrieval/utils.py), and then, if it's text,
the loader fetches the whole page again. The probe response is just dropped
in that case.

原因分析

最可能的原因:抓取流程为了区分文本页面与 PDF/DOCX 等二进制文件,先做一次 Content-Type 探测请求;探测完成后,文本分支没有复用该响应,而是交给 get_loader 重新抓取。因此普通 HTML 页面固定产生两次 GET,Attach Webpage 路径再叠加一次前置检查。该设计中的探测请求还承担 SSRF 防护,不能直接删除;Issue 中提到 #25775 曾加固该探测。

环境排查

  • 确认 Open WebUI 版本:报告环境为 v0.12.2(Docker);Issue 中未确认 dev 分支上的实际运行结果。
  • 确认使用的 web loader 引擎:问题影响默认 safe_web loader;Playwright、Firecrawl、Tavily、Exa、Web IQ 和外部 loader 的抓取方式不同,探测请求仍需保留。
  • 确认触发路径:模型调用 fetch_url,或使用 Attach Webpage 附加网页。
  • 查看 otel trace 中同一 URL 的请求次数与耗时,区分探测请求和 loader 请求。
  • 检查目标站点是否限流:重复请求可能导致 429;Issue 中报告了两次请求均失败的情况。
  • Issue 未提供 Python、CUDA、PyTorch、显卡、节点或依赖版本信息,无需据此排查。

解决步骤

  1. 先通过 otel trace 或访问日志确认同一页面确实出现两次 GET,且一次仅用于读取 Content-Type,另一次为完整下载;Attach Webpage 场景确认是否出现三次请求。
  2. 确认所用的 web loader 引擎是否为默认 safe_web。若为 Playwright、Firecrawl、Tavily、Exa、Web IQ 或外部 loader,该重复请求属于其抓取模型的一部分,不能按“复用首次响应”简单处理。
  3. 关注 Issue 中关联的修复方向与 PR(#32523、#32524),确认所用版本是否已包含相应改动。Issue 明确说明第二次 GET 的复用仍在开发中,未给出可直接执行的一步修复命令。
  4. 在修复可用前,可优先尝试减少单轮对话中连续抓取多个页面的频率,以降低触发站点限流和 429 的概率;这不是 Issue 中验证过的正式修复方案。
  5. 如需自行修改代码,应确保单次请求使用 loader 自身的请求设置(USER_AGENT、浏览器类请求头、SSL 校验、代理、超时),流式读取到 Content-Type 后再分流:文本走 HTML 解析,文件走文档提取并保留大小限制;探测失败时回退到 loader。该方案在 Issue 中尚未确认合入。

验证方法

对同一 URL 抓取后检查 otel trace 或服务端访问日志:普通 HTML 页面应只出现一次完整 GET,Attach Webpage 不应额外产生重复下载请求;抓取耗时相应减少,目标站点不再收到重复命中。同时确认页面内容正常返回、USER_AGENT 等请求设置生效、SSL/代理/超时配置未被绕过,PDF/DOCX 等文件仍能进入文档提取路径并受大小限制约束。Issue 中报告的单次抓取约 0.6–0.9 秒,重复请求使每次 fetch_url 多出约 0.65 秒,可作为对照参考。

参考来源

open-webui/open-webui #32521

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29324

发表回复

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