云计算百科
云计算领域专业知识百科平台

RAG 向量检索:从“查字“到“查意“

LLM 很聪明,但它有一个硬伤:知识截止到训练那天。你今天问它"公司上周更新的报销流程",它只能瞎编。RAG(Retrieval-Augmented Generation,检索增强生成)就是为了解决这个问题:先检索外部知识,再让 LLM 基于检索结果生成答案。而 RAG 的检索环节,核心靠的就是向量检索。

这篇文章从零讲清楚:什么是向量检索、Embedding 干了什么、相似度怎么算、大规模检索怎么加速,以及它在 Agent 里到底长什么样。

一、传统搜索 vs 向量检索:为什么"同义词"是个大麻烦

传统搜索引擎(比如数据库里 LIKE '%关键词%' 或倒排索引的 BM25)的核心逻辑是字面匹配。你用"调薪"去搜,文档里写的是"薪酬调整流程"——一个词对不上,直接搜不到。

这叫词汇鸿沟(lexical gap):你说的话和文档里写的话用的是不同词,但意思一样。传统搜索对此毫无办法——它没有"语义理解"能力,只有"字符串匹配"能力。

向量检索换了一个思路:不找"字",找"意思"。它把查询和文档都转成一串数字(向量),然后在数学空间里算距离。语义相近 → 距离近 → 命中。你说"怎么调薪",文档里有"薪酬调整流程",它们在向量空间里紧挨着——哪怕字面上完全不同。

对比维度传统关键词搜索向量检索
匹配依据 字面命中(TF-IDF/BM25) 语义距离(余弦相似度等)
“调薪"搜"薪酬调整” 搜不到 能搜到,向量距离近
搜人名、型号、编号 精准 可能漂移
搜"大概意思" 无能为力 强项

一句话:传统搜索像在找字,向量检索像在找意。成熟的系统都会做混合检索(Hybrid Search)——两路结果融合,互补短板。

二、Embedding:把文字变成"语义坐标"

为什么需要 Embedding

计算机只认识数字。想让计算机判断"猫在沙发上睡觉"和"猫咪在沙发上打盹"意思相近,得先把这两句话都变成数字。Embedding 就是这个转换过程——把文本映射到一个高维向量空间里的一个点。

输入一段文字,Embedding 模型输出一个固定长度的浮点数数组,比如 OpenAI 的 text-embedding-3-small 吐出 1536 个浮点数:

[0.012, -0.453, 0.891, -0.023, …, 0.147] # 共 1536 维

你没法想象 1536 维空间长什么样(人类大脑超过三维就抓瞎了),但数学上完全合理。Embedding 模型在训练时就是靠海量语料学到了一个规律:把语义相近的文字放在高维空间中相邻的位置。

经典类比:向量算术

Embedding 的妙处还不止于此。经典实验:"国王" – "男人" + "女人" ≈ "女王"。向量可以做加减法,而且结果还符合人类直觉——这说明向量确实编码了语义信息,不只是随机数字。

主流 Embedding 模型一览

模型维度特点
OpenAI text-embedding-3-small 1536 通用性强,性价比高,中文支持不错
OpenAI text-embedding-3-large 3072 精度更高,维度更大,适合高要求场景
BGE (BAAI) 768/1024 开源,中文优化,自部署免 API 费用
Jina Embeddings v3 1024 多语言,支持 8192 token 长文本输入
Cohere Embed v3 1024 支持多种输入类型(搜索文档/搜索查询等)

选模型的核心原则:入库和检索必须用同一个 Embedding 模型。不同模型产出的向量空间不一致,换模型 = 推倒重来。

三、相似度:怎么判断两个向量"靠得近"

向量检索最后一步,就是拿用户 query 的向量,去向量库里找距离最近的 K 个文档向量。这里"距离"有三种常用度量:

余弦相似度(Cosine Similarity)

最通用。计算两个向量夹角的余弦值,范围 [-1, 1]。只看方向不看长度,所以长的文档和短的 query 也能公平比较。

余弦相似度 = (A · B) / (||A|| × ||B||)

