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

【LLM&&AI应用开发 八股文】--3.1.RAG检索增强(上)

为什么有了大模型还需要RAG?幻觉、私有知识、时效性四大问题

假设你们公司有几千份内部文档:产品手册、操作规范、历史项目经验、客户合同……领导想做一个 AI 问答系统,让员工随时可以问"我们的退款政策是什么"、"这个客户签了哪些条款",系统能直接给出准确答案。

你直接用大模型来做,第一轮测试效果还不错——但很快发现几个绕不开的问题:

  • 模型对公司内部文档一无所知,回答全靠"编"
  • 产品文档上周刚更新,但模型说的还是老版本的内容
  • 模型回答的很流畅,但根本无法知道它说的是真是假,也无法追溯来源
  • 文档加载到 Prompt 里,token 成本高到无法接受

这不是模型能力不够的问题,而是大模型作为一种技术,有几个根本性的天花板——而 RAG 就是为了突破这些天花板而诞生的。

目录

1.RAG–定义

1.1.适合的场景

1.2.面试官可能会问

2.RAG–完整链路

2.1.离线阶段

2.2.在线阶段

2.3.核心认知

2.4.面试官可能会问

3.Embedding 是什么

3.1.Embedding –压缩语义

3.2.Embedding 模型怎么选?

3.3.面试官可能会问

4.向量数据库

4.1.MySQL 不行

4.2.向量索引:ANN很快

4.3.向量数据库功能

4.4.面试官可能会问

5.RAG 切片策略

5.1.Overlap

5.2.面试官可能会问


1.RAG–定义

RAG 的全称是 Retrieval-Augmented Generation,检索增强生成。它的核心思路非常直觉:在让模型回答之前,先去知识库里检索出最相关的内容,把这些内容作为上下文一起喂给模型,让模型"看着资料"来回答。

下面这张图展示了 RAG 如何对应地解决上面四个问题:

RAG 针对四个问题各有应对:

对幻觉问题: 检索到的原文片段作为上下文传入模型,模型被要求"根据以下资料回答",而不是凭空生成。有了事实依据的约束,幻觉概率大幅降低——但注意,不是归零,这个后面会讲。

对私有知识问题: 知识库完全由你自己构建和维护,可以包含任何内部文档。模型不需要知道这些内容,只需要在被检索到的片段基础上进行推理和组织语言。

对知识更新问题: 更新知识库不需要重新训练模型,只需要更新文档、重新做向量化索引即可。知识的新鲜度完全由知识库决定,和模型训练截止日期解耦。

对可追溯性问题: 每次检索都能知道具体命中了哪份文档的哪个片段,可以在答案里附上引用来源,用户可以自行核查。

1.1.适合的场景

很多人看到 RAG 的思路后,产生了一个误区:是不是所有大模型应用都应该加 RAG?不是的。

适合 RAG 的场景:

知识密集型的问答系统,比如企业内部知识库、产品手册问答、法律法规查询——这类场景对事实准确性要求高,内容量大,且需要明确的来源追溯。

内容频繁更新的业务,比如新闻摘要、竞品分析、政策解读——这类场景下知识库可以持续接入实时数据,而模型本身不需要动。

长尾事实查询,比如"我们公司在上海的办公地址是什么""这个合同的甲方是谁"——这类问题的答案藏在特定文档里,必须检索才能找到。

1.2.面试官可能会问

Q:为什么有了大模型还需要 RAG?

参考思路:大模型有几个局限性——幻觉、私有知识盲区、知识时效性、无法溯源。RAG 通过在回答前先检索外部知识库,把相关文档片段注入上下文,让模型"看资料回答",从而有针对性地缓解以上问题。

Q:RAG 能解决幻觉问题吗?

参考思路:能显著缓解,但无法根治。有了检索到的事实作为锚点,模型乱编的概率大幅降低,且答案可以附上来源供核查。但模型仍然可能在检索结果上做出错误推理,或者在检索质量差时进行"补充生成"。RAG 降低幻觉概率,不消灭幻觉根因。

Q:什么场景下你会推荐用 RAG,什么场景下不用?

