做 RAG 的人大多有个盲区:眼睛只盯着文字。

你花了两周调 chunk size,换了三种 embedding 模型,reranker 也加上了——《Rerank 在 RAG 中的角色:Bi-Encoder vs Cross-Encoder》里讲的那些优化你全做了。但回头一看,技术文档里的截图、架构图、参数表格,这些图片承载的信息,你的系统压根没碰。

这不是小问题。kapa.ai 的团队最近在 Hacker News 上分享了他们的生产实践(89 points),标题直白:How we index images for RAG。他们服务 200+ 客户,知识库里有数百万张图片,每天处理百万级查询。这篇文章把他们的方案拆开来看,顺便聊聊 ColPali 等另一条路线,以及你到底该选哪条。

图片在技术文档里到底干了什么

kapa.ai 把文档图片分成两类,这个分类非常实用。

说明型(illustrative):文字说"点击设置图标",旁边的截图标出了图标在哪、长什么样。图片让答案更直观,但信息本身在文字里也有——用户不看图也能做事,只是要多找一会儿。

承重型(load-bearing):接线图、参数规格表、认证矩阵、颜色可选表——这些图里的数值只存在于图片中。你不看图,就根本不知道答案。

他们跑了上千条真实客户问题验证:有图片上下文时,LLM 评委(McNemar 检验,p < 0.05)显著偏好带图片的答案。效果不是微调能弥补的那种——是用户能感知到的质变。

但问题来了:怎么把这些图片喂给 LLM?

查询时看图:一个看起来对、实际上贵到用不起的方案

直觉反应是:检索到相关 chunk 后,把它们引用的图片一起丢给多模态模型(GPT-5.1、Claude 4.6 Sonnet 等)。kapa.ai 测试了这个方案,发现三个结构性问题:

1. 贵得离谱。 原始图片让 GPT 单次查询成本增加 27%,Claude 增加 51%(Claude 把一张图编码成约 975 tokens,GPT 约 716)。kapa.ai 每天百万级查询,这笔钱根本花不起。

2. 塞不进去。 一个典型问题检索 10-30 个 chunk,平均引用 20-30 张图片,长尾能到 130 张。Claude 的 payload 上限 30 MB,OpenAI 的 50 MB——超过 20 张图就撞墙了。

3. CLIP 式嵌入在技术文档上失效。 CLIP 这类视觉嵌入模型擅长的是"这是一只猫"还是"这是一条狗",不是"这个表格第三行的耐火等级是多少"。短技术查询(“how do I configure X”)和图表细节之间,语义鸿沟太大。

kapa.ai 的结论很干脆:这些不是工程细节能调掉的问题,是今天多模态生态的结构性限制。于是他们换了一条路。

索引时描述一次,查询时当文字检索

核心思路反过来:重活在索引时干一次,查询时完全不碰图片。

流程很清晰:

  1. 索引阶段:用视觉语言模型(VLM)给每张图片生成一段文字描述(caption)
  2. 存储:caption 作为独立的文本 chunk 存进向量数据库
  3. 查询阶段:检索器照常做文本检索,如果 caption chunk 被命中,就把它放进上下文

这样查询时的成本几乎不增加(纯文本检索),延迟也几乎不变。“看图"这个昂贵操作只发生一次——在文档摄入的时候。

听起来简单,但生产环境里有三个关键细节决定了成败。

关键细节一:大多数图片是垃圾,过滤是第一步

你不能给知识库里的每张图都生成描述。Logo、头像、社交预览图、装饰性横幅——这些占了大多数。

kapa.ai 用启发式规则做第一轮过滤(丢掉不支持的格式、过小的图片等),然后用分类器做第二轮过滤。在明确的图片上,分类器准确率 96.8%(F1 0.974),但在模糊图片上准确率暴跌到 59.8%。

原因很根本:一张倒计时截图,你分不清它是装饰性横幅还是功能性内容。图片分类在边界情况下就是很难。

关键细节二:上下文比模型大小更重要

给 VLM 喂图片时,把图片前后的段落一起喂进去,caption 质量会大幅提升。没有上下文时,一个文件上传对话框的描述是"一个有文件选择按钮的网页”;有上下文后,描述变成"项目配置页面中的文件上传对话框,用于导入自定义规则集"。

另一个有意思的发现:贵的模型几乎不值得。 他们测试了五个模型,从 Claude 4.6 Sonnet 到 GPT-5.4 nano。小型模型(GPT-5.4 mini)生成的 caption 和四倍价格的大模型几乎无法区分。