欧氏距离(Euclidean Distance)

两点之间直线距离。当向量已经 L2 归一化后,欧氏距离和余弦相似度等价。

点积(Dot Product)

两个向量逐元素相乘再求和。向量归一化后 = 余弦相似度。适合需要加权排序的场景。

实际工程里 90% 的场景用余弦相似度就对了。推理开销小,语义表达力足够。

四、ANN 加速:百万向量怎么毫秒级搜完

为什么要近似

如果暴力搜索(kNN)——拿 query 向量和库里每个向量都算一遍距离再排序——复杂度是 O(N)。N = 十万的时候还行,N = 百万、千万就崩了:每次查询要跑几百万次浮点运算,延迟秒级起步。

所以实际用的不是精确搜索,而是 ANN(Approximate Nearest Neighbor,近似最近邻)——牺牲一丁点精度(比如从"100% 召回"降到 “99.5% 召回”),换回几十上百倍的加速。

两大主流算法

IVF(Inverted File,倒排文件):先把所有向量用 K-Means 聚成 N 个桶(簇)。查询时只搜离 query 最近的几个桶,桶内做暴力搜索。核心思想是"先粗筛再细查"。

关键参数:

  • nlist:分多少个桶。越大越细,但建索引越慢。
  • nprobe:查几个桶。越大召回越高,但越慢。

HNSW(Hierarchical Navigable Small World,分层可导航小世界图):目前精度和速度的标杆。构建一个分层图结构——上层稀疏用于"导航到大致区域",下层稠密用于"精确定位"。搜索时从顶层逐层下降,类似在多层停车场里从顶层俯瞰逐步找到车位。

关键参数:

  • M:每个节点的最大连接数(16~64)。越大越精确,但内存也越大。
  • efSearch:搜索时考察的候选数(50~200)。越大召回越高,但越慢。
对比维度IVFHNSW
召回精度 高,但依赖 nprobe 调参 极高,通常优于 IVF
检索速度 极快,接近 O(log N)
构建速度 快(只聚类) 慢(逐点建图)
内存占用 高(存全部原始向量) 高(存图结构 + 向量)
适合场景 平衡速度与精度的通用场景 高要求场景(RAG、推荐系统)

代表向量数据库

数据库核心算法特点
FAISS (Meta) IVF, HNSW, PQ 库而非数据库,极高性能,GPU 加速
Milvus IVF, HNSW 分布式架构,支持十亿级
Qdrant HNSW 过滤功能丰富,Rust 实现性能好
Chroma HNSW 轻量易用,适合原型和中小规模
pgvector IVF, HNSW PostgreSQL 扩展,和业务库同存

五、分块策略:切多大才合适

Embedding 模型再好,分块没搞对,检索照样烂。这是工程中最容易被低估的环节。

核心矛盾

  • 切太大(比如 2048 token):一段里塞了三个不同话题,Embedding 向量变成一个"杂糅语义点",搜什么都能命中一点,但精准度极差。
  • 切太小(比如 128 token):一句完整的话被腰斩,上下文丢失,LLM 拿到碎片答不出完整答案。

工程上的经验值

  • 通用场景:512 token 为一块,相邻块重叠 10%~15%(overlap)。这样关键句落在边界处也不被切开。
  • 技术文档/代码:按自然边界切——函数级、段落级、章节级。不要机械按字符数切。
  • QA 场景:每个 Q&A 对独立成块。

# chunking_config.py — 典型分块配置
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块 500 字符
chunk_overlap=50, # 相邻块重叠 50 字符(10%)
separators=["\\n\\n", "\\n", "。", ".", " "] # 优先按自然边界切
)
chunks = splitter.create_documents([document])

分块同时要带上元数据:来源文档名、章节标题、时间戳、版本号。检索时可以用元数据做过滤(“只搜 2024 年的文档”),精度大幅提升。

六、Rerank:少花钱、多办事

向量检索拉回 top-20 个候选块,直接全塞给 LLM?token 浪费不说,后面十几条可能是噪音。