参考思路:适合 RAG 的是知识密集、内容频繁更新、需要溯源的场景,比如企业知识库问答、法规查询。不适合的是创意生成、强推理任务、以及模型训练数据已良好覆盖的稳定领域——在这些场景下,RAG 只是增加延迟和成本,没有实质收益。

2.RAG–完整链路

先用一张图把整条链路建立起来,再逐段拆解:现在逐段拆解这条链路上的每个环节。

整条链路分两段:离线侧负责"把知识存进去",在线侧负责"把相关知识找出来、组合出答案"。

2.1.离线阶段

1.原始文档(解析)

RAG 系统的知识来源可以多种多样:PDF 报告、Word 文档、网页、Markdown 文件、数据库记录、邮件……不同格式的文档需要不同的解析方式,这一步通常叫做 文档加载(Document Loading)。

值得注意的是,这一步的质量直接影响整个系统的上限。如果原始文档本身是扫描件或排版混乱的 PDF,解析出来的文本就会充满噪声,后续所有环节都会受损。"垃圾进,垃圾出"在 RAG 里体现得非常明显。

2.文档处理(清洗与预处理)

解析出来的原始文本往往不能直接用,需要做一轮清洗:去掉页眉页脚、无意义的格式符号、重复内容;识别并保留文档的标题结构;过滤掉表格乱码、图片占位符等。

这一步看起来琐碎,但在实际项目里,文档预处理往往是工程量最大、最容易被低估的部分。

3.切片(Chunking)

清洗好的文档不能整篇塞进向量库,需要切成更小的片段(chunk)。这是 RAG 系统里设计决策最多的一个环节,直接影响后续检索的精准度。

为什么要切?原因很直接:一篇 20 页的文档,用户的问题可能只和其中的某一段相关。如果把整篇文档作为一个单元存储和检索,要么检索粒度太粗(命中了整篇但相关内容被淹没),要么上下文太长(放不进模型或者注意力被稀释)。

切多大合适?这没有通用答案,需要根据文档类型、模型的上下文窗口、业务问题的颗粒度来决定。

4.向量化(Embedding)

切好的每个 chunk,都需要通过 Embedding 模型转换成一个向量(一个高维浮点数数组),这个向量代表了这段文字的"语义"。

向量化的关键点是:用户问题和文档 chunk 必须用同一个 Embedding 模型来处理,这样两者的向量才处于同一个语义空间,相似度计算才有意义。

同时还需要存储对应的元数据:这个 chunk 来自哪份文档、原文在哪一页、文档的创建时间等。元数据在过滤检索结果时非常重要,比如"只看最近三个月的文档"这类需求,就需要依赖元数据来实现。

5.存入向量数据库

向量和元数据分别存入向量数据库(如 Milvus、Weaviate、Chroma、Pinecone 等)和普通数据库/文档存储。向量数据库的核心能力是近似最近邻搜索(ANN),能在数百万向量中毫秒级找到与查询向量最相似的 top-K 结果。

文档解析 –>文档处理 –> 切片 –>向量化 –>存入向量数据库

2.2.在线阶段

下面这张图单独展示在线检索链路的各个环节,以及常见的优化分叉点:

1. Query 处理(改写/拓展/优化)

输入:用户原始自然语言问题 输出:用于检索的查询字符串 / 多条子 query

