向量搜索的银河系漫游指南
Clelia Astra Bertelli 和 Evgeniya Sukhodolskaya
·2025 年 7 月 9 日

从讲堂到生产管线,Qdrant Stars——创始人、导师和开源贡献者——分享他们如何在实际应用中构建向量。
在这篇文章中,Clelia 提炼了她在“巴伐利亚搜索开发进展”聚会上的演讲中的技巧,她在演讲中分享了从她广泛的开源构建中获得的宝贵经验。
嘿,向量空间宇航员们!
我是 Clelia,LlamaIndex 的一名开源工程师。在过去的两年里,我致力于 AI 领域,构建(和破坏)了很多东西,有时甚至将它们部署到生产环境!
我花了很多时间研究 LLM、向量数据库和 AI 代理,我非常乐意与大家分享一些与向量搜索相关的技巧和窍门。这些见解不仅来自我的理论知识,还来自我在构建由向量搜索驱动的应用程序时获得的真实世界实践经验。
让我们深入了解吧!
文本 RAG 快速概览
这篇博客文章中的所有建议都与文本向量搜索相关,它为许多检索增强生成 (RAG) 应用程序提供支持。那么,RAG 是如何工作的呢?
简单来说,你可以把它分解成三个步骤
- 数据准备:通过从文件中提取原始文本并将其分块为更小、更易消化的片段来准备数据。
- 嵌入:选择一个文本嵌入模型,并用它来生成文本块的向量化表示。
- 上传到数据库并提供服务:将嵌入上传到向量数据库(例如 Qdrant),并将数据库作为管道中的检索端点提供服务。
当用户提出问题时,将从数据库中检索上下文并提供给 LLM,然后 LLM 将生成由检索到的信息增强的内容。
文本提取:你的最佳朋友和最差敌人

文本提取是关键一步:拥有干净、结构良好的原始文本对于 RAG 的所有下游步骤都可能改变游戏规则,尤其有助于使检索到的上下文易于 LLM “理解”。
你可以通过多种方式执行文本提取,例如
基于对象的解析,例如 PyPDF 或 PyMuPDF 提供的解析,对于纯文本文档来说快速且廉价,但可能无法捕获当今许多文件可能具有的表格、图像和其他视觉元素的复杂性。
基于代理和 OCR 的解析,例如 LlamaParse 提供的解析,这通常是处理复杂文档的绝佳选择,以及其他方法,包括使用视觉语言检索器,例如 ColPali&ColQwen,它们也非非常有效,尤其是对于扫描件或图像密集的文件。
我的建议
相信你的直觉。如果一个解决方案似乎能为你提供高质量的原始文本,那就选择它!
如果你想了解好坏文本提取如何带来差异的真实示例,可以查看我构建的一个项目,PapersChat。
它允许你使用 LlamaParse 或使用 PyPDF 进行简单解析,从你的论文中提取文本并与它们聊天。
分块是你所需要的一切

分块可能真正决定 RAG 管道的成败。
分块意味着将大文本分解成更小的片段,这些片段将被提供给 LLM 以执行增强生成。因此,将文本分解成有意义的块至关重要。
如果你想将文本按句子划分,使用基于句子或 token 的分块器可能更合理,而使用基于语义或嵌入的(后期)分块更适合分离段落。
当你想要隔离更高级别的语义单元时,例如一篇关于爬行动物的论文中所有关于鳄鱼的信息,应该使用代理或神经分块。
我的建议
有效分块归结为一件事:你想要作为输出的文本表示的复杂性。
对于我提到的所有分块策略,一个非常易于使用的库是 chonkie —— 试试看,你不会失望的!
你还可以查看 Code-RAGent 中如何使用抽象语法树来解析和分块代码文件,这是一个基于我的 GO 代码库构建的 RAG 代理,因此我可以检索我忘记或有疑问的代码概念和实现。
嵌入:全部抓捕!

嵌入文本等同于生成其数值表示。例如,作为目标表示,你可以选择密集或稀疏向量。区别在于它们捕获的内容:密集嵌入最擅长广泛捕捉文本的语义细微之处,而稀疏嵌入则精确地提取其关键词。
好消息是你不必在混合搜索中只选择一种。混合搜索结合了密集(语义)搜索和稀疏(关键词)搜索的结果。
但是如何组合呢?
- 你可以通过重新评分向量来做到这一点:你重新嵌入(通常使用密集或多向量嵌入模型)所有与检索到的向量(无论是密集还是稀疏)关联的文本,然后找到与查询最相似的向量。或者,你可以使用交叉编码器。
- 你也可以融合结果,例如,根据它们在两个排名(稀疏和密集)中的位置给它们分配分数,然后将这些分数相加。分数最高的块就是最佳匹配!
我的建议
混合搜索并非所有检索问题的解决方案,但当你想在保留语义区分的同时仍依赖基于关键词的搜索时,它是一个有价值的选择。例如,法律或医疗领域的 RAG 应用。
如果你想快速开始混合搜索,请查看 Pokemon-Bot,这是一个基于 Qdrant 和 Cohere 构建的简单 Discord 机器人。
搜索增强 101