两阶段检索是性价比最优解:

  • 粗筛(向量检索):从全库拉 top-20 ~ top-50
  • 精排(Rerank 模型):用一个专门的重排序模型对候选集打分,取 top-3 ~ top-5 喂 LLM
  • Rerank 模型比 Embedding 模型更"贵"但更准——它会把 query 和候选文档逐对精细比对,而不是只算一次向量距离。Cohere Rerank、BGE-Reranker 是常用选择。

    # retrieval.py — 两阶段检索伪代码
    def retrieve_and_rerank(query: str, top_k: int = 20, final_k: int = 3) > list[str]:
    # 阶段1:向量粗筛
    query_vec = embed(query)
    candidates = vector_db.search(query_vec, top_k=top_k)

    # 阶段2:Rerank 精排
    scores = reranker.compute_scores(query, [c.text for c in candidates])
    ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)

    return [c.text for c, _ in ranked[:final_k]]

    七、在 Agent 中长什么样

    Agent 用 RAG 不需要把每个细节都自己手写,成熟的框架已经封装好了。以你正在学的 LangChain 为例:

    # agent_rag_pipeline.py — Agent 中 RAG 的最小闭环
    from langchain.document_loaders import TextLoader
    from langchain.text_splitter import RecursiveCharacterTextSplitter
    from langchain.embeddings import OpenAIEmbeddings
    from langchain.vectorstores import Chroma

    # 1. 加载文档 + 分块
    loader = TextLoader("company_policy.txt")
    docs = loader.load()
    chunks = RecursiveCharacterTextSplitter(
    chunk_size=500, chunk_overlap=50
    ).split_documents(docs)

    # 2. 向量化 + 存入向量库
    embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
    vectorstore = Chroma.from_documents(chunks, embeddings)

    # 3. 作为检索器接入 Agent
    retriever = vectorstore.as_retriever(search_kwargs={"k": 5})

    # 4. Agent 调用时,retriever 自动搜相关文档注入上下文

    完整链路:用户问 → Agent 决策 → 调 retriever 搜向量库 → 拿 top-k 文档 → 拼 prompt → LLM 生成 → 返回答案。

    关键设计点:

    • retriever 对 Agent 来说是一个工具(Tool),和其他工具(API 调用、数据库查询、代码执行)并列。Agent 自己决定什么时候该用检索、什么时候不该。
    • 检索到的内容注入到 LLM 的 system prompt 或上下文里,而不是替换用户原始问题。

    八、常见坑

    现象真相
    向量检索结果完全不对 入库和检索用了不同的 Embedding 模型,向量空间不统一
    换了个相似问法就搜不到了 Embedding 模型对领域术语没训练过,考虑微调或换领域模型
    明明文档有答案,检索就是命中不了 分块太大,语义被稀释;或分块太小,关键上下文被切断
    向量检索快但内存爆炸 没做向量压缩(PQ),1536 维 × 百万条 = 几个 GB 起
    Rerank 加了反而变慢 Rerank 模型和 Embedding 模型有"排序偏好冲突"——粗筛选出的候选集本身不行,精排救不回来
    混合检索分数无法对齐 向量余弦值(-1~1)和 BM25 得分量纲不同,直接加权无效;用 RRF(倒数排名融合)代替

    九、总结

    向量检索用一句话概括:把文本映射到高维向量的语义空间,靠距离度量"意思有多近",用 ANN 算法在大规模数据中毫秒级找出最相关的文档。它在 RAG 链路里扮演"外部大脑的记忆索引"——不是取代 LLM,而是让 LLM 有据可依。

    工程上的优先级:分块策略 > Embedding 模型选择 > 向量数据库选型。很多项目在向量数据库上纠结半天,结果分块一塌糊涂——方向跑偏了。

    最后记住一个核心判断:向量检索擅长"语义模糊匹配",不擅长"精确条件查找"。人名、型号、编号、日期范围、法条编号——这些老老实实用过滤条件或关键词搜索,别硬往向量上套。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » RAG 向量检索:从“查字“到“查意“
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!