Query 改写

  • 作用:口语转书面、消歧义、复杂问题拆分子问题
  • 示例: 原始:公司报销怎么弄,最多能报多少? 改写拆分:
  • 公司报销流程
  • 公司报销额度上限
    • 适用场景:用户问句长、多意图、口语化;基础版本可以直接使用原 query 跳过。

    Query 扩展

    • 作用:同义词、相关术语扩充 query,解决用户用词和文档用词不一致导致召回失败
    • 示例:离职补偿 → 扩展离职赔偿金、辞退补偿
    • 实现方式:大模型生成扩展、同义词词典;小体量知识库可以不开启,避免引入无关检索方向。

    注意:改写 / 扩展是可选,过度扩展会引入噪声,反而降低检索质量。

    2. Retrieval 检索

    输入:处理后的 Query 输出:粗排候选 chunk 列表 (top‑K)

    方法一 :纯向量检索

  • Query 经过 Embedding 模型向量化
  • 和向量库内全部文档块 (chunk) 计算余弦相似度
  • 返回相似度最高的 top‑K,K 一般取 3~10
    • 优点:抓语义,同义词也能召回
    • 缺点:关键词精确匹配弱,专有名词、编号容易漏。

    方法二 :混合检索 Hybrid Search(工业常用)

    两路并行检索:

  • 向量检索:语义匹配
  • BM25 关键词检索:字面关键词精确匹配 再做结果融合(分数加权、Reciprocal Rank Fusion RRF)合并候选集合。
  • 优势:兼顾语义理解 + 关键词精准命中,解决纯向量容易丢失专有名词的问题。

    举个例子:

    pip install rank-bm25 jieba

    import jieba
    from rank_bm25 import BM25Okapi

    # ———————- 1. 准备知识库 chunk ———————-
    corpus = [
    "国内出差住宿标准:一线城市单人上限600元/晚,二线城市450元/晚。出差机票优先经济舱。",
    "公司为异地员工提供住房补贴,一线城市每月补贴1500元,二线城市1000元。",
    "供应商住宿接待标准,一类城市不超过800元每晚。",
    "出差报销需要发票、行程单,提交OA流程审批。",
    ]

    # 给每个chunk标记来源id
    chunk_ids = [0, 1, 2, 3]

    # 中文分词:BM25需要分词后的词列表
    tokenized_corpus = [list(jieba.cut(doc)) for doc in corpus]

    # 构建BM25索引(纯内存倒排索引,无训练)
    bm25 = BM25Okapi(tokenized_corpus)

    # ———————- 2. BM25检索函数 ———————-
    def bm25_search(query: str, top_n=3):
    query_tokens = list(jieba.cut(query))
    scores = bm25.get_scores(query_tokens)
    # (score, chunk_id, text)
    scored = [(scores[i], chunk_ids[i], corpus[i]) for i in range(len(scores))]
    scored.sort(key=lambda x: x[0], reverse=True)
    return scored[:top_n]

    # ———————- 3. 模拟向量检索(真实场景调用Embedding+向量库,这里模拟输出排名) ———————-
    def mock_vector_search(query: str, top_n=3):
    """模拟向量检索返回结果,格式:(sim_score, chunk_id, text)
    对应前面例子:向量召回顺序 0,1,2
    """
    # 模拟向量相似度分数
    mock_ret = [
    (0.92, 0, corpus[0]),
    (0.78, 1, corpus[1]),
    (0.71, 2, corpus[2]),
    ]
    return mock_ret[:top_n]

    # ———————- 4. RRF 排名融合算法 Reciprocal Rank Fusion ———————-
    def rrf_fuse(list_a, list_b, k=6):
    """
    list_a / list_b: [(score, chunk_id, text), …]
    k: RRF常数,一般取6
    return: 融合后排序列表 [(rrf_score, chunk_id, text)]
    """
    rrf_dict = {}

    # 处理第一路结果
    for rank, item in enumerate(list_a):
    _, cid, text = item
    rrf_score = 1.0 / (rank + 1 + k)
    if cid not in rrf_dict:
    rrf_dict[cid] = {"score": 0.0, "text": text}
    rrf_dict[cid]["score"] += rrf_score

    # 处理第二路结果
    for rank, item in enumerate(list_b):
    _, cid, text = item
    rrf_score = 1.0 / (rank + 1 + k)
    if cid not in rrf_dict:
    rrf_dict[cid] = {"score": 0.0, "text": text}
    rrf_dict[cid]["score"] += rrf_score

    # 降序排序
    fused = sorted(rrf_dict.items(), key=lambda x: x[1]["score"], reverse=True)
    out = [(v["score"], cid, v["text"]) for cid, v in fused]
    return out

    # ———————- 5. 运行测试 ———————-
    if __name__ == "__main__":
    user_query = "国内出差一线城市住宿报销标准是多少?"

    bm25_res = bm25_search(user_query, top_n=3)
    vec_res = mock_vector_search(user_query, top_n=3)

    print("==== BM25检索结果 ====")
    for s, cid, txt in bm25_res:
    print(f"score={s:.3f}, id={cid}: {txt}")

    print("\\n==== 模拟向量检索结果 ====")
    for s, cid, txt in vec_res:
    print(f"sim={s:.3f}, id={cid}: {txt}")

    fused_result = rrf_fuse(bm25_res, vec_res, k=6)
    print("\\n==== RRF混合检索融合结果 ====")
    for s, cid, txt in fused_result:
    print(f"rrf={s:.3f}, id={cid}: {txt}")

    3. Rerank 精排(召回后,可选但性价比极高)

    输入:粗排得到的 top‑K 候选 chunk 输出:重新打分排序后的短列表(一般截取 top‑2~top‑4 送入 LLM)

    流程:

  • 使用 Cross‑Encoder 重排模型,输入(Query, Chunk)成对输入模型
  • 模型输出该 chunk 对于当前问题的相关性分数
  • 根据分数重新排序,过滤低分片段,取 top‑N
    • 优点:RAG 优化中收益最高的手段,过滤掉语义向量相似但实际无关的碎片
    • 代价:额外模型推理,增加推理延迟;候选集不能太大,否则速度很慢。

    实践范式:粗召回 K=8‑10 → rerank → 筛选 top‑3‑4 给 LLM。

  • Embedding(双编码器 Dual‑Encoder):Query 和 Chunk 分开编码,得到两个独立向量,算余弦相似度。训练目标:让相关的 pair 向量靠近、不相关远离。
    • 优点:chunk 可以提前向量化入库;检索速度快。
    • 缺点:query 和 chunk 没有交互,只能粗粒度语义,细粒度相关性判断弱。
  • Rerank 使用 Cross‑Encoder(交叉编码器):Query + Chunk 拼接在一起送入同一个模型,token 之间互相做注意力交互,直接输出一个相关性分数。
  • 4. 上下文构建 Context Construction

    输入:rerank 筛选后的 chunk 片段 输出:组装完成的 Prompt 上下文

  • 将 chunk 连同元数据(文档来源、页码、文件名)格式化拼接
  • 拼接系统指令、参考资料块、用户原始 query,组装完整 Prompt 模板
  • 模板示例:

    你是一个企业知识库助手。请根据以下资料回答问题,如果资料中没有相关信息,请明确说明。

    参考资料:
    [来源:产品手册第3页]
    ……chunk内容……
    [来源:财务制度V2.0]
    ……chunk内容……

    用户问题:我们的退款政策是什么?

    ⚠️关键点:控制总 token 长度,防止上下文溢出;chunk 不要无限制堆砌。

    5. Generation LLM 生成

    输入:完整 Prompt 输出:最终回答给用户

    核心约束写在 Prompt 指令中:

  • 优先依赖给定参考资料回答,禁止使用模型自身的内部知识
  • 资料无信息时明确告知 “现有资料未提及该内容”,禁止幻觉编造
  • 回答中标注资料来源,方便溯源校验

  • 2.3.核心认知

    核心认知要点说明实践启示
    各环节对质量的影响各不相同

    1. Chunking:决定能不能检索到相关内容

    2. Embedding 模型:决定语义理解是否准确

    3. Rerank:决定召回 top 结果是否真的最相关

    4. Prompt 设计:决定LLM 能否正确利用上下文

    优化 RAG 优先定位薄弱环节,不要所有环节盲目调参
    离线‑在线链路必须对齐 文本清洗、分词、Embedding 模型,离线建索引和在线检索必须完全一致;索引用模型 A,检索用模型 B,向量空间不一致,相似度计算失效 上线前校验预处理链路一致性;不要随意更换 embedding 模型
    检索追求精准,而非片面追求召回数量 少量高质量 chunk(top‑3)优于大量混杂的 top‑20 结果;上下文 token 越长,LLM 注意力越分散,信噪比下降 控制粗召回候选数量,依靠 Rerank 过滤噪声,精简送入 LLM 的上下文

    2.4.面试官可能会问

    Q:请描述一个完整的 RAG 链路。

    参考思路:分两段回答。

    离线侧:文档加载 → 清洗预处理 → Chunking → Embedding 向量化 → 存入向量数据库(同时存元数据)。

    在线侧:用户 Query →(可选 Query 改写)→ Query 向量化→向量检索召回 top-K →(可选混合检索、Rerank 精排)→ 拼装 Context + Prompt → LLM 生成 → 输出带来源引用的答案。

    元数据有什么用?

    {
    "vector": [0.123,0.456, …],
    "content": "国内出差住宿标准:一线城市单人上限600元/晚…",
    "metadata": {
    "doc_id": "doc_005",
    "doc_name": "差旅管理规定V3.pdf",
    "page": 4,
    "chunk_index": 12,
    "department": "财务部",
    "version": "V3",
    "create_time": "2026‑01‑10"
    }
    }

  • 溯源:给答案加来源出处,便于校验;
  • 过滤:检索时做条件筛选(版本、部门、租户权限);
  • 运维:按 doc_id 批量删除 / 更新文档,是向量和源文档的映射桥梁;
  • 业务:实现多租户、权限、分类控制。
  • RAG 很多线上问题根源就是元数据缺失:文档更新后旧向量清不掉、答案无法溯源、没法做权限过滤。

    Q:RAG 里哪些环节最影响效果?

    参考思路:

    离线侧最关键的是 Chunking 策略(决定检索粒度)和 Embedding 模型选型(决定语义理解质量)。

    在线侧最关键的是 Prompt 设计(引导模型正确利用上下文)。其中文档质量是前提,再好的系统也处理不好乱码和结构混乱的输入。

    Q:Embedding 模型在离线和在线需要保持一致吗?为什么?

    参考思路:必须一致。

    Embedding 模型把文本映射到一个高维向量空间,不同模型的向量空间是不同的。离线用 A 模型建的索引,在线用 B 模型生成 Query 向量,两者处于不同空间,余弦相似度计算完全失去意义,检索结果会非常混乱。

    3.Embedding 是什么

    面试官:用户问‘出差能不能报销坐飞机’,你的知识库明明有答案,为什么搜不出来?

    他:可能是关键词没匹配上,我再多加几个同义词。

    面试官:文档里写的是‘民用航空器’,不是‘飞机’,再想想。

    他沉默了几秒:是不是搜索词库不够全?

    面试官摇摇头:你加再多同义词也没用。你的检索到底在匹配什么?是文字,还是语义?

    他:我就是按关键词搜索啊……

    面试官:那用户说‘飞机’,你怎么匹配‘民用航空器’?

    他:(́◉◞౪◟◉‵)……

    传统搜索在拼文字,而 Embedding,就是让机器读懂人类的语言。

    今天我们把 Embedding 向量检索,从头到尾拆清楚。

    语义压缩、模型选型、和 Rerank 的区别

    Embedding 是一种将文本(或图片、音频等)映射到高维向量空间的技术。一个句子经过 Embedding 模型处理后,会变成一个由几百到几千个浮点数组成的数组,比如 [0.23, -0.87, 0.14, …, 0.56](维度通常是 384、768 或 1536 维)。

    关键不在于这串数字本身,而在于它在空间里的位置:语义相似的文本,它们的向量在这个高维空间里彼此距离近;语义不相关的文本,距离远。

    这是 Embedding 的核心承诺:用空间距离来表达语义相似度。

    (在高维 Embedding 空间,余弦相似度衡量两个向量指向的语义方向有多接近)

    下面这张图用二维空间来直觉化这件事。真实的向量是几百到几千维,但投影到二维平面后,语义聚类的模式仍然清晰可见:

    图中的每个点都是一段文本经过 Embedding 后在向量空间中的位置。真实维度远不止两维(通常是几百到几千维),但语义聚类的规律是一致的:出行报销类的文档彼此靠近,动物类、编程类各自聚集。

    用户的 Query 向量化后,系统计算它与所有文档向量的距离,找到最近的几个,这就是向量检索的本质。

    3.1.Embedding –压缩语义

    Embedding 不是生成文本,是在压缩语义

    这里有一个经常被混淆的概念,值得单独说清楚。

    生成式大模型(如 GPT、Claude)的目标是输出文字,给你一段输入,生成下一段内容。

    Embedding 模型的目标完全不同——它的输出不是文字,而是一个向量表示,目的是把一段文字的"语义"压缩到一个固定维度的数字数组里,保留语义信息,丢掉格式和措辞细节。

    同一个语义,即使换各式各样的说法,经过一个好的 Embedding 模型,得到的向量应该非常接近。这就是语义搜索能跨越措辞差异找到相关内容的根本原因。

    3.2.Embedding 模型怎么选?

    在实际工程中选 Embedding 模型,有几个维度需要考量:

    向量维度

    维度越高,理论上能表达的语义越细腻,但存储开销和检索速度也会相应增加。常见维度有 384 维(轻量)、768 维(均衡)、1536 维(高精度)。大多数中等规模业务选 768 维是合理起点。

    最大 token 限制

    每个 Embedding 模型都有输入长度上限,超过上限的内容会被截断。这个限制直接约束了 Chunk 的最大大小。比如 bge-small-zh 支持最多 512 token,那你的 chunk 就不能超过这个限制。选模型前一定要核对这个参数。

    中文支持

    这是中文 RAG 场景最关键的选型依据。通用的英文 Embedding 模型(如 OpenAI 的 text-embedding-ada-002)对中文的支持质量明显不如专门优化过中文的模型。目前中文场景下口碑较好的开源选项包括 BGE 系列和 M3E 系列,都在评测榜上有较好表现。

    是否支持非对称检索

    RAG 里有一个典型的非对称场景:Query 是一个简短的问题("退款政策是什么"),而文档片段是一段较长的说明文字。有些模型为这类非对称的 Query-Document 对做了专门优化,检索效果明显更好,比如 BGE 系列支持为 Query 加特殊前缀 "Represent this sentence for searching relevant passages:" 来提升检索效果。

    项目对称检索 Symmetric非对称检索 Asymmetric (RAG 常用)
    使用场景 句对相似度、去重、问题‑问题匹配 RAG 检索:短 Query 检索长 Passage
    输入处理 Query、Passage 完全相同处理,不加特殊前缀 Query 加检索指令前缀;Passage 直接原文,不加前缀
    训练数据 (普通句子,普通句子) (带指令的 query,原始 passage)
    示例输入 Q: 退款政策是什么P: 退款政策:xxx Q: Represent this sentence for searching relevant passages: 退款政策是什么P: 退款政策:xxx
    BGE 模型使用模式 bge‑small‑zh 对称 bge‑m3‑zh、bge‑v3支持非对称模式

    3.3.面试官可能会问

    Q:Embedding 模型怎么选?

    参考思路:从四个维度回答。

    第一,语言场景——中文业务优先选中文优化模型(BGE、M3E),不要直接用英文通用模型;第二,输入长度——模型的最大 token 限制直接决定 chunk 大小的上限;

    第三,向量维度——根据存储资源和精度要求权衡,768 维通常是合理起点;

    第四,任务类型——非对称检索(短 Query 找长文档)和对称检索(相似问题匹配)的最优模型不同,要看具体业务场景。

    Q:Embedding 和 Rerank 有什么区别?

    参考思路:Embedding(双塔/Bi-Encoder)对 Query 和文档分别独立编码成向量,通过向量相似度召回,优点是文档向量可离线预计算、检索极快,可处理百万量级,适合粗筛;

    Rerank(Cross-Encoder)把 Query 和每个候选文档拼接后联合输入,直接输出相关性分数,模型能看到两者的深度交互,精准度更高,但无法预计算、需逐对推理,只适合对少量候选做精排。两者是流水线关系:Embedding 粗筛召回候选池,Rerank 精排过滤出最终传给 LLM 的上下文。

    4.向量数据库

    你做了一个 RAG 系统,有 100 万个文档 chunk,每个 chunk 都经过 Embedding 变成了一个 768 维的向量。

    现在用户提了一个问题,你把这个问题也向量化了。接下来你要做的事情是:找到 100 万个向量里,和这个 Query 向量最相似的 top-5 个。

    听起来不难,实际做起来很麻烦。

    最直接的方法是"暴力搜索":把 Query 向量和全部 100 万个向量逐一计算余弦相似度,排序,取 top-5。在一台普通服务器上,这个操作大概需要几百毫秒到几秒——对于实时对话场景来说完全不可接受。

    而且,当向量数量增长到 1000 万、1 亿时,暴力搜索的耗时线性增长,根本无法用于生产。

    这就是向量数据库要解决的核心问题:在海量高维向量中,如何在毫秒级内找到最相似的结果?

    4.1.MySQL 不行

    这是面试里最常问的问题之一。答案不只是"MySQL 不支持",而是有本质的技术原因。

    传统关系型数据库的查询本质上是精确匹配或范围扫描——比如 WHERE age > 25 AND city = '北京',通过 B-Tree 索引可以快速定位到符合条件的行。

    向量相似度搜索完全不同。你不是在问"哪些向量等于某个值",而是在问"哪些向量和我的查询向量最接近"——这是一个在高维连续空间里的几何问题。

    传统数据库的索引结构(B-Tree、Hash Index)对这类问题完全无效,因为它们设计之初没有考虑"高维几何相似度"这个维度。即便 PostgreSQL 的 pgvector 扩展支持向量存储,在大规模场景下的性能仍然远不如专门的向量数据库。

    4.2.向量索引:ANN很快

    要在百万量级向量中做毫秒级检索,关键是向量索引。向量数据库不做暴力全量计算,而是预先构建一个特殊的索引结构,让检索时只需访问一小部分向量就能找到近似的最近邻——这就是 ANN(Approximate Nearest Neighbor,近似最近邻搜索)。

    "近似"两字需要注意。ANN 不保证找到绝对最近邻,但在实践中找到的结果精准度足够高(通常 95%+),而速度提升是数量级的。

    目前最主流的两类向量索引算法是:

    HNSW(Hierarchical Navigable Small World)

    HNSW 构建了一个层级结构的图:最顶层是少量节点,形成"高速公路";底层是所有节点,形成"街道网络"。检索时从顶层入口进入,沿图中的邻居边快速导航,逐层下降,像 GPS 导航一样越来越精细,最终定位到目标附近的最近邻。

    HNSW 的优势是查询速度极快、精度高,是 Milvus、Qdrant、Weaviate 等主流向量数据库的默认索引。代价是构建索引时内存占用较大。

    IVF(Inverted File Index)

    IVF 先对所有向量做 K-Means 聚类,把相似的向量分组到同一个"货架"里。检索时先找到 Query 向量最近的几个货架,只在这些货架内做精细查找,而不是全量扫描。

    IVF 的优势是内存占用较低,适合超大规模数据集。缺点是如果 Query 向量恰好落在两个货架的边界,可能会漏掉一些相关结果(边界效应)。

    4.3.向量数据库功能

    向量数据库不只是"存向量、搜向量"这么简单,它还有几个在 RAG 工程里非常重要的能力:

    元数据过滤(Metadata Filtering)

    每个向量可以附带结构化的元数据,比如文档来源、创建时间、部门归属、文档类型等。检索时可以在向量相似度搜索的同时附加元数据条件——比如"只在最近三个月的文档里搜索"、"只搜索产品部门的文档"。这让 RAG 系统可以做到语义相关 + 业务过滤的组合查询。

    混合检索(Hybrid Search)

    主流向量数据库(如 Weaviate、Elasticsearch with dense vectors)支持同时运行向量搜索和关键词搜索,然后用融合算法(如 RRF,Reciprocal Rank Fusion)合并两路结果。这对中文专业术语场景尤其有用,因为有些专有名词的语义表示很弱,必须依赖关键词精确匹配。

    向量更新和删除

    知识库需要持续更新——文档修改了、删除了,向量索引也需要对应更新。不同向量数据库对这个操作的支持成本差异很大,选型时需要考虑业务的更新频率。

    类别代表产品核心特点适用场景局限
    专用向量数据库 Milvus、Qdrant、Weaviate、Pinecone 原生以向量检索为核心;完善的元数据过滤、混合检索、分片扩容;性能强 百万及以上向量,生产环境;需要混合检索、高并发;Pinecone 为云端托管免运维 Pinecone 为海外云服务;自建需要运维部署成本
    传统数据库向量扩展 PostgreSQL+pgvector、Elasticsearch(dense vectors) 复用现有数据库基础设施;支持向量 + 原有业务查询;ES 原生支持 BM25 + 向量做混合检索 已有 PG/ES 运维体系,中小规模业务 百万向量以上,检索性能弱于专用向量库;扩缩容复杂
    轻量级本地向量库 FAISS、Chroma FAISS:纯索引库,非完整数据库,无持久化 / 元数据管理;Chroma:开箱即用轻量库 原型开发、本地调试、小规模测试(几十万向量以内) 不适合线上高并发大流量生产环境

    4.4.面试官可能会问

    Q:为什么不用 MySQL 做相似检索?

    参考思路:分两个层面回答。

    第一,功能层面:传统关系型数据库的查询模型是精确匹配和范围扫描,基于 B-Tree 等索引结构,这类结构无法支持"找高维空间中的近似最近邻"这种几何问题;

    第二,性能层面:即便通过扩展支持向量存储和计算(如 pgvector),在百万级向量时全量计算余弦相似度的复杂度是 O(N),远远无法满足毫秒级检索需求。向量数据库通过 HNSW、IVF 等专门的近似索引结构,把检索复杂度降低到近似 O(log N)。

    Q:向量数据库为什么能加速召回?

    参考思路:向量数据库的核心是 ANN(近似最近邻搜索),通过预先构建向量索引来避免全量计算。以 HNSW 为例,它构建了分层的可导航小世界图,检索时从顶层稀疏图的入口快速导航,逐层定位到目标区域,只访问极少数节点就能找到近似最近邻,速度比暴力搜索快几个数量级。代价是"近似"——不保证绝对最近邻,但实践中 recall 精度 95%+ 足以满足 RAG 场景需求。

    5.RAG 切片策略

    内容有点多了,这个我重新出一个章节。

    切片:【LLM&&AI应用开发 八股文】–RAG的分块策略-CSDN博客

    5.1.Overlap

    讲 Chunking 绕不开一个关键参数:overlap(重叠)。

    设想一段文字,中间某句话恰好落在两个 chunk 的边界:前半句在 chunk 1,后半句在 chunk 2。当用户提问这句话相关的内容时,单独检索到 chunk 1 或 chunk 2,拿到的都是一半,信息不完整,生成的答案就会出错。

    Overlap 的解决思路是:相邻 chunk 之间保留一段重叠的内容。比如 chunk 大小设为 512 token,overlap 设为 64 token,那么 chunk 2 的前 64 个 token 和 chunk 1 的后 64 个 token 是完全相同的。

    这样,边界附近的信息在两个 chunk 里都有备份,不管检索命中哪个,都能拿到完整的上下文。

    5.2.面试官可能会问

    Q:你们项目里 chunk 是怎么切的?

    参考思路:

    先说选择了什么策略及原因,再说具体参数(chunk size、overlap),最后说是如何评估和调整的。

    例如:"我们的文档是有章节结构的产品手册,所以用了结构感知切分,按二级标题划分。每个 chunk 控制在 600 token 以内,overlap 设了 80 token。后来发现部分技术规格内容跨段落,把 overlap 调大到 120 token 后,相关问题的召回率有明显提升。"

    Q:chunk 过大过小分别有什么问题?

    参考思路:

    过小会导致语义不完整,单个 chunk 缺乏上下文,向量表示语义模糊,检索精准度低。

    过大会导致 Context 里的噪声增多,模型注意力被分散,同时每个 chunk 的向量是多话题混合的平均,语义匹配变差。两个方向的问题都直接影响最终的生成质量。

    Q:为什么要设置 overlap?

    参考思路:

    overlap 是为了防止重要信息落在 chunk 边界被割裂,通过让相邻 chunk 共享一段内容来保证边界附近的信息在两侧都能被完整检索到。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【LLM&&AI应用开发 八股文】--3.1.RAG检索增强(上)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!