搜索增强是每个人都想要的:更少的计算、更低的延迟,以及整体上更快、更高效的管道,可以使用户体验更流畅。我将提及其中两个。
语义缓存
假设你的 Qdrant 向量数据库包含大量信息,因此在其中搜索需要时间。然而,很容易想象,许多用户会在我们的 RAG 应用程序中提出类似的问题,因此为他们提供相同的答案是有意义的。
语义缓存登场:你应该创建第二个更小的向量数据库实例(Qdrant 中的集合),你可以在其中存储用户提出的问题的向量化表示,并在相关的元数据中存储该问题的答案。
然后,在运行整个 RAG 管道之前,你可以在语义缓存中快速搜索,看看是否有任何问题与之前提出的问题相似。你只需返回相关的答案,而不是重新生成一个,从而为你节省大量时间和计算!
二值量化
二值量化也能帮助你,特别是当你有海量文档时(我们说的是数百万)。大数据集是性能挑战,也是内存问题:像 OpenAI 这样的提供商的嵌入可能有 1536 维,这意味着每个全精度嵌入几乎 6 KB!
看,它来了:将向量作为浮点数列表,二值量化根据数学舍入将其转换为 0 和 1 的列表。这种表示显着减少了内存占用,并使你的搜索算法更容易比较向量表示。
使用二值量化自然会引出一个问题:“搜索结果是否与使用非量化向量时一样好?”通常,它们没有那么好,这就是为什么它们应该与上面讨论的其他技术结合使用,例如重新评分。
我的建议
你想构建一个具有语义缓存和量化的生产级系统吗?那么,你可能想看看 PhiQwenSTEM,一个拥有 15,000 多个文档访问权限的学习助手,可以回答你的 STEM 问题!
查询有所不同

RAG 管道中一个常见的错误是,你精心策划了所有细节,但没有考虑到一个关键方面:查询。
大多数时候,查询都过于通用或过于具体,无法从你的向量数据库中获取嵌入的知识。然而,有一些“魔法技巧”可以应用来优化你的用例查询。
我的建议
这是我的经验法则
| 查询类型 | 应用转换 |
|---|---|
| 通用查询:过于宽泛,可能混淆搜索过程 | 扩展:你可以将查询转换为假设文档(HyDE),使用语言模型生成更详细的查询文本,然后将其嵌入并用于检索。 |
| 特定查询:询问可以在你的文档中轻松识别的特定信息 | 在这种情况下无需转换,你可以直接检索! |
| 复杂查询:包含许多问题,通常无法仅凭数据库中的一个文档来回答 | 分解:你可以将查询分解为几个子查询,每个子查询都用于从数据库进行多步检索。然后,每个步骤的结果将构成 LLM 的最终答案。 |
如何分配查询类型?
嗯,你可以构建一个代理系统来自动选择查询转换,就像我的 RAGcoon 中那样。在该系统中,查询代理会尝试各种检索技术,以为创业公司创始人获取最佳信息。
不要淹没在评估中

将想法转化为实现很酷,但只有评估指标才能说明你的项目是否能带来真正的价值并具有进入市场的潜力。
然而,很容易淹没在所有现有的评估框架、策略和指标中。在评估产品首次实现时,在某些指标上获得中等偏上的结果,然后高兴地停止开发,而实际上还有巨大的改进空间,这种情况也很常见。
我的建议
对于陷入这些陷阱的人,我有两条建议
- 简单胜过复杂:正如 Python 禅宗格言所述,你的实现必须简单、易懂、易读。使用直观的指标,例如检索管道中的命中率或平均倒数排名 (MRR),或者你的 LLM 生成的响应的忠实度和相关性,是了解你正在构建的产品的最佳方式。总有时间测试和调整复杂的指标,但那是以后的事!
- 迭代、迭代、再迭代:启动一个简单且还算不错的东西很容易,但真正生产就绪的软件的关键在于迭代。在简单的基础上构建,并在每一轮调整和评估中使其变得更好。一旦你的产品开始变得足够好,就用更复杂的指标再次测试它们。迭代没有固定的限制,但一次永远不够!
如果你想从一些能立即提供关于结合不同嵌入和语言模型的概念验证的见解开始,你可以尝试 diRAGnosis,一个轻量级框架,它会用简单的指标告诉你你的模型表现如何。
我希望为你留下一些关键的收获。
最后一条可能听起来理所当然,但我保证并非人人都能做到:持续探索、构建和破坏——这是唯一的学习方式!
如果你愿意,可以通过我的社交媒体关注我在 AI 领域的旅程,向量空间宇航员们,再会!