这很符合直觉——描述一张截图不需要博士级推理,需要的是看清图片内容并用准确的语言表述。小模型就够了。

关键细节三:独立存储优于内联替换

两种存储 caption 的方式:

  • 内联(inline):替换图片的 alt text,让 caption 和原文混在一起
  • 独立(separate):每个 caption 作为单独的 chunk 存储,原文 chunk 保持不变

直觉告诉你会内联更好——caption 和上下文紧挨着嘛。但实际测试中,独立存储在成本和图片使用率上都赢了。

原因:内联 caption 会膨胀每个它所在的 chunk,而这些 chunk 每次查询都要发送。独立 chunk 只在相关时才被检索到,不相关的查询根本不会为它付 token 费。

生产环境数据

端到端测试(三个客户项目,GPT-5.1 和 Claude 4.6 Sonnet):

指标纯文本基线加入图片 caption
图片被引用比例0%10%-64%
答案质量(LLM 评委)基线显著更好(p < 0.05)
单次查询成本增加1%-6%
延迟(首 token 时间)亚秒级增加
图片放置正确率94%-99%

用 1%-6% 的成本换来 10%-64% 的图片引用率提升,且图片放置正确率 94%-99%。这笔账怎么算都划算。

另一条路:ColPali 的视觉检索方案

kapa.ai 的方案是"把图片变成文字再检索"。ColPali(2024,illuin-tech,2652 stars)走了完全不同的路:直接在视觉空间做检索

ColPali 用 PaliGemma-3B 的 ViT 输出作为多向量表示,按 ColBERT 的方式训练。它跳过了 OCR 和版面分析,直接把文档的视觉特征编码成嵌入,查询时在视觉空间里做相似度匹配。

ColPali 的优势在于:

  • 不需要 OCR 或版面识别管线——端到端一个模型搞定
  • 对图表、表格等视觉信息天然友好——不像 CLIP 那样丢失细节
  • 在 ViDoRe benchmark 上表现优异

但 kapa.ai 在生产中对 CLIP 类方法的批评同样适用于 ColPali:

  • 短查询 vs 长文档的语义鸿沟——用户问"how do I configure X",和一张架构截图之间的匹配,视觉嵌入很难做好
  • 推理成本——每次查询都要对所有候选文档做视觉编码比对,在百万级查询场景下不现实
  • 工程复杂度——需要维护专门的视觉检索基础设施

说白了,ColPali 更适合文档问答场景(比如你有一个 PDF 库,每份文档都要理解图表),而 kapa.ai 的方案更适合大规模知识库检索场景(技术文档 RAG,查询量大,成本敏感)。

实操建议:你的 RAG 管线怎么选

根据你的场景,选择不同的路线:

场景 A:技术文档 RAG,查询量大(>1 万次/天) → kapa.ai 方案:索引时用 VLM 生成 caption,独立 chunk 存储,查询走纯文本。成本可控,延迟低,效果有保障。

场景 B:文档问答,查询量小,但文档图表密集 → ColPali 方案:直接在视觉空间检索,跳过 OCR 管线。适合研究、法律、金融等需要理解复杂图表的领域。

场景 C:预算有限,只想快速验证 → 先用 OCR + 图片 alt text 提取文字,和文本 chunk 一起存。效果不如前两种,但零额外成本。

场景 D:已有成熟文本 RAG,只想补上图片能力 → 按 kapa.ai 的方案做增量:给已有文档的图片批量生成 caption,作为新 chunk 加入向量库。不需要改动现有管线。

几个容易踩的坑

1. 别用大模型生成 caption。 前面说了,小模型就够。用 GPT-4o 描述截图是拿大炮打蚊子。

2. 一定要喂上下文。 没有前后文的图片描述质量差两个档次,这个投入绝对值得。

3. 过滤比生成更重要。 大多数图片是噪声,不过滤的话 caption chunk 会严重污染检索结果。

4. 独立存储,不要内联。 这个反直觉,但实测数据很清楚。

5. 别把图片当文本的附属品。 在 RAG 管线设计时就把图片处理作为一等公民,而不是"后续优化"。

写在最后

RAG 领域的优化已经卷到了 text chunking、embedding、reranking 这些层面,但图片处理一直是个被忽视的角落。kapa.ai 的方案之所以有价值,不是因为技术多新,而是因为它在生产环境里跑通了——百万级查询、200+ 客户、有数据支撑。

如果你在做技术文档类的 RAG,我建议认真考虑这个方案。投入小(1%-6% 成本),回报大(10%-64% 图片引用率),且不需要重构现有管线。

相关阅读:


信源: