1. RAG 的动机
LLM 的核心局限
知识截止 (Knowledge Cutoff)
预训练数据有明确的时间边界。GPT-4 的知识截止于 2023 年 4 月,对于最新信息、实时股价、最近发表的论文等无法准确回答。这限制了模型在时效性要求高的领域的应用。
幻觉问题 (Hallucination)
模型会生成看似合理但完全虚构的信息。因为模型本质是一个统计文本预测器,没有真实的知识库或事实检查机制。在知识库外的话题上,模型倾向于编造答案而不是表示不知道。
无法访问私有数据 (No Private Data Access)
企业的内部文档、数据库、CRM 系统、专有知识库等都不在模型的训练数据中。模型无法直接查询或检索这些私有信息,限制了在企业应用中的可用性。
上下文窗口限制 (Context Window Limit)
虽然现代 LLM 的上下文窗口在扩大 (例如 GPT-4 Turbo 128K),但仍有上限。处理超大规模文本库时,需要智能检索而非直接注入全部数据。
RAG 的核心思想
RAG (Retrieval-Augmented Generation) 的核心思想:
不依赖模型的参数知识,而是动态检索外部知识库中的相关信息,让模型基于真实、最新的上下文生成答案。
RAG 的三个演进阶段
| 演进阶段 | 核心特点 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| Naive RAG | 分块 → 嵌入 → 相似度搜索 → LLM | 实现简单,流程清晰 | 检索精度低,易丢失上下文 | 快速原型,小规模场景 |
| Advanced RAG | 查询优化 + 精排 + 重排 + 上下文压缩 | 检索和生成质量显著提升 | 系统复杂度增加,计算成本提高 | 生产环境,对质量要求高 |
| Modular RAG | 模块化设计,支持条件路由和动态组装 | 灵活性强,可针对性优化每个模块 | 需要大量标注数据和实验 | 超大规模应用,特殊业务需求 |
2. RAG 完整架构
两大阶段:索引 + 查询
索引阶段 (Indexing): 离线预处理,一次性执行。将原始文档分块、向量化,存储到向量数据库中以支持快速检索。
查询阶段 (Query): 在线执行,每次用户查询时触发。将用户查询转化为向量,检索相关文档,重排精排,构建提示词,调用 LLM 生成最终答案。
3. 文本嵌入 (Embedding) 详解
嵌入模型的演进
Skip-gram 和 CBOW 模型。每个词映射到固定维度的向量空间,能捕捉基本的词义关系。局限:单词级别,不能处理词序和长距离语义。
上下文化的词嵌入。BERT 能捕捉句子和文档级别的语义,但需要微调。ELMo 基于 LSTM,计算复杂度较高。
引入句子级对比学习损失函数,直接训练产生可比较的句子向量。大幅降低计算成本,成为 RAG 的标准选择。
OpenAI text-embedding-3, BGE (BAAI), E5-mistral, Cohere, GTE, Jina Embeddings 等。在各种下游任务上优化,多语言支持,不同维度选项,特殊用途(长文本、多粒度等)。
对比学习训练原理
现代嵌入模型大多基于对比学习 (Contrastive Learning):
InfoNCE Loss 函数:
L = -log(exp(sim(q, p+) / τ) / Σ exp(sim(q, p_i) / τ))
其中:
q- 查询句子的嵌入向量p+- 正样本(相关文本)的嵌入向量p_i- 负样本(无关文本)的嵌入向量sim(·,·)- 相似度函数(通常是余弦相似度)τ- 温度参数,控制相似度分布的锐度
训练目标: 最小化正样本与查询的距离,最大化负样本与查询的距离。通过大量正负样本对的对比,模型学会了在向量空间中捕捉语义相似性。
主流嵌入模型对比
| 模型 | 维度 | 训练数据规模 | 特点 | 适用场景 |
|---|---|---|---|---|
| OpenAI text-embedding-3-small | 1536 | 大规模多语言数据 | 商业模型,性能稳定,降维友好 | 通用 RAG,企业应用 |
| OpenAI text-embedding-3-large | 3072 | 大规模多语言数据 | 更强的表达力,成本更高 | 高精度需求,知识密集任务 |
| BGE-M3-Embedding | 1024 | 多语言(包括中文) | 开源,多粒度(token, chunk, doc),混合搜索 | 中文 RAG,多粒度检索 |
| E5-mistral-7b-instruct | 1024 | 大规模英文数据 | 基于 Mistral,指令可微调,开源可部署 | 私有部署,特定领域微调 |
| Cohere embed-v3 | 可配置 (64-4096) | 专有数据集 | 动态维度,支持短文本和长文本 | 灵活的成本控制,多任务 |
| GTE (Alibaba) | 1024 | 中文优化 | 面向中文优化,开源 | 中文文档检索 |
| Jina Embeddings v3 | 可变 (可达 8192) | 长文本优化 | 支持超长上下文 (8K tokens),云原生 | 长文档检索,法律文书等 |
高级嵌入技术
Hard Negative Mining(难负样本挖掘)
在对比学习中,不是所有的负样本都同等重要。"难负样本"是那些与查询在语义上相似但标签不同的样本。通过优先使用难负样本,模型的区分能力显著提升。
实现: 在训练中,使用 BM25 或之前模型的检索结果识别难负样本,优先在批次中包含它们。
Matryoshka Representation Learning(俄罗斯套娃表示)
模型在训练时,同时优化多个不同维度的表示。允许在推理时根据需求选择向量维度,权衡精度与成本。例如,text-embedding-3-small 在全 1536 维度和截断后的 256 维度上都能表现良好。
优势: 灵活的性能-成本权衡,降低存储和计算成本而几乎不损失精度。
相似度计算:余弦相似度
在高维向量空间中,余弦相似度是检索最常用的相似度度量:
cos(A, B) = (A · B) / (||A|| × ||B||)
计算两个向量的夹角的余弦值。结果在 [-1, 1] 之间,值越大表示越相似。
面试考点:
- 对比学习中 InfoNCE loss 的直观理解
- 什么是硬负样本挖掘?为什么重要?
- 不同嵌入模型的选择标准是什么?
- Matryoshka Representation 如何实现成本优化?
4. 向量数据库
核心问题:高维近似最近邻搜索 (ANN)
向量数据库的根本问题:给定一个查询向量 q,从数百万个向量中快速找到最相似的 K 个向量。精确最近邻搜索的时间复杂度是 O(N),这对于大规模数据不可接受。因此需要 近似最近邻搜索 (ANN),在精度和速度之间找到平衡。
主流 ANN 算法详解
HNSW (Hierarchical Navigable Small World)
思路: 受复杂网络理论启发,构建一个多层的小世界网络结构,在高层稀疏导航,逐层到达目标区域。
构建过程:
- 为每个新插入的向量随机选择一个层级 (layer)
- 在该层级及更高层级上,找到最近的 M 个向量作为邻接点
- 连接新向量与这些邻接点,形成图的边
查询过程:
- 从最高层的任意点开始(通常是入口点)
- 在该层贪心搜索,找到最近邻
- 下降到下一层,从上层找到的最近邻继续贪心搜索
- 重复直到到达第 0 层,返回 K-NN
性能: 查询时间复杂度 O(log N),构建复杂度 O(N log N)
IVF (Inverted File Index)
思路: 先用 K-means 将向量空间分成 K 个聚类簇,每个簇由其聚类中心代表。查询时,找最近的聚类中心,然后只在相关簇内搜索。
构建过程:
- 使用 K-means 算法将全部向量分成 K 个簇
- 为每个簇维护一个倒排表 (inverted list),记录属于该簇的向量
- 保存每个簇的聚类中心向量
查询过程:
- 计算查询向量到所有聚类中心的距离
- 选择最近的 nprobe 个簇(通常 nprobe = 1 到 10)
- 在这些簇内的向量中进行线性搜索或进一步优化
性能: 当 nprobe 较小时速度快,但精度依赖于簇质量
Product Quantization (PQ)
思路: 将高维向量分成多个子段,每个子段独立量化。大幅减小存储空间同时保留相似度计算能力。
工作原理:
- 将 D 维向量分成 m 段,每段 d 维
- 对每段独立进行 K-means 量化,产生 256 个聚类中心
- 原向量用 m 个字节表示 (每字节是段的聚类索引)
- 查询时,用段级距离近似计算完整距离
优势: 存储减少 100-1000 倍,距离计算仍然快速
ScaNN (Scalable Nearest Neighbors) - Google
创新点: 各向异性向量量化 (Anisotropic Vector Quantization)。在量化时考虑各个方向的不同重要性,比等向量化的 PQ 更精确。
特点: Google 内部使用,在 TIMIT 等标准数据集上性能最优
主流向量数据库对比
| 数据库 | 架构 | ANN 算法 | 部署方式 | 特点 | 适用场景 |
|---|---|---|---|---|---|
| Pinecone | 托管云服务 | HNSW + 优化 | Serverless | 完全托管,开箱即用,支持元数据过滤 | 快速原型,小中型企业 |
| Weaviate | 分布式,模块化 | HNSW | 自托管 + 云 | 开源,混合搜索 (dense + sparse),GraphQL API | 混合搜索需求,自有基础设施 |
| Qdrant | Rust 实现,高性能 | HNSW | 自托管 + Qdrant Cloud | 低延迟,高吞吐,成熟的 API | 高性能需求,大规模检索 |
| Milvus | 分布式,可扩展 | HNSW, IVF, DiskANN | Kubernetes 友好 | 开源,支持多种 ANN,GPU 加速 | 超大规模企业,云原生 |
| ChromaDB | 嵌入式 + 服务器 | HNSW | Python 库或服务 | 轻量级,零配置,内置嵌入模型 | 快速原型,学习项目 |
| pgvector | PostgreSQL 扩展 | IVFFlat, HNSW | PostgreSQL 插件 | 与关系数据库无缝集成,SQL 查询 | 已有 PostgreSQL,混合业务 |
| FAISS | 库(非数据库) | IVF, PQ, HNSW 等 | 本地库 | Facebook 开源,多 GPU 支持,研究友好 | 研究,离线批处理 |
面试考点:
- HNSW 的基本原理和查询复杂度?
- IVF 和 HNSW 的区别与权衡?
- Product Quantization 如何减小内存占用?
- 如何为不同场景选择合适的向量数据库?
5. 分块策略 (Chunking)
为什么需要分块?
常见分块策略
1. 固定大小分块 (Fixed Size)
最简单的方法:按固定字符数或 token 数切分文本。
chunk_size = 512, overlap = 50
优点: 实现简单,计算快
缺点: 可能在句子中间或语义边界处切断,降低检索质量
2. 递归字符分块 (Recursive Character Split)
LangChain 默认方法。按照层级分隔符 (如 "\n\n", "\n", " ", "") 递归切分,尽量保持语义完整性。
separators = ["\n\n", "\n", " ", ""]
递归选择分隔符直到块大小合适
优点: 保持段落和句子的完整性
缺点: 对格式不规范的文本效果差,仍需要调参
3. 语义分块 (Semantic Chunking)
基于嵌入相似度检测语义边界。计算相邻句子的嵌入相似度,当相似度下降到阈值以下时,认为找到了语义边界。
优点: 语义感知,分块质量最高
缺点: 计算成本高(需要嵌入每个句子),推理时间长
工具: llamaindex, langchain 都有语义分块的实现
4. 文档结构感知分块 (Document-Aware Chunking)
利用文档的结构信息(标题、段落、章节、表格等)进行分块,保留层级关系。
实现: 先解析 Markdown 或 HTML,按标题层级组织,然后在叶子章节级别做分块
优点: 保留文档上下文,支持层级查询
缺点: 需要针对特定格式的解析器
5. 父子分块 (Parent-Child Chunking)
创建两个层级的块:小块用于向量检索,大块作为最终的上下文注入。检索时返回小块ID,但将对应的大块注入提示词。
优点: 兼顾检索精度(小块) 和上下文丰富度(大块)
缺点: 需要额外的映射管理
6. Late Chunking (Jina AI)
先对整个长文档进行嵌入,然后基于已计算的嵌入进行分块,而非先分块再嵌入。
优点: 充分利用嵌入模型的长上下文能力,避免分块导致的信息丢失
缺点: 嵌入成本高,需要支持长上下文的模型
分块参数选择
| 参数 | 典型值 | 影响因素 | 调优方向 |
|---|---|---|---|
| Chunk Size | 256-1024 tokens | 嵌入模型限制,文本粒度需求 | 更小 → 精度高但覆盖面小;更大 → 上下文丰富但语义分散 |
| Chunk Overlap | 10-20% (of chunk size) | 文本连贯性需求,上下文边界问题 | 更大 → 减少边界截断问题但增加冗余;更小 → 节省成本 |
| Strategy | Recursive / Semantic | 文本特性,质量要求,计算预算 | 快速原型用 Recursive;关键应用用 Semantic |
面试考点:
- 为什么需要分块?
- 如何选择分块大小和重叠?
- 什么是语义分块?优缺点?
- 父子分块模式的优势?
6. 检索策略
检索方式对比
稠密检索 (Dense Retrieval)
使用向量相似度搜索。查询和文档都转化为向量,计算向量相似度,返回最相似的 K 个文档。
优点: 捕捉语义相似性,跨语言检索
缺点: 需要额外的嵌入计算和向量存储
稀疏检索 (Sparse Retrieval) - BM25
经典的信息检索方法,基于 TF-IDF 和词的统计特性。计算查询词和文档词的加权匹配分数。
BM25 公式:
score(q, d) = Σ IDF(q_i) * (f(q_i, d) * (k1 + 1)) / (f(q_i, d) + k1 * (1 - b + b * |d| / avgdl))
其中 f(q_i, d) 是词 q_i 在文档 d 中的频率,|d| 是文档长度
优点: 快速、可解释、精确匹配,不需要嵌入
缺点: 无法理解语义,依赖关键词匹配
混合搜索 (Hybrid Search)
结合稠密和稀疏检索的优势。同时执行向量搜索和 BM25 搜索,然后融合结果。
融合方法:
- 加权组合:
score = w * dense_score + (1-w) * sparse_score - 倒数排名融合 (RRF):
score = Σ 1/(k + rank_i)其中 k 通常为 60
优点: 综合了精确匹配和语义匹配,性能最优
多向量检索 (Multi-Vector) - ColBERT
不是为整个文本生成单个向量,而是为每个词生成一个向量。查询的每个词与文档的所有词向量进行匹配。
sim(q, d) = Σ_i max_j (q_i · d_j)
MaxSim:对于每个查询词,找到与文档中最相似的词,求和
优点: 介于词级和文档级之间,精度高
缺点: 计算和存储成本高
面试考点:
- BM25 算法的原理和参数含义?
- 密集检索 vs 稀疏检索的权衡?
- 混合搜索如何实现和融合结果?
- ColBERT 的多向量方法有什么优势?
7. 高级 RAG 技术
查询优化
查询改写 (Query Rewriting)
用 LLM 改进用户的原始查询,使其更容易被检索系统理解。例如,将 "我怎样才能..." 改写为 "方法:..."。
实现: 一个简单的 LLM 调用,给定用户查询和一些示例,返回改写后的查询
假设性文档嵌入 (HyDE)
不直接用用户查询检索,而是先让 LLM 生成一份假设性的相关文档,然后用这个假设文档的嵌入进行检索。
直观理解: 假设性文档通常包含查询中暗示的关键信息和上下文,比用户简短的查询更容易匹配真实文档。
多查询 (Multi-Query)
LLM 生成用户查询的多个语言变体或相关查询,然后分别进行检索,最后合并结果。
优点: 覆盖多个角度的表述方式,提高召回率
Step-Back Query
将用户的具体查询抽象化为更高层次的问题。例如,从 "COVID-19 对中国经济的影响" 抽象到 "大规模传染病对经济的影响",以检索更相关的背景信息。
检索后处理
重排 (Reranking)
初步检索返回 Top-K 文档后,使用交叉编码器 (Cross-Encoder) 对这些文档进行精排。
方法对比:
- Bi-encoder (检索用): 分别编码查询和文档,计算向量相似度。快但精度有限。
- Cross-encoder (重排用): 联合编码 (query, document) 对,直接预测相关性分数。精确但计算成本高。
流程: 密集检索 (Fast, 快速返回候选) → 交叉编码器重排 (Slow, 精确排序)
工具: Cohere Rerank, BGE-reranker, ColBERT 等
上下文压缩 (Contextual Compression)
从检索到的文档中提取最相关的片段,而不是返回整个文档。减少输入给 LLM 的文本量,降低成本同时提高相关性。
Lost in the Middle Problem
研究表明,当多个文档被拼接到 LLM 的提示词中时,中间的文档往往被忽视。LLM 倾向于关注开头和结尾的文档。
解决方案: 将最重要的相关文档放在提示词的开头或结尾,而不是中间。
高级架构模式
递归检索 (Recursive Retrieval)
多轮检索,逐步细化。初次检索返回粗粒度结果后,基于中间生成的内容,进行更精细的第二轮检索。
纠正性 RAG (Corrective RAG, CRAG)
检索后评估检索文档的相关性:
- 如果相关性高 → 直接用于生成
- 如果相关性低 → 降级到 web 搜索或其他知识源
优点: 自适应地处理检索失败的情况
自适应 RAG (Self-RAG)
模型在生成过程中自己决定是否需要检索。对于能从参数知识中回答的问题,跳过检索;对于需要外部知识的问题,触发检索。
实现: 使用特殊 token (如 [RETRIEVE]) 标记检索点,模型学会何时生成这个 token
适应性 RAG (Adaptive RAG)
根据查询复杂度或类型选择不同的检索策略:
- 简单查询 → Naive RAG (快速)
- 复杂查询 → Advanced RAG + 多轮检索
- 事实性查询 → 混合搜索
- 推理性查询 → 知识图谱 + 检索
8. GraphRAG (Microsoft)
核心思想
GraphRAG 不仅检索相关文档,而是从文档中构建知识图谱 (Knowledge Graph),利用图结构的全局视角来回答问题。特别适合需要综合多个信息源的复杂问题。
工作流程
实体和关系提取
使用 LLM (如 GPT-4) 从文本中提取实体和它们之间的关系。例如,从 "张三是阿里巴巴的 CTO" 中提取实体 (张三, 阿里巴巴) 和关系 (任职)。
知识图谱构建
将提取的实体和关系组织成有向图。每个实体是节点,每个关系是边,包含关系的类型和属性。
社区检测
使用 Leiden 算法(比 Louvain 更优)对图进行社区检测,找到紧密相关的实体簇。每个社区代表一个领域或话题。
自底向上的社区摘要
对每个社区及其子社区,使用 LLM 生成摘要。形成多层次的摘要树,从叶子社区的详细摘要到根社区的高层概括。
查询路由与搜索
全局查询 (Global): 并行查询所有社区摘要,获得数据集的全局视角。
本地查询 (Local): 基于查询内容精准定位相关社区,返回详细信息。
全局查询 vs 本地查询
| 查询类型 | 处理方式 | 特点 | 适用问题类型 |
|---|---|---|---|
| 全局查询 (Global) | Map: 并行查询所有社区 Reduce: 汇总聚合结果 |
综合整个数据集,获得全景视图 | 宏观分析,趋势总结,跨领域综合 |
| 本地查询 (Local) | 定位相关社区,深入探索细节 | 精确到特定话题,信息密集 | 微观分析,特定实体追踪,关系探索 |
GraphRAG 的优势与局限
优势
- 全局视角:能综合多个信息源的关键观点
- 关系理解:显式建模实体和关系,支持复杂推理
- 可解释性:知识图谱提供清晰的推理链
- 长文档处理:通过社区分解,能处理很长的文档集合
局限
- 构建成本高:需要 LLM 多次调用进行提取和摘要
- 提取准确性:LLM 提取的实体和关系可能不完整或有误
- 复杂性:系统复杂,难以调试和优化
- 适应性:对于高度动态的数据或特定领域知识,效果可能一般
LightRAG
LightRAG 是 GraphRAG 的轻量级替代方案,降低了构建和查询的成本,同时保持了图结构的优势。相比 GraphRAG 的多层社区和复杂摘要,LightRAG 使用更简化的图结构和查询策略。
9. Function Calling / Tool Use
什么是 Function Calling?
Function Calling 让 LLM 有能力调用外部函数或工具,而不仅仅生成文本。模型能理解何时需要调用工具、调用哪个工具、传递什么参数,然后应用程序执行函数并将结果返回给模型。
OpenAI Function Calling
定义函数模式
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["location"]
}
}
}
模型返回 tool_calls
{
"id": "chatcmpl-xxx",
"choices": [{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_xyz",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\": \"San Francisco, CA\", \"unit\": \"celsius\"}"
}
}
]
}
}]
}
并行函数调用
# 一个 API 调用可以同时调用多个函数
# 模型返回多个 tool_calls,应用程序并行执行
tool_calls = response.choices[0].message.tool_calls
results = [execute_function(tc.function.name, tc.function.arguments) for tc in tool_calls]
Anthropic Tool Use (Claude)
工具定义
tools = [
{
"name": "get_weather",
"description": "Get weather for a location",
"input_schema": {
"type": "object",
"properties": {
"location": {"type": "string"},
"unit": {"enum": ["celsius", "fahrenheit"]}
},
"required": ["location"]
}
}
]
response = client.messages.create(
model="claude-opus",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "What's the weather in NYC?"}]
)
处理工具使用
# 检查响应中是否有工具调用
for block in response.content:
if block.type == "tool_use":
tool_name = block.name
tool_input = block.input
tool_use_id = block.id
# 执行工具
result = execute_tool(tool_name, tool_input)
# 将结果返回模型
messages.append({
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use_id,
"content": str(result)
}
]
})
执行流程
面试考点:
- Function Calling 的工作原理?
- OpenAI 和 Anthropic 的工具定义格式区别?
- 如何设计好的函数模式?
- 并行函数调用的优势和应用场景?
10. MCP (Model Context Protocol)
什么是 MCP?
MCP 是 Anthropic 在 2024 年 11 月推出的开放标准,用于统一 LLM 与外部工具、数据源、应用的连接方式。类似于"LLM 应用的 USB 标准",使得工具开发者和应用开发者可以独立工作,通过 MCP 标准进行集成。
MCP 的三大能力
Tools (工具/函数)
让 LLM 可以调用的函数。类似 Function Calling,但以标准化的方式定义和执行。
示例: 查询数据库、调用 API、执行计算、文件操作
Resources (资源/数据)
LLM 可以访问的数据源或上下文。允许应用向 LLM 提供动态的、上下文相关的信息。
示例: 文件内容、数据库查询结果、用户会话数据、实时数据流
Prompts (提示模板)
可复用的提示词模板,可以包含参数和动态内容。允许统一管理和版本控制提示词。
示例: 代码审查提示、内容生成模板、问题分类提示
MCP 架构
MCP vs Function Calling
| 特性 | MCP | Function Calling (OpenAI/Anthropic) |
|---|---|---|
| 定位 | 开放标准协议 | 模型 API 功能 |
| 范围 | Tools + Resources + Prompts | 仅 Tools |
| 传输 | stdio/HTTP/SSE | HTTP (API 调用) |
| 适用 | 复杂的多工具系统,需要数据上下文 | 简单函数调用,单个 API 调用 |
| 学习曲线 | 较陡,需要理解协议 | 较平,易于上手 |
MCP 的发展潜力
- 生态扩展: Anthropic 宣布超过 1000 个开源 MCP servers 已经上线
- 跨平台支持: 不仅支持 Claude,也在与其他 LLM 厂商合作
- 统一接口: 将成为 LLM 应用与外部系统连接的事实标准
- 企业应用: 为企业安全地集成 LLM 提供了标准化的方式
面试考点:
- MCP 是什么?与 Function Calling 的区别?
- MCP 的三大能力(Tools, Resources, Prompts)分别是什么?
- MCP 的传输方式有哪些?各自适用场景?
- 如何开发一个 MCP Server?
11. RAG 评估
评估的多个层级
组件级评估指标
检索 (Retrieval) 指标
| Precision@K | 前 K 个检索结果中,有多少是相关的 | Precision@5 = 相关文档数 / 5 |
| Recall@K | 所有相关文档中,前 K 个结果覆盖了多少 | Recall@5 = 检索到的相关数 / 总相关数 |
| MRR (Mean Reciprocal Rank) | 第一个相关结果的位置倒数的平均 | MRR = 平均(1/rank_of_first_relevant) |
| NDCG (Normalized Discounted Cumulative Gain) | 考虑结果排序和相关程度的加权指标 | 评估排序质量,范围 [0,1] |
生成 (Generation) 指标
| Faithfulness | 生成的答案是否忠实于检索到的文档内容 | 评估幻觉程度,通常用 LLM 自动评估 |
| Answer Relevancy | 生成的答案是否回答了用户的问题 | 衡量答案与查询的相关性 |
| Hallucination Rate | 答案中完全虚构(无根据)的内容比例 | 越低越好,理想值接近 0 |
RAGAS 框架
RAGAS (Retrieval-Augmented Generation Assessment) 是一个开源框架,专门用于自动化 RAG 系统评估。它提供了一套无需人工标注的自动化指标。
Faithfulness
衡量生成答案中有多少内容可以从检索的上下文中推导出来。使用 LLM 检测答案中的声称,并验证其是否能从上下文支持。
计算: 可被上下文支持的声称比例
范围: [0, 1],越高越好
Context Relevancy (Context Precision)
检索到的上下文中,有多少句子对回答问题是必要的。低相关性表示检索中有许多噪声。
计算: 必要上下文的比例
范围: [0, 1],越高越好
Answer Relevancy
生成答案与用户问题的相关程度。使用 LLM 将答案改写成问题,比较改写问题与原问题的相似度。
计算: 基于向量相似度的相关性评分
范围: [0, 1],越高越好
Context Recall
检索到的所有上下文中,回答问题所需的信息占比。评估检索的完整性。
计算: 支持性证据的覆盖比例
范围: [0, 1],越高越好
RAGAS 使用示例
from ragas.metrics import (
answer_relevancy, faithfulness, context_precision, context_recall
)
from ragas import evaluate
# 定义数据集:[(question, answer, contexts), ...]
dataset = [
{
"question": "What is AI?",
"answer": "AI is artificial intelligence...",
"contexts": ["AI stands for Artificial Intelligence..."]
}
]
# 评估
results = evaluate(
dataset=dataset,
metrics=[answer_relevancy, faithfulness, context_precision, context_recall]
)
print(results)
评估的实践建议
- 不依赖单一指标: 综合考虑检索、生成、端到端的多个指标
- 建立基准数据集: 针对应用领域创建金标数据集,进行对标评估
- 定期监控: 在生产环境中持续收集样本,定期评估系统性能
- 人工评估: 虽然自动评估方便,但人工评估仍然是最可靠的方式
- A/B 测试: 比较不同配置的 RAG 系统性能
面试考点:
- 如何评估 RAG 系统?主要指标有哪些?
- RAGAS 框架的四个核心指标分别衡量什么?
- 检索精度和生成质量的权衡?
- 如何在生产环境中持续评估和优化 RAG 系统?
12. 面试高频问题
Q1: 什么是 RAG?RAG 解决了什么问题?
核心要点: RAG = Retrieval-Augmented Generation,通过检索外部知识库的相关文档,将其作为上下文注入给 LLM,让模型基于真实、最新的信息生成答案。解决知识截止、幻觉、私有数据访问问题。
Q2: Naive RAG vs Advanced RAG 有什么区别?
核心要点: Naive RAG 流程简单(分块 → 嵌入 → 检索 → 生成),但检索精度低。Advanced RAG 添加了查询优化、重排、上下文压缩等技术,显著提升了质量。Modular RAG 进一步支持模块化和条件路由,允许对不同类型查询采用不同策略。
Q3: 如何选择嵌入模型?
核心要点: 考虑维度 (成本/精度权衡)、训练数据 (语言和领域覆盖)、微调能力、成本预算。通用场景用 text-embedding-3-small,中文优化用 BGE-M3,需要长文本支持用 Jina。优先考虑开源模型便于私有部署和微调。
Q4: HNSW 和 IVF 算法的区别?各自何时使用?
核心要点: HNSW 是多层图结构,查询复杂度 O(log N),精度高但内存占用大。IVF 是聚类+倒排表,查询速度受 nprobe 影响,内存占用小。大规模、对精度要求高用 HNSW;成本敏感、接受精度略微下降用 IVF;超大规模考虑 PQ 量化。
Q5: 分块大小和重叠应该如何选择?
核心要点: chunk_size 通常 256-1024 tokens(更小 → 精度高但上下文少;更大 → 上下文丰富但语义分散)。overlap 通常 10-20%(保持连贯性,减少边界截断)。最好通过 RAGAS 等框架在真实数据上实验,而不是凭经验选择。
Q6: 什么是混合搜索?为什么它比单一方法更好?
核心要点: 混合搜索结合了稠密检索(语义相似)和 BM25(精确词匹配)。稠密检索容易漏掉关键词精确匹配,BM25 无法理解语义。混合搜索通过 RRF 或加权融合两者,兼顾精确性和语义理解,通常比单一方法性能更优。
Q7: 重排 (Reranking) 的作用和成本权衡?
核心要点: 重排使用交叉编码器对候选文档精排,显著提高相关性。但计算成本高 (对每个候选计算相关性)。实践中常用两阶段:bi-encoder 快速检索返回 Top-K,cross-encoder 重排 Top-K。为成本考虑,只对 Top-K 做重排,而不是整个文档库。
Q8: GraphRAG 相比传统 RAG 的优势和劣势?
核心要点: GraphRAG 通过知识图谱+社区检测,提供全局视角,特别适合综合多源信息的复杂问题。优势:全局视角、关系建模、可解释性。劣势:构建成本高、提取准确性依赖 LLM、系统复杂、调试困难。适合知识密集、需要关系理解的场景。
Q9: 什么是 MCP?与 Function Calling 有什么区别?
核心要点: MCP (Model Context Protocol) 是 Anthropic 推出的开放标准,统一 LLM 与外部工具、数据的连接方式。范围比 Function Calling 更广(Tools + Resources + Prompts)。Function Calling 仅限工具调用,MCP 还能提供动态上下文和提示模板。MCP 是协议标准,Function Calling 是模型 API 功能。
Q10: 如何评估一个 RAG 系统的质量?
核心要点: 多层级评估:(1) 检索评估 - Precision@K, Recall@K, NDCG;(2) 生成评估 - Faithfulness, Answer Relevancy;(3) 端到端 - Answer Correctness。使用 RAGAS 框架自动化评估。建立基准数据集,定期人工抽样审核,A/B 对比不同配置。优先追求 Faithfulness(减少幻觉),再追求 Answer Relevancy(回答准确度)。