外观
RAG 基础链路
目录
- 1. 学习目标
- 2. 面试结论
- 3. 面试官为什么问
- 4. 概念与边界
- 5. 原理剖析
- 6. 实现与代码
- 7. 实际项目案例
- 8. 方案权衡与常见误区
- 9. 面试题与参考答案
- 10. 递进追问
- 11. 实践任务
- 12. 相关知识与参考资料
- 13. 简明总结
1. 学习目标
- 理解 Retrieval-Augmented Generation(检索增强生成,RAG)的离线摄取链路与在线查询链路;
- 能够解释文档解析、切块、Embedding、向量索引、Top-k、上下文组装和生成各自解决的问题;
- 能够推导余弦相似度、Recall@k,并说明精确检索与近似最近邻的复杂度边界;
- 能够实现一个最小可运行的“切块 → 向量化 → 检索 → 带引用回答”教学系统;
- 能够沿调用链定位“查不到、查错了、查对但答错、文档未更新”等生产问题。
2. 面试结论
2.1 30 秒回答
RAG 是在生成前从外部知识库检索证据,并把证据连同问题交给大模型回答。完整系统分两条链:离线把文档解析、切块、向量化并建立带版本和权限元数据的索引;在线由可信服务端先计算用户权限范围,把 ACL 条件推入 Top-k 召回,再二次授权、去重并按 Token 预算组装上下文,最后生成带引用的答案。它能改善知识新鲜度和可追溯性,但不会自动保证召回、事实正确或权限安全,所以必须分别评测检索、生成和系统链路。
2.2 一分钟复述版
我会先强调 RAG 不是“接一个向量库”。离线侧要保证内容解析正确,Chunk 既保留回答所需语义又不过度冗余,每个向量带 source_id、版本、权限和位置元数据;在线侧先由可信服务计算授权范围并规范化或改写查询,再让向量和关键词检索都携带 ACL 条件,对结果二次授权后按相关性、去重和 Token 预算构造上下文,最后要求模型只依据证据回答并返回引用。诊断时我会按“语料是否存在 → 索引是否新鲜 → 查询是否表达正确 → 召回是否命中 → 上下文是否丢失 → 模型是否忠实”逐层看证据。RAG 与微调也不是互斥:RAG 主要提供外部事实,微调主要改变行为和任务能力。
3. 面试官为什么问
- 核心考察点:是否理解端到端数据流,而不是只会调用向量数据库;
- 对应岗位与级别:AI 应用、AI 后端、搜索与平台工程;高级岗位会追问索引一致性、权限、评测和故障隔离;
- 优秀回答的区分度:
- 能分离离线摄取和在线查询;
- 能说明 Chunk、Embedding、索引和上下文预算之间的耦合;
- 能区分检索错误与生成错误;
- 能用元数据、版本和引用建立可追溯性;
- 不声称 RAG 可以消除幻觉。
4. 概念与边界
4.0 小白先这样理解:新员工带着门禁卡查制度
小林入职第一天想知道“出差发票多久内可以报销”,没有凭印象作答,而是拿门禁卡进入公司资料室:目录员先按问题找到可能相关的制度,抽出其中几页交给小林,小林读完后组织答案,并标出制度名称和页码。这里,资料室是知识库,目录员是检索器,制度页是 Chunk,门禁卡是 ACL 权限,小林是 LLM,制度名称和页码是引用。如果没找到,小林应明确说证据不足,而不是编一个期限。
类比边界: 找到书页不代表书页最新、内容正确,也不代表小林一定读对;语料缺失、索引过期、权限过滤错误和模型误读仍要分别检查。门禁权限必须由可信服务端执行,不能让“像小林一样会说话的模型”自行决定能看哪些资料。
4.1 是什么
RAG 把参数化知识与非参数化知识结合:
- 参数化知识:模型权重中学习到的模式;
- 非参数化知识:查询时从文档库、数据库或搜索系统取回的外部证据。
工程上的基础 RAG 通常包含:
- 文档接入和版本识别;
- 解析、清洗与切块;
- Embedding 与索引;
- 可信身份解析、权限条件与 Top-k 检索;
- 候选二次授权、去重和上下文组装;
- 带证据生成、引用和拒答;
- 日志、评测和反馈。
4.2 不是什么
- RAG 不是微调:它不通过训练更新模型权重;
- RAG 不是向量数据库:向量库只是索引与检索组件;
- RAG 不是全文搜索的替代品:精确编号、专有名词和错误码常适合关键词检索;
- RAG 不是长上下文的同义词:把全部文档塞入上下文会受成本、噪声和窗口限制;
- RAG 不保证答案正确:检索命中后,模型仍可能忽略、误解或越过证据;
- RAG 不自动实现权限:ACL 必须在可信服务端参与检索和上下文构造。
4.3 解决什么问题
RAG 主要解决:
- 权重知识过时,业务文档持续变化;
- 私有知识不适合或不足以训练;
- 回答需要引用来源和审计;
- 同一模型服务多个动态知识域;
- 希望只更新语料和索引,而不是每次重新训练。
RAG 不适合单独解决:
- 需要稳定格式或行为风格,可考虑 Prompt 或微调;
- 需要严格计算、交易和权限判断,应使用确定性工具;
- 知识库本身没有答案,检索无法凭空创造事实;
- 极低延迟且答案集合固定的场景,缓存或规则可能更合适。
4.4 输入、输出与前置条件
- 离线输入:源文档、版本、更新时间、访问控制和解析配置;
- 离线输出:可检索 Chunk、向量、元数据、索引版本和失败记录;
- 在线输入:用户问题、身份、会话上下文和过滤条件;
- 在线输出:候选证据、最终上下文、答案、引用和链路诊断数据;
- 前置条件:知识确实存在、解析可信、Embedding 空间一致、索引已就绪、权限可执行。
4.5 与相近方案的区别
| 方案 | 主要改变 | 优势 | 局限 |
|---|---|---|---|
| Prompt 上下文 | 单次请求输入 | 简单、透明 | 需预先知道该放哪些内容 |
| RAG | 查询时外部证据 | 新鲜、可引用、易更新 | 依赖检索和索引质量 |
| 微调 | 模型参数或适配参数 | 行为、格式和特定任务能力 | 更新事实成本高,仍可能幻觉 |
| 工具/数据库查询 | 确定性系统结果 | 实时、结构化、可校验 | 需要明确接口和参数 |
| 长上下文 | 一次放入更多资料 | 少一层索引 | 成本、延迟、噪声和窗口仍有限 |
5. 原理剖析
5.1 直觉理解
可以把 RAG 看成“开卷考试”。模型负责理解问题和组织答案,检索系统负责在考试前迅速翻到相关页。书中有答案但没翻到,是召回问题;翻到正确页却答错,是生成忠实度问题;书本身没有答案,是语料覆盖问题。三者不能用一个“幻觉率”模糊处理。
5.2 端到端数据流
图 1:基础 RAG 的离线与在线双链路
替代文本: 上半部分将文档经过解析、切块和 Embedding 写入带版本与权限元数据的向量索引;下半部分将用户问题与身份条件转成查询,检索并组装上下文,再让 LLM 生成带引用答案,整个链路写入追踪和评测记录。
图表加载中…
读图结论: RAG 有两条独立但通过索引版本连接的链路;任何一层丢失内容、版本或权限,都可能让最终答案失败。
5.3 文档解析与切块
5.3.1 为什么要切块
文档通常大于单次检索单元。Chunk 太大:
- 向量表达混合多个主题,匹配不精确;
- 占用上下文,挤掉其他证据;
- 引用定位粗。
Chunk 太小:
- 丢失标题、定义条件和跨段关系;
- 同义短片段难以区分;
- 检索结果碎片化,重组困难。
常见策略:
- 固定 Token 长度加 overlap;
- 按标题、段落、列表和代码块递归切分;
- 语义边界切分;
- 子块检索、父块返回,即 small-to-big;
- 表格、代码、PDF 页眉页脚采用专用解析。
Chunk 必须带 source_id、document_version、section_path、字符或页码位置、ACL、content_hash 和 parser_version,才能删除、更新、引用和排障。
5.3.2 overlap 的边界
重叠可以减少边界信息丢失,却会:
- 增加索引体积和 Embedding 成本;
- 让 Top-k 出现近重复结果;
- 夸大某些文档在候选中的占比。
因此 overlap 不是越大越好,应与去重策略、文档结构和评测结果共同选择。
5.4 Embedding 与相似度
Embedding 模型把文本
查询向量
若向量已做 L2 归一化,余弦排序等价于点积排序。必须确认向量库使用的距离方向:有的返回相似度(越大越好),有的返回距离(越小越好),阈值不能照搬。
Embedding 模型、预处理和维度属于索引契约。查询与文档必须位于兼容空间;模型升级时不能把新旧向量无标记混在同一索引中。
5.5 Top-k、上下文组装与生成
Top-k 不是“先从全库取 k 个块,再隐藏无权内容”,也不是“最终把 k 个块全部塞给模型”。基础流程是:
- 由可信身份服务计算 tenant、用户组、项目、文档 ACL 和策略版本等授权条件;
- 将授权条件推入关键词、向量等每一路检索算子,再执行 Top-k 候选召回;
- 对候选文档重新授权,作为索引或缓存错误的二次防线;
- 去掉重复或同源过密 Chunk;
- 取回原文并核对版本;
- 在 Token 预算内保留问题、指令、证据和输出空间;
- 用稳定引用 ID 标记证据;
- 明确要求证据不足时拒答;
- 返回答案与引用映射。
如果先取全局 Top-k 再过滤,无权文档会占满候选位,使有权文档进不了后续链路,候选分数或缓存也可能越过权限边界;如果把过滤放在生成之后,未授权内容已经进入模型上下文,属于直接数据泄露。召回后授权仍有必要,但它是二次防线,不能替代检索内 ACL。
5.6 检索指标
设查询
若每个问题只标一个必要证据,也常报告 Hit@k:
边界:
- Recall@k 依赖相关性标注;只有答案文本、没有证据标注时不能直接计算;
- Chunk 粒度改变会改变
,跨切块版本的数值不能直接比较; - k 增大通常不降低召回,但会增加噪声、上下文成本和生成干扰;
- 检索命中不等于答案正确,还要单独评测忠实度与正确性。
5.7 复杂度与关键假设
假设有
- 全量 Embedding 成本近似随总 Token 数增长;
- 暴力精确向量检索需计算所有点积,时间约为
; - 保存稠密向量的主体空间约为
,还不含图索引、元数据和副本; - Approximate Nearest Neighbor(ANN,近似最近邻)用召回换延迟与内存,具体复杂度依赖 HNSW、IVF 等结构和参数,不能一概写成固定对数复杂度;
- 上下文构造受模型输入预算
约束,所有 Chunk Token 总数必须与指令、问题、历史和输出预留共同满足预算。
关键假设是“语义相近能代表回答相关”。编号、稀有实体、否定条件和时间范围可能违反这个假设,因此基础向量检索往往需要在下一阶段加入关键词检索、过滤和重排。
6. 实现与代码
6.1 最小可运行示例
下面只依赖 Python 标准库,用字符二元组构造教学向量,演示切块、向量化、余弦检索、上下文与引用。它不是生产语义 Embedding,也不调用 LLM;生产环境应替换 embed 与 generate,但保留相同数据契约。
运行:保存为 rag_demo.py 后执行 python rag_demo.py。
python
import math
import re
from collections import Counter
from dataclasses import dataclass
@dataclass(frozen=True)
class Chunk:
chunk_id: str
source: str
text: str
def normalize(text: str) -> str:
return re.sub(r"\s+", "", text.lower())
def embed(text: str) -> Counter[str]:
"""教学用字符二元组向量;生产环境替换为同版本语义 Embedding。"""
text = normalize(text)
return Counter(text[i : i + 2] for i in range(max(0, len(text) - 1)))
def cosine(a: Counter[str], b: Counter[str]) -> float:
dot = sum(value * b.get(key, 0) for key, value in a.items())
norm_a = math.sqrt(sum(value * value for value in a.values()))
norm_b = math.sqrt(sum(value * value for value in b.values()))
return dot / (norm_a * norm_b) if norm_a and norm_b else 0.0
def retrieve(query: str, chunks: list[Chunk], k: int = 2):
query_vector = embed(query)
scored = [
(cosine(query_vector, embed(chunk.text)), chunk)
for chunk in chunks
]
return sorted(scored, key=lambda item: item[0], reverse=True)[:k]
def build_grounded_answer(query: str, ranked) -> str:
# 为了可离线运行,这里只组装“交给 LLM 的证据”,不伪装成生成模型。
evidence = "\n".join(
f"[{chunk.chunk_id}] {chunk.text}" for score, chunk in ranked if score > 0
)
if not evidence:
return "证据不足,无法回答。"
return (
f"问题:{query}\n"
"请只依据以下证据回答;证据不足时明确拒答,并引用 chunk_id。\n"
f"证据:\n{evidence}"
)
if __name__ == "__main__":
chunks = [
Chunk("c1", "退款规则.md", "退款申请应在购买后七日内提交。"),
Chunk("c2", "退款规则.md", "数字商品已完整下载后不支持无理由退款。"),
Chunk("c3", "账号安全.md", "修改密码后应重新登录全部设备。"),
]
query = "退款申请期限是多久?"
ranked = retrieve(query, chunks, k=2)
for score, chunk in ranked:
print(f"{chunk.chunk_id}\t{score:.4f}\t{chunk.source}")
print("--- prompt ---")
print(build_grounded_answer(query, ranked))6.2 关键实现说明
- Chunk 是最小可检索和引用单元,chunk_id 必须稳定;
- normalize 与 embed 的版本在生产中必须记录,避免查询和索引不一致;
- 排序前没有设任意“通用阈值”,因为不同模型和距离实现分数不可直接迁移;
- generate 阶段故意只输出 Prompt,避免把字符串拼接冒充 LLM;
- 真实系统要批量 Embedding、持久化索引、按 ACL 过滤、限制 Token,并记录候选分数。
6.3 边界条件与验证
运行后应验证:
- 问退款期限时 c1 排在账号文档之前;
- 查询完全无关时不应因为“总有 Top-k”就强行回答;
- 删除 c1 后索引和原文同时不可见;
- 同一 source 的重叠 Chunk 不应占满所有候选;
- Chunk 文本与引用 source 能从当前版本原文核验;
- 切换 Embedding 版本时阻止新查询读取旧向量空间。
教学向量只利用字符重叠,无法处理真正同义表达。这个失败本身可作为对照实验,说明词法检索、语义 Embedding 和混合检索的差异。
6.4 技术栈与横向选型
RAG 是系统模式,不等于某个向量库或编排框架。下表使用三个主 TP 覆盖摄取、向量编码与候选存储;候选产品只是参考实现,真实结论需固定文档类型、权限、数据量和评测集。
| 技术点 ID | 技术点/环节 | 类型 | 采用方案 | 链路职责 | 版本/证据边界 |
|---|---|---|---|---|---|
| TP-RB-01 | 文档解析与结构化 | 库/服务 | Markdown/HTML 优先原生解析器;复杂 Office/PDF 以 Unstructured 或 Apache Tika 作候选 | 提取正文、标题、页码、表格与来源定位,为切块提供结构 | PDF/OCR 质量强依赖文档分布;解析率需用真实样本库评测 |
| TP-RB-02 | Embedding 编码 | 模型/服务 | 通过 Adapter 封装本地 Sentence Transformers 或托管 Embedding API | 对文档切块与查询使用同一受控模型产生向量 | 必须固定模型、维度、规范化、任务 Prompt 和 API 版本;不虚构召回收益 |
| TP-RB-03 | 向量与元数据存储 | 存储/检索服务 | 关系数据库已是主栈时优先评估 pgvector;独立向量服务以 Qdrant 作候选 | 存储向量、原文引用、ACL、版本与过滤字段,返回可追溯候选 | 产品不会自动保证 ACL 正确或召回质量;必须用权限与性能基准决策 |
| 技术点 ID | 候选方案 | 优点 | 缺点/代价 | 适用场景 | 不适用场景 | 选择结论与依据 |
|---|---|---|---|---|---|---|
| TP-RB-01 | Unstructured | 面向多格式文档提供元素化抽取与分区思路 | 复杂依赖、版式差异和 OCR 错误需额外质检 | PDF、Office 等多格式摄取,需保留元素类型 | 来源只是结构清晰的 Markdown,原生解析已足够 | 仅在复杂格式样本库上证明标题、表格与定位收益后采用 |
| TP-RB-01 | Apache Tika | 广泛文件类型检测与文本/元数据提取,服务边界清晰 | 输出往往还需业务化结构恢复,不自带 RAG 切块质量保证 | 多格式统一文本抽取、JVM 服务已成熟 | 需高保真表格、版面与 OCR 领域化结构 | 作为稳定通用抽取候选,用同一文档金标集与 Unstructured 对比 |
| TP-RB-02 | 本地 Sentence Transformers | 数据不出域、批处理与模型版本可控 | 需 GPU/CPU 容量、模型加载、扩容和升级运维 | 敏感数据、稳定高吞吐、需自主固定模型 | 请求少且团队没有推理运维能力 | 在隐私或稳定负载证明总成本收益时采用 |
| TP-RB-02 | 托管 Embedding API | 接入快、无需维护推理集群,容量由服务方提供 | 存在数据出域、限流、成本和模型升级边界 | 原型、弹性负载、合规允许的通用语义检索 | 严格数据驻留、无外网或必须绑定自训模型 | 以数据边界、限流、质量和总成本联合决策,并置于 Adapter 后 |
| TP-RB-03 | PostgreSQL + pgvector | 向量、关系元数据和事务处在同一运维体系 | 大规模 ANN 、独立扩容与索引调优会与业务数据库争资源 | 已有 PostgreSQL、数据规模受控、元数据过滤重 | 向量搜索需独立大规模扩展且会影响主库 | 作中小规模首个可运维基线,容量与权限基准不达标再分离 |
| TP-RB-03 | Qdrant | 向量检索、过滤与服务化运行边界清晰 | 引入新存储、备份、容量和双写/迁移复杂度 | 检索负载需独立扩展、复杂过滤与在线更新 | 数据小或团队无多存储运维能力 | 只在独立扩展、延迟或过滤证据超过额外成本时切换 |
6.5 架构与技术调用流程
图:架构|基础 RAG 离线摄取与在线问答边界
替代文本: 离线链路将权威文档经解析、切块、Embedding 与质量门禁写入版本化索引;在线链路将用户身份与查询一起进入权限过滤、向量检索、上下文构造和 LLM,索引清单连接两条链路的版本。
图表加载中…
读图结论: 离线索引发布与在线问答是两条独立链路,必须通过不可变索引清单对齐语料、Embedding 和 ACL 版本。
架构图表达静态数据与权限边界。向量索引不是权威事实源;回答必须能回到原文版本和用户可见的证据片段。
图:技术调用流程|RAG 查询的权限、召回与拒答时序
替代文本: 问答 API 先验证身份并生成可见过滤条件,再调用 Embedding 和索引;无可见候选或证据不足时拒答,LLM 超时时返回已受权的检索结果或明确失败,成功时校验引用后返回。
图表加载中…
读图结论: ACL 必须在召回前进入候选边界;证据不足和 LLM 不可用是两类失败,分别需要拒答语义与服务降级策略。
时序图将检索与生成故障分开。生产 Trace 应记录索引、Embedding、ACL、Prompt 和模型指纹,但不应将未脱敏原文无限制写入日志。
7. 实际项目案例
示例项目,非本仓库真实业务;不假设数据量、QPS 或效果提升。
7.1 背景、目标与约束
构建企业内部运维知识助手,回答部署、故障和权限流程问题。知识来自 Markdown、PDF 和工单总结,具有以下约束:
- 文档更新频率不同,删除和撤权必须及时生效;
- PDF 可能出现页眉、表格和扫描页解析错误;
- 不同团队只能看到各自文档;
- 回答必须给出文档与段落引用;
- 无证据时应拒答,不能靠模型常识补全内部流程。
7.2 架构与调用链
图:业务双泳道|企业运维知识助手的索引发布与在线问答
替代文本: 离线泳道从文档版本判断开始,解析、切块和批量向量化后写入候选索引;质量或权限检查失败时保留旧索引,通过后才原子切换。在线泳道从可信身份和租户上下文开始,检索、原文复核和上下文预算后生成带引用答案;无证据、越权或生成失败进入拒答或降级分支。
图表加载中…
读图结论: RAG 的可信边界跨越发布和查询两条链:候选索引未过门禁不能被读,在线候选未过权限、版本和证据检查不能进入模型或伪装成正常答案。
数据模型至少包含 Document、DocumentVersion、Chunk、EmbeddingVersion、IndexBuild、RetrievalTrace。删除不是只删原文,还要产生可审计的索引删除事件。
7.3 方案选择与实现难点
- Markdown 按标题和代码块切分,PDF 使用保留页码/版面的解析结果,不统一粗暴定长;
- 检索子块但返回包含标题的父级上下文,兼顾定位与完整性;
- 写入新索引后先做完整性与抽样查询,再切换可读别名,避免半更新;
- ACL 在检索前或检索算子内执行,不能只在答案显示层隐藏;
- 文档正文和工具输出都标记为非可信数据,防止其中指令覆盖系统规则。
未选择“把全部文档放进长上下文”,因为它无法解决权限、更新一致性、成本和可追溯检索问题。
7.4 异常处理、监控与测试
| 现象 | 根因假设 | 解决方案 | 验证证据 |
|---|---|---|---|
| 明明有文档却零命中 | 文档未解析;索引任务失败;版本过滤错误 | 查 source_id 全链路;重放失败任务;校验别名 | 当前版本 Chunk 可数;金标准查询 Hit@k 恢复 |
| 命中旧制度 | 增量更新未删旧 Chunk;缓存键无版本 | tombstone 删除;索引版本入缓存键 | 旧 chunk_id 不可检索;引用指向新版本 |
| Top-k 都是重复段落 | overlap 过大;没有同源去重 | 降低重叠;按 source/section 做 MMR 或配额 | 候选唯一来源数与 Recall@k 同时检查 |
| 检索正确但答错 | 上下文被截断;Prompt 允许常识补全 | 记录最终上下文;调整预算;要求引用/拒答 | 相同证据下忠实度回归测试通过 |
| 用户看到他组文档 | ACL 晚于检索;只按 tenant/role 缓存;撤权后未失效 | 每路召回推入完整 entitlement 条件;命中后二次授权;权限指纹和策略版本入缓存键;撤权主动失效 | 覆盖同租户同角色但不同文档权限的越权测试;Trace 显示授权条件与策略版本 |
| PDF 答案乱码 | OCR/表格解析失败 | 解析质量门禁;类型化解析;失败隔离 | 原文抽样、页码引用和解析错误率检查 |
7.4.1 故障演练:撤权后缓存仍返回其他团队文档
- 现象与影响:用户权限已撤销,但相同查询仍命中旧缓存并引用受限文档,造成持续的数据泄露窗口。
- 定位证据:检查身份、完整 entitlement、policy_version、缓存键、候选文档 ACL、撤权事件时间、命中记录与最终上下文。
- 根因:检索缓存只按 query 或 tenant/role 隔离,撤权事件没有主动失效缓存;命中后也没有二次授权。
- 临时止损:禁用或清理受影响缓存命名空间,阻断相关检索流量,撤销已生成链接并启动安全审计。
- 长期修复:每路召回携带可信权限过滤,缓存键绑定完整权限指纹与策略版本;命中后二次授权,撤权和删除事件主动失效。
- 回归验证:覆盖同租户同角色不同 ACL、撤权传播、共享变更、缓存命中和索引回滚,确认未授权候选始终不可见。
- 防复发:权限测试加入发布门禁,监控异常跨主体命中、撤权传播延迟和缓存失效失败;审计日志绑定 request_id 与策略版本。
监控至少分层记录 ingest_lag、parse_failure、chunk_count、index_build_status、retrieval_candidate_count、filtered_count、Recall@k(离线)、无证据率、引用缺失率和端到端延迟。高基数的 query_id 放日志/Trace,不直接当无界指标标签。
7.5 结果与复盘
项目验收不能写“能回答几个问题”:
- 为每个问题标注答案是否存在、必要证据和允许引用;
- 分别测试文档新增、修改、删除、撤权和回滚;
- 将失败归到覆盖、解析、索引、查询、召回、上下文或生成;
- 记录每次变更的 parser、chunker、embedding、index、prompt 与 model 版本;
- 只有在固定评测集与线上安全门禁均通过后才发布。
8. 方案权衡与常见误区
8.1 适用与不适用场景
适用:
- 私有或频繁变化的文档问答;
- 需要引用和审计;
- 多租户、多知识域且可建立检索语料;
- 允许“证据不足时拒答”。
不适用或需组合其他方案:
- 权威实时数值应直接查数据库/API;
- 需要模型稳定遵守风格可组合微调;
- 没有可治理知识源时,RAG 无法修复知识空洞;
- 确定性流程应由状态机或规则主导。
8.2 关键权衡
| 决策 | 一侧收益 | 另一侧成本 | 验证方式 |
|---|---|---|---|
| Chunk 变小 | 定位精确 | 上下文破碎 | 按问题类型比较 Recall@k 与答案忠实度 |
| overlap 增大 | 减少边界丢失 | 重复、成本、候选挤占 | 唯一来源数、索引体积、Recall@k |
| k 增大 | 可能提高召回 | 噪声与 Token 增加 | 检索-生成联合曲线 |
| 精确检索 | 结果确定 | 大规模延迟高 | 以精确结果作 ANN 召回基线 |
| ANN | 延迟可控 | 近似误差、参数复杂 | ANN Recall 与延迟压测 |
| 强拒答 | 降低无证据回答 | 可能误拒 | answerable/unanswerable 分开评测 |
8.3 常见错误回答
- “Top-1 分数高就一定相关”:分数依赖模型、查询和索引实现,需标注集校准;
- “Chunk 越大信息越全”:可能混合主题并挤占上下文;
- “用了 RAG 就不会幻觉”:生成仍可能不忠实;
- “Embedding 升级只改模型名”:必须重建兼容索引并管理版本;
- “权限在返回前过滤即可”:未授权文本进入上下文已构成泄露;
- “向量库召回差就是换更大模型”:先确认语料、解析、版本、查询和标注。
8.4 生产问题的诊断顺序
对一条失败请求保留并依次检查:
- 用户身份、租户和过滤条件;
- 答案所需事实是否存在于当前权威文档;
- 文档版本是否完成解析和索引;
- Chunk 是否包含完整答案及标题条件;
- 查询向量与索引 Embedding 版本是否一致;
- 原始候选、分数、过滤前后列表和最终上下文;
- 模型输入是否截断,输出是否引用证据;
- 缓存是否跨版本、跨租户或保存旧答案。
这个顺序先查确定性数据链,再判断模型质量,能避免把摄取失败误报为“LLM 幻觉”。
9. 面试题与参考答案
问题 1:完整 RAG 链路有哪些关键步骤?
- 难度:基础;
- 考察点:端到端理解;
- 合格答案要点:离线解析、切块、Embedding、索引;在线查询处理、检索、过滤、上下文、生成和引用;
- 优秀答案加分项:版本、ACL、删除、观测和评测;
- 常见错误:只回答“Embedding 加向量库”;
- 可继续追问:哪个步骤最容易造成“文档存在但查不到”?
问题 2:Chunk 大小如何选择?
- 难度:中级;
- 考察点:检索单元与上下文完整性的权衡;
- 合格答案要点:根据文档结构、答案跨度、Embedding 与 Token 预算,通过固定集实验;
- 优秀答案加分项:子块检索父块返回、overlap 去重、表格/代码专用解析;
- 常见错误:给出一个适用于所有系统的固定数字;
- 可继续追问:切块版本变化后为什么不能直接比较旧 Recall@k?
问题 3:为什么检索到正确 Chunk,模型仍可能答错?
- 难度:中级;
- 考察点:检索与生成解耦;
- 合格答案要点:上下文截断、冲突证据、指令不清、模型忽略或误解证据;
- 优秀答案加分项:查看最终实际上下文、引用和忠实度,不只看原始候选;
- 常见错误:直接增大 Top-k;
- 可继续追问:如何设计证据不足拒答?
问题 4:RAG 与微调如何选择?
- 难度:中高级;
- 考察点:方案边界;
- 合格答案要点:动态事实与引用优先 RAG,行为与任务能力可考虑微调,两者可组合;
- 优秀答案加分项:比较更新频率、数据质量、延迟、成本、审计和评测;
- 常见错误:把两者说成互斥;
- 可继续追问:如果答案来自实时订单状态,应使用哪种方案?
问题 5:如何安全地做多租户 RAG?
- 难度:高级;
- 考察点:数据权限和缓存隔离;
- 合格答案要点:可信身份下发、每路检索前/检索内 ACL、候选二次授权、租户隔离索引或强过滤、缓存绑定完整权限指纹和策略版本;
- 优秀答案加分项:撤权同步、越权红队、Trace 审计和最小化日志;
- 常见错误:生成后隐藏敏感句子;
- 可继续追问:索引库不支持高效 ACL 过滤时如何设计?
10. 递进追问
- 基础概念:为什么 RAG 被称为“非参数化知识”增强?
- 原理细节:L2 归一化后,为什么点积排序与余弦排序一致?
- 实现边界:文档更新时怎样避免一半新索引、一半旧索引?
- 工程权衡:增大 Top-k 为什么可能提高召回却降低最终答案质量?
- 系统设计:设计一个支持删除、撤权、回滚和引用的文档索引版本系统。
- 项目复盘:线上“无答案率”上升,你如何证明是语料变化、检索退化还是拒答策略变化?
参考回答线索:
- 知识保存在外部可检索存储而非只在模型参数;
- 单位向量的范数为 1,余弦分母恒定;
- 新索引暂存、校验后原子切换别名,保留可回滚版本;
- 更多弱相关证据会挤占 Token、制造冲突并分散注意;
- 不可变版本、事件驱动删除、ACL 元数据、引用定位和切换审计;
- 按版本切分并重放固定查询,分别观察语料覆盖、Recall@k 和忠实度/拒答指标。
11. 实践任务
- [ ] 最小实现:运行第 6 节代码,为 Chunk 增加 section 与 document_version;
- [ ] 对比实验:构造同义表达与精确编号查询,观察字符二元组向量的失败,作为语义/关键词检索基线;
- [ ] 切块实验:对同一篇自有文档使用段落切块、定长切块和父子切块,人工标注必要证据后比较;
- [ ] 故障注入:模拟文档删除但向量未删、Embedding 版本混用、ACL 缺失和上下文截断;
- [ ] 面试口述:不看文档完整讲出离线与在线两条调用链,并解释每层失败证据。
12. 相关知识与参考资料
12.1 相关知识
- 前置知识:Token 与 Embedding;
- 前置知识:Prompt 与结构化输出;
- 后续主题:RAG 检索优化;
- 后续主题:RAG 评测与生产工程。
12.2 参考资料
以下均为原始论文、官方文档或官方源码,访问日期均为 2026-07-10:
- Lewis et al., Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks, NeurIPS 2020:RAG 的原始问题定义与参数化/非参数化记忆组合;
- Karpukhin et al., Dense Passage Retrieval for Open-Domain Question Answering, EMNLP 2020:双编码器稠密检索;
- Johnson, Douze, Jégou, Billion-scale similarity search with GPUs, IEEE BigData 2017:FAISS 相似度检索设计;
- Malkov and Yashunin, Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs, IEEE TPAMI:HNSW 原始论文;
- Facebook Research, FAISS source repository:精确与近似向量索引的官方源码;
- OpenAI, Embeddings guide:Embedding 输入、相似度用途与官方 API 说明。
13. 简明总结
一句话记忆: RAG 是“离线把知识做成可追溯索引,在线把正确证据送进上下文”,不是简单连接一个向量库。
- 基础链路必须拆成文档摄取与查询生成两条路径;
- Chunk、Embedding、Top-k 和 Token 预算互相制约,要靠标注集选择;
- 文档存在、检索命中、上下文保留和生成忠实是四个不同检查点;
- 权限、版本、删除和引用必须从数据模型开始设计;
- 面试中要能沿“语料 → 解析 → 索引 → 检索 → 上下文 → 生成”逐层定位失败。