RAG面试题|全网最全RAG面试题目 HOT火火火

88 阅读41分钟

RAG

1.什么是RAG

RAG,全称是 Retrieval-Augmented Generation,中文可以理解为 “检索增强生成”

而是一种将**信息检索(Information Retrieval)系统与大语言模型(LLM)生成(Generation)**能力相结合的技术框架。

解决了LLM的:

知识局限性 (Knowledge Cutoff):LLM 的知识都来自于其训练数据,这些数据有明确的截止日期。对于截止日期之后的新知识,模型是无法感知的。

事实幻觉 (Hallucination):LLM 在回答它不确定的问题时,有时会“编造”听起来合理但实际上是错误的答案,这在需要高度事实准确性的场景中是致命的。

缺乏领域专有知识 (Lack of Domain-Specific Knowledge):对于一些非常专业或企业内部的私有领域,通用的大模型由于没有接触过相关数据,无法提供精准的回答。

当模型需要回答问题时,不直接让它依赖内部知识进行生成,而是先从一个外部的、可信的知识库中检索出与问题最相关的信息,然后将这些信息作为上下文(Context)和原始问题一起提供给大语言模型,让它基于这些“新鲜的”、“准确的”信息来组织和生成最终的答案。

RAG可以分为两个阶段:

  1. 数据准备/索引阶段 (Data Preparation / Indexing - Offline)

这个阶段是预处理工作,目标是建立一个可供快速检索的知识库。

  • 数据加载 (Load):首先,我们需要加载原始的知识文档,来源可以是 PDF、HTML、数据库记录、Notion/Confluence 页面等等。
  • 文档切分 (Chunking/Splitting):由于 LLM 的上下文窗口长度有限,我们不能将整篇长文档直接作为输入。因此,需要将文档切分成大小适中的、有意义的文本块(Chunks)。切分策略很关键,可以按段落、句子,或者固定长度来切,好的切分能保证语义的完整性。
  • 向量化 (Embedding):这是 RAG 的核心步骤之一。我们需要将每个文本块通过一个 Embedding Model(例如 aall-mpnet-base-v2, bge-large-zh 等)转换成一个高维的数字向量(Vector)。这个向量可以被认为是该文本块在语义空间中的“坐标”。语义上相近的文本块,其向量在空间中的距离也更近。
  • 数据索引与存储 (Index & Store):最后,我们将生成的文本块原文和其对应的向量存储到一个专门的数据库中,这个数据库通常被称为 向量数据库(Vector Database),例如 Milvus、Pinecone、Chroma,或者像 Elasticsearch、PostgreSQL 加上相应的向量检索插件。
  1. 检索生成阶段 (Retrieval & Generation - Online)

这个阶段是用户与系统交互、实时生成答案的过程。

  • 用户提问 (User Query):用户输入一个问题。

  • 查询向量化 (Query Embedding):使用与数据准备阶段相同的 Embedding Model,将用户的查询也转换成一个向量。

  • 向量检索 (Vector Retrieval):用查询向量,去向量数据库中执行一个相似性搜索(通常是余弦相似度或欧氏距离计算)。目标是找出与查询向量“距离”最近的 K 个文本块向量,这些文本块就是与用户问题最相关的信息。

  • 构建提示词 (Prompt Construction):将检索到的这 K 个相关的文本块(即上下文 Context)与用户的原始问题(Query)组合成一个新的、更丰富的提示词(Prompt)。这个 Prompt 的模板通常类似于:

    "请根据以下提供的上下文信息来回答用户的问题。如果上下文中没有足够信息,请回答你不知道。

    上下文: [这里是检索到的文本块 1] [这里是检索到的文本块 2] ...

    问题: [用户的原始问题]"

  • 生成答案 (Answer Generation):将这个增强后的 Prompt 发送给大语言模型(如 GPT-4, Llama3 等)。LLM 会基于我们提供的上下文来生成一个更加准确、可靠的答案。

  • 返回结果 (Return Response):将 LLM 生成的答案返回给用户。有时为了增加答案的可信度,还会附上检索到的原文出处链接。

2.什么是 RAG 中的 Rerank?

Rerank 是在初始的向量检索(Retrieval)之后,将结果喂给大语言模型(LLM)之前,增加的一个中间精排阶段

它的核心目标是:对初步检索到的文档列表进行二次的、更精细化的排序,从而将最相关的文档排在最前面,提升最终喂给 LLM 的上下文(Context)质量。

分为两个阶段:

  • 粗排 (Retrieval/Recall):通过高效的向量相似度搜索,从海量的文档库中快速捞出 Top N (比如 N=20 或 50) 个候选文档。这一步追求的是**“快”“全”**,希望能把所有可能相关的文档都找出来。
  • 精排 (Rerank):对这 N 个候选文档,使用一个更强大但通常也更慢的排序模型,逐一计算它们与原始问题(Query)的精准相关性分数,然后根据这个分数重新排序。这一步追求的是**“准”**。

那么我们为什么需要Rerank?

  • 提升信噪比:初始检索出的文档可能包含一些“噪音”,即主题相关但内容不直接回答问题的文档。Rerank 可以有效地将这些噪音文档排到后面,把信噪比最高的“黄金上下文”筛选出来。
  • 优化 LLM 的注意力:LLM 在处理长上下文时,存在“迷失在中间(Lost in the Middle)”的问题,即对输入上下文的开头和结尾部分注意力更高,中间部分容易忽略。通过 Rerank 将最关键的信息放在最前面,可以更好地引导 LLM 的注意力。
  • 降低成本/延迟:由于 LLM 的上下文窗口有限且 API 调用成本与 token 数量相关,我们不可能将粗排召回的几十个文档都塞给它。Rerank 帮助我们用更智能的方式,而不是简单地按向量相似度分数截断,来挑选出最有价值的少数几个文档。

模型的差异:

实现 Rerank 的核心在于使用一个 Reranker 模型。这个模型与我们之前提到的 Embedding 模型在架构上有所不同。

  • Embedding 模型 (用于检索):通常是 Bi-Encoder 架构。它独立地为问题(Query)和文档(Document)分别生成向量,然后通过计算这两个向量的距离来判断相关性。它速度快,适合在大规模数据集上进行首次召回。
    • score = similarity(embed(query), embed(document))
  • Reranker 模型 (用于重排):通常是 Cross-Encoder 架构。它将问题(Query)和候选文档(Document)作为一个对(Pair) 同时输入到模型中,让模型内部的注意力机制充分捕捉它们之间复杂的交互关系,然后直接输出一个代表相关性的分数(Score)。
    • score = rerank_model.predict(query, document)

因为 Cross-Encoder 可以直接建模 query 和 document 之间的深层交互,所以它的判断通常比 Bi-Encoder 的向量距离计算要精准得多,但也因此计算量更大、速度更慢,不适合用于海量文档的初筛。

使用:

  • 例如 BAAI 的 bge-reranker-largebge-reranker-base。它们在 Hugging Face 等平台可以找到。
  • 商业 API:一些服务商也提供 Rerank API,比如 Cohere 的 Rerank API,它开箱即用,性能强大。

3.什么混合检索?

混合检索,顾名思义,就是将两种或多种不同的检索技术结合起来,取长补短,以提供比单一技术更全面、更精准的检索结果。

在当前主流的 RAG 应用中,混合检索特指传统关键词检索 (Keyword Search)现代向量检索 (Vector Search) 的结合。

  • 关键词检索 (Keyword Search):
    • 代表技术: BM25 (常用于 Elasticsearch, Lucene)。
    • 工作原理: 基于词频(TF-IDF)和文档频率等统计学原理,精确匹配查询语句中的关键词。一个词在文档中出现次数越多、在整个文档库中越稀有,相关性得分就越高。
    • 优点:
      • 精确性高: 对于包含专有名词、产品型号、错误代码、缩写(如 "JVM", "JDK 1.8")的查询,效果极佳。
      • 速度快,成熟稳定: 技术非常成熟,索引和查询效率都很高。
    • 缺点:
      • 语义理解能力差: 无法理解同义词、近义词或概念。搜索 “automobile” 找不到包含 “car” 的文档。
      • “词汇鸿沟”问题: 必须使用文档中出现过的词才能搜到,无法处理用户用不同措辞表达相同意图的情况。
  • 向量检索 (Vector Search):
    • 代表技术: HNSW, IVF-PQ (常用于 Milvus, Pinecone 等向量数据库)。
    • 工作原理: 使用 Embedding 模型将文本转换成高维向量,捕捉文本的语义信息。通过计算查询向量与文档向量之间的“距离”(如余弦相似度)来找到语义上最接近的结果。
    • 优点:
      • 语义理解能力强: 能轻松跨越“词汇鸿沟”,理解概念和意图。搜索“适合全家去山里玩的车”,可能会找到包含“大空间 SUV”、“越野性能”等关键词的文档。
    • 缺点:
      • 对关键词不敏感: 有时会过度“泛化”,忽略掉那些虽然语义略有偏差、但包含关键“精确词”的重要文档。比如搜索 “iPhone 15 Pro Max 评测”,它可能会返回一篇关于 “Apple 最新旗舰手机” 的文章,而忽略了一篇标题就是 “iPhone 15 Pro Max 深度评测” 的文章。
      • 对于新词或领域黑话处理不佳: 如果 Embedding 模型在训练时没见过某个新词或非常专业的术语,可能无法生成有意义的向量。

混合检索的流程通常是在查询时,并行执行两种检索,然后将两组结果进行智能融合(Fusion),生成一个最终的排序列表。

  1. 并行查询: 用户的查询请求会同时发送给关键词检索引擎和向量检索引擎。
  2. 获取结果: 两个引擎各自返回一个 Top-K 的文档列表,每个列表都带有各自的相关性分数。
  3. 结果融合: 这是最关键的一步。由于 BM25 的分数和向量相似度分数处于不同的尺度,不能直接相加。最常用的融合算法是 RRF (Reciprocal Rank Fusion, 倒数排名融合)
    • RRF 算法思想: 它不关心原始分数是多少,只关心一个文档在不同列表中的排名。一个文档在两个列表中的排名都越高,它在最终结果中的排名就越靠前。
    • RRF Score(doc) = 1 / (k + rank_bm25(doc)) + 1 / (k + rank_vector(doc)) (k 是一个常数,用于防止排名过小时分母太小)
  4. 最终输出: 根据 RRF 分数重新排序,得到一个融合后的、质量更高的文档列表,再将这个列表的 Top-N 作为上下文送给大模型。

混合检索解决的问题:

  • 解决了单纯向量检索对“精确关键词”的失灵问题
    • 问题场景: 用户在内部知识库中搜索一个特定的函数名 calculateGrossMargin() 或者一个服务器错误代码 ERR_CONN_RESET
    • 向量检索的短板: 向量检索可能会找到一些关于“利润计算”或“网络连接问题”的通用文档,但很可能错过包含那个精确函数名或错误码的核心技术文档。
    • 混合检索的优势: 关键词检索会立刻将包含 calculateGrossMargin()ERR_CONN_RESET 的文档排在最前面。通过 RRF 融合,这些高精度结果会被保留下来,确保 LLM 获得了最直接相关的“事实依据”。
  • 提升了对复杂、混合意图查询的召回率和精度
    • 问题场景: 一个用户查询:“给我找一下去年Q3关于‘天狼星计划’项目的复盘报告,特别是关于性能优化的部分。”
    • 查询意图分析: 这个查询既包含需要精确匹配的实体(天狼星计划Q3),也包含需要语义理解的概念(复盘报告性能优化)。
    • 混合检索的优势:
      • 关键词检索锁定包含 天狼星计划Q3 的文档。
      • 向量检索则能找到内容上讨论 项目总结系统性能提升 的文档,即使这些文档没有明确使用“复盘”或“优化”这些词。
      • 两相结合,就能最精准地找到用户想要的那份文档,既满足了实体的约束,又理解了用户的真实意图。
  • 增强了 RAG 系统的鲁棒性和可靠性,减少“幻觉”
    • 问题的根源: RAG 产生幻觉,很多时候是因为检索阶段给错了“原材料”。如果检索返回的上下文是模棱两可或不完全相关的,LLM 就只能基于这些不准确的信息进行“猜测”和“创作”。
    • 混合检索的贡献: 通过结合两种检索范式,混合检索极大地提高了检索到“正确答案”的概率。它为 LLM 提供了一个经过双重验证、信噪比更高的上下文。有了更坚实的事实基础,LLM 生成答案的准确性和忠实度会显著提升。

4.在 RAG 应用中为了优化检索精度,其中的数据清洗和预处理怎么做?

在RAG应用中,大模型的生成能力是上限,而我们检索系统的精度则是下限,它决定了这个上限能被多大程度地发挥出来。而检索精度的核心,恰恰就始于数据清洗和预处理这个阶段

数据预处理的最终目标,是生成一系列**“检索友好”(Retrieval-Friendly)**的文本块(Chunks)。这些文本块应该具备三个核心特质:

  1. 高信噪比 (High Signal-to-Noise Ratio):每个块都应包含清晰、集中的信息,剔除所有无关的“噪音”,如广告、导航栏、格式错乱的字符等。
  2. 语义内聚 (Semantic Cohesion):每个块自身应该是一个语义完整、自洽的单元。它应该能独立地表达一个完整的意思,避免一个完整的段落被拦腰截断。
  3. 上下文感知 (Context-Awareness):虽然每个块是独立的,但它应该保留必要的上下文信息。这可以通过块与块之间的重叠(Overlap)或附加元数据(Metadata)来实现。

工作步骤:

  1. 原始数据提取与净化 (Extraction & Purification)

这是最基础的“物理清洗”,目标是从各种格式的原始文档中提取出纯净的文本

  • 统一格式转换:无论原始数据是 PDF、Word、HTML、Markdown 还是数据库记录,第一步都是将其转换为统一的、易于处理的纯文本或 Markdown 格式。
    • Java实践: 我们可以使用强大的 Apache Tika 库,它能自动检测并从上千种文件类型中抽取出文本和元数据。
  • 剔除无关元素
    • 对于网页数据,需要剔除导航栏、页眉页脚、广告、推荐阅读等噪音。Jsoup 这样的 Java HTML 解析库是做这件事的利器。
    • 对于 PDF 或扫描件,需要处理 OCR 识别带来的错误、删除水印、页码等。
    • 清理多余的空格、无法识别的乱码、特殊的控制字符。
  • 处理半结构化数据
    • 表格(Tables): 直接将表格拍平成文本,会丢失其行列的结构化信息。更好的做法是将其转换为 Markdown 格式的表格,或者将其内容序列化为描述性语句(例如:“表格显示,2024年Q1季度的销售额为100万”)。
    • 列表(Lists): 保持列表的结构和顺序,而不是将它们合并成一个大段落。
  1. 内容增强与规范化 (Enhancement & Normalization)

这一步是“化学加工”,目标是提升文本的语义清晰度和一致性

  • 缩写与术语扩展:将领域内的专有缩写展开。例如,将 “JVM” 替换或补充说明为 “Java Virtual Machine (JVM)”。这有助于弥合用户查询和文档内容之间的“词汇鸿沟”。
  • 去除模糊指代:在某些情况下,可以尝试用更明确的实体替换“它”、“这个”、“前者”等代词,但这需要更高级的 NLP 技术,需要谨慎使用。
  • 数据去重:在文档或段落级别进行内容去重,避免重复信息干扰检索结果的排序,浪费宝贵的上下文窗口。
  1. 策略性分块 (Strategic Chunking)

这是 RAG 预处理中最具技术含量、对结果影响最大的一步。简单的按固定字数切分(Fixed-size Chunking)往往效果最差。

  • 内容感知分块 (Content-Aware Chunking)
    • 递归分割 (Recursive Splitting):这是目前最主流且有效的方法。它会优先尝试使用最大的语义单元(如段落 \n\n)进行分割,如果分割后的块仍然太大,则退一步使用次级单元(如句子 .)分割,以此类推。这最大限度地尊重了原文的自然结构。
    • 基于文档结构的分块:如果文档是 Markdown 或 HTML 格式,我们可以利用其标题层级(H1, H2, H3)进行分割。例如,将一个 H2 标题下的所有内容作为一个大的逻辑块,再对其内部进行递归分割。
  • 块重叠 (Chunk Overlapping)
    • 目的:为了保证一个完整的语义概念在块的边界处不被切断。例如,一个句子的前半句在块A的末尾,后半句在块B的开头,如果没有重叠,单独检索到任何一个块都可能信息不完整。
    • 实践:通常设置 10% 到 20% 的重叠率。块A = [sent 1, sent 2, sent 3],块B = [sent 3, sent 4, sent 5]。这样,关于 sent 3 的完整信息就被保留了下来。
  • 块大小(Chunk Size)的权衡
    • 小块:语义更集中,检索更精确。但可能因为上下文不足导致 Embedding 质量下降,也可能需要检索多个小块才能拼凑出完整答案。
    • 大块:上下文更丰富,利于回答复杂问题。但可能包含太多噪音信息,稀释了核心主题,导致在向量空间中“失焦”。
    • 结论:这是一个需要根据数据特点和应用场景不断实验和调整的超参数。
  1. 元数据提取与关联 (Metadata Extraction & Association)

为每个文本块打上丰富的元数据标签,是**实现高级检索(如混合检索中的过滤)**的关键。

  • 提取什么?
    • 来源信息:文档名、URL、创建/修改日期、作者。
    • 结构信息:所属章节、标题、父标题。
    • 实体信息:从文本中提取出的关键实体(人名、地名、产品名、技术术语)。
    • 摘要信息:可以利用小模型为每个块生成一个简短的摘要,作为额外的元数据。
  • 如何使用?
    • 前置过滤 (Pre-filtering):在进行向量检索前,先通过元数据过滤掉不相关的文档。例如,用户问“告诉我去年关于XX项目的技术方案”,我们可以先过滤出 date > last_yeartitle.contains("XX项目") 的文档,再在这些文档的块中进行向量搜索。这能极大地提升检索速度和精度。
    • 增强上下文:将重要的元数据(如标题)附加到块内容的前面,再进行 Embedding。"Title: JVM Memory Model\nContent: JMM specifies..." 这样的块,其向量表示会更加精确。

5.为什么需要查询扩展

简单来说,查询扩展就是在进行实际检索之前,通过算法自动地对用户的原始查询进行改写、丰富和增强,生成一个或多个语义更丰富、表达更多样化的新查询

常见的查询扩展技术包括:

  1. 同义词扩展:将查询中的词替换或补充为其同义词。例如,用户查询“JVM 调优”,可以扩展为 ("JVM" OR "Java 虚拟机") AND ("调优" OR "性能优化")
  2. 相关术语扩展:不仅仅是同义词,还包括下位词、上位词、概念相关的词。例如,查询“数据库”,可以扩展补充“MySQL”、“PostgreSQL”、“索引”、“事务”等。
  3. 使用大语言模型(LLM)进行查询重写和生成:这是目前在 RAG 中最强大也最流行的方式。我们可以设计一个 Prompt,让 LLM 根据原始查询,从不同的角度生成几个新的、质量很高的问题。
    • 例如,用户原始查询是:“如何解决 OOM?”
    • 我们可以让 LLM 将其扩展为:
      • 查询1 (原始): 如何解决 OOM?
      • 查询2 (具体化): Java 堆内存溢出(Heap Space OOM)的原因和解决方法有哪些?
      • 查询3 (相关领域): 除了堆内存,还有哪些常见的 OOM 类型,比如 Metaspace OOM,应该如何排查?
      • 查询4 (工具和实践): 使用 MAT 或 JProfiler 等工具分析 .hprof 内存转储文件的具体步骤是什么?

在 RAG 应用中,一个集成了查询扩展的工作流通常是这样的:

  1. 用户输入原始查询 Q_orig
  2. Q_orig 发送给一个 LLM(通常是较小的、响应快的模型),让它根据预设的 Prompt 生成 N 个扩展后的查询 [Q_1, Q_2, ..., Q_N]
  3. 并行地Q_orig 和所有扩展查询 [Q_1, ..., Q_N] 去向量数据库进行检索。
  4. 将所有检索到的结果汇总在一起,使用 RRF (Reciprocal Rank Fusion) 等算法进行智能融合和排序。
  5. (可选但推荐)将融合后的 Top-K 结果送入一个 Reranker 模型进行精排。
  6. 将最终最优的几个文档块作为上下文,与 Q_orig 一起送给 LLM 生成最终答案。

6.什么自查询?为什么在 RAG 中需要自查询?

自查询(Self-Querying) 是一种先进的检索技术,它使用一个大语言模型(LLM)作为“查询规划器”,来解析用户的自然语言查询,并自动将其转换成一个包含“元数据过滤条件(Metadata Filters)”和“语义搜索关键词(Semantic Search Query)”的结构化查询。

核心流程:

  • 用户提问: 用户输入一个包含事实约束的自然语言问题。例如:“请给我找找 2023 年之后,由张三发布的关于‘性能优化’的技术文档。”
  • LLM 介入解析: 这个查询首先被发送给一个 LLM(而不是直接去向量数据库)。这个 LLM 的任务不是回答问题,而是**“翻译”**问题。它被指示从查询中抽取出两部分信息:
    • 元数据过滤器 (Metadata Filters): 查询中所有可以被精确匹配的结构化条件。在上面的例子中,它会抽取出:
      • 发布年份 >= 2023
      • 作者 == "张三"
    • 语义搜索内容 (Semantic Search Query): 查询的核心语义部分,用于进行向量相似度搜索。在上面的例子中,这部分是:
      • “性能优化”的技术文档
  • 生成结构化查询: LLM 会将上述解析结果输出为一个结构化的格式(通常是 JSON)。
  • 执行分步检索: RAG 的检索器(Retriever)接收到这个结构化指令后,会执行一个两步操作:
    • 第一步(过滤): 它首先向数据库(可以是向量数据库本身,如果它支持元数据过滤;也可以是 Elasticsearch 等)发送一个元数据过滤请求,筛选出所有满足 年份 >= 2023作者 == "张三" 的文档。
    • 第二步(搜索): 然后,它只在第一步筛选出的小得多的数据子集上,执行对 “性能优化”的技术文档 的向量相似度搜索。
  • 返回结果: 最终返回给用户的是经过精确过滤后再进行语义排序的高度相关的文档。

7.什么提示压缩?为什么在 RAG 中需要提示压缩?

在把从知识库检索出的上下文(Context)和用户问题(Query)喂给 LLM 之前,先对它们进行一次“瘦身”,以达到降本增效和提升性能的目的。显著减少 Prompt 中的 Token 数量,同时最大限度地保留回答用户问题所必需的关键信息和上下文关系。

提示压缩主要有两种实现路径:

  1. 抽取式压缩 (Extractive Compression):
    • 方法: 从检索到的上下文中,直接抽取出与用户问题最相关的、最重要的句子或短语。其他无关的句子则被丢弃。
    • 实现: 这通常通过一个小型模型来完成。比如,我们可以将每个句子进行 Embedding,然后计算它与用户查询向量的相似度,只保留相似度最高的 Top-N 个句子。
    • 优点: 简单快速,能有效保留原文的关键信息。
  2. 生成式/抽象式压缩 (Abstractive Compression):
    • 方法: 使用一个小型 LLM 来“阅读”并“理解”检索到的上下文,然后用它自己的话重新生成一个更短、更精炼的摘要。
    • 实现: 设计一个 Prompt,例如:“请根据以下上下文,总结出能回答‘{用户问题}’的关键信息点。”然后将检索到的文档作为上下文输入给一个小型 LLM(如 GPT-3.5-Turbo, Llama 3 8B)。
    • 优点: 压缩率更高,语言更连贯,能更好地融合来自不同文档片段的信息。

8.如何进行 RAG 调优后的效果评估?请给出真实应用场景中采用的效果评估标准与方法

一个 RAG 系统主要包含两大核心组件:检索(Retrieval)和生成(Generation)。任何一环出问题都会影响最终结果。因此,我们的评估也必须双管齐下:

  1. 组件级评估(Component-level Evaluation):像做单元测试一样,独立评估检索模块和生成模块的性能。这有助于我们精准定位问题瓶颈。
  2. 端到端评估(End-to-End Evaluation):像做集成测试或用户验收测试(UAT),直接评估用户输入的原始问题和系统输出的最终答案。这衡量的是系统的综合表现和用户体验。

检索:

首先,需要人工构建一个“黄金标准”评测集。它包含一系列有代表性的问题,以及每个问题对应的“正确”文档块(Ground Truth Chunks)。这项工作非常耗时,但却是后续所有自动化评估的基石。

评估标准 (Metric)解释说明评估方法
命中率 (Hit Rate)检索返回的 Top-K 个结果中,是否至少包含一个正确的文档块。这是最基础的指标。如果 Hit Rate 很低,说明检索系统有严重问题,连相关的边都摸不到。计算(至少命中一个正确文档的问题数) / (总问题数)
平均倒数排名 (MRR - Mean Reciprocal Rank)找到的第一个正确文档块出现在检索结果列表中的排名的倒数。例如,第一个正确文档排第3,则倒数排名为 1/3。MRR 是所有问题该值的平均。这个指标衡量的是**“效率”**。MRR 越高,说明系统能越快地把最关键的信息排在前面。对于上下文长度有限的场景,这个指标尤为重要。
精确率@K (Precision@K)检索返回的 Top-K 个结果中,正确文档块所占的比例。例如,K=5,返回5个结果中有3个是正确的,则 Precision@5 = 3/5 = 0.6。衡量检索结果的**“含金量”**。高精确率意味着送给 LLM 的上下文中噪音更少。
召回率@K (Recall@K)检索返回的 Top-K 个结果中,命中的正确文档块占所有正确文档块总数的比例。例如,一个问题总共有4个相关文档块,K=5时我们找到了2个,则 Recall@5 = 2/4 = 0.5。衡量检索结果的**“全面性”**。高召回率意味着系统能把相关的知识点尽可能多地找回来,适合回答需要综合多个信息源的复杂问题。

生成:

验证 LLM 在给定上下文的情况下,能否生成忠实、相关且有用的答案。

这一阶段的评估非常棘手,因为涉及自然语言的“好坏”,很难用精确的数学公式衡量。目前,业界主流采用 LLM-as-a-Judge(让另一个强大的 LLM 作为裁判) 的自动化评估方法,并辅以人工抽样校验。

评估标准 (Metric)解释说明评估方法(LLM-as-a-Judge)
忠实度/接地气 (Faithfulness / Groundedness)生成的答案是否完全基于所提供的上下文信息,没有捏造、歪曲或添加外部知识(即幻觉)。**这是 RAG 的生命线!**向裁判 LLM 提问:“请判断以下‘答案’是否完全由‘上下文’支持,不得引入任何外部信息。回答‘是’或‘否’。”
答案相关性 (Answer Relevancy)生成的答案是否直接、清晰地回应了用户的原始问题。向裁判 LLM 提问:“请判断以下‘答案’是否与‘原始问题’高度相关,并提供了有用的信息。请从1到5打分。”
上下文相关性 (Context Relevancy)检索出的上下文,对于回答用户问题是否有用、是否包含噪音这是对检索结果质量的补充验证。向裁判 LLM 提问:“请判断以下‘上下文’中,有多少比例的句子对于回答‘原始问题’是必要且相关的。请给出一个百分比。”

端到端:

评估标准 (Metric)解释说明评估方法
答案正确性 (Answer Correctness)最终答案在事实上是否正确。这个指标很难自动化,是人工评估的重点。通常会建立一个专家小组,对一小部分(例如 5%)的线上或评测集问题进行事实核查,作为对自动化指标的最终校验。
用户满意度 (User Satisfaction)用户对系统的回答是否满意。这是最直接的业务指标。方法包括: 1. 在应用界面提供**“👍 / 👎”**按钮。 2. 定期进行用户调研(NPS - 净推荐值)。 3. 分析用户追问的次数,追问次数少可能意味着初次回答质量高。
任务完成率 (Task Completion Rate)用户是否通过与 RAG 系统的交互,成功完成了他们的目标。在客服或内部知识库场景中,可以衡量“问题是否被解决”、“工单是否被关闭”、“文档查找时间是否缩短”等与业务流程紧密集成的 KPI。

9.什么是 RAG 中的分块?为什么需要分块?分块的策略?

分块(Chunking)是构建 RAG 系统数据处理流水线中,可以说最核心、最基础,也是对最终效果影响最大的一个步骤。如果说 Embedding 是将知识向量化的过程,那么分块就是决定这些“知识”基本单元形态的艺术。

在 RAG 的语境下,指的是将大型、原始的文档(如一篇 PDF 报告、一个网页、一本电子书)分割成一系列更小的、独立的、但又保持语义连贯的文本片段(Chunks)的过程

分块的好处:

  1. 为了克服技术与模型的硬性限制,比如LLM的上下文窗口,嵌入模型的限制
  2. 为了提升检索与生成的核心质量,一块一块的去检索肯定比全文检索要快,并且准确度高
  3. 出于成本与延迟的现实考量,降低成本。

分块的策略:

固定大小分块

  • 核心思想: 这是最简单、最“暴力”的策略。它不考虑文本的任何语义或结构,直接按照固定的字符数(或 Token 数)进行切割。
  • 区别与特点:
    • 优点: 实现极其简单,计算开销小,处理速度快。
    • 缺点: 严重破坏语义完整性。一个完整的句子、段落甚至一个单词都可能被无情地从中间切断,导致生成的文本块语义不完整、难以理解,进而影响 Embedding 的质量和检索的准确性。
    • 适用场景: 仅适用于完全没有结构、语义不强的纯文本,或者作为快速搭建原型、建立性能基线(Baseline)的初始方案。在生产环境中基本不被推荐

递归字符分块:

    1. 预设一个分隔符列表,按语义重要性从高到低排序,常见的列表是 ["\n\n", "\n", " ", ""](段落 -> 行 -> 空格 -> 字符)。
    2. 它首先尝试用最重要的分隔符(\n\n,段落)来分割整个文档。
    3. 然后检查分割出的每一块的大小,如果某个块仍然大于设定的 chunk_size,它就会递归地用下一个次重要的分隔符(\n,行)对这个过大的块进行再分割。
    4. 这个过程会一直持续下去,直到所有块的大小都小于 chunk_size,或者用尽了所有分隔符。
  • 区别与特点:
    • 优点: 最大限度地保持了语义的内聚性。它会优先保留完整的段落和句子,只有在万不得已时才会粗暴地按字符分割。通用性极强,对各种类型的文本文档都有不错的表现。
    • 缺点: 实现比固定大小分块稍复杂,但现在已有成熟的库(如 LangChain, LlamaIndex)封装好了。
    • 适用场景: 绝大多数 RAG 应用的首选和默认策略。无论是处理报告、文章还是网页内容,它都是一个非常强大的起点。

内容感知分块:

a. 文档结构分块 (Document-Specific Splitting)

  • 核心思想: 直接利用源文档的结构化标记(如 HTML 标签、Markdown 标题)作为分割的依据。
  • 工作原理:
    • 对于 Markdown 文档,可以按标题(#, ##, ###)来分割,将每个标题下的内容作为一个独立的块。
    • 对于 HTML 文档,可以按标签(如 <p>, <li>, <div>)来提取和分割内容块。
  • 区别与特点:
    • 优点: 语义边界最清晰,完全遵循了作者创作时的逻辑结构,生成的块质量非常高。
    • 缺点: 非通用,严重依赖于源文档的格式。如果文档格式不规范或没有结构,此方法就无法使用。
    • 适用场景: 当你的知识库是高度结构化的文档时(如 Confluence 导出页面、API 文档、技术博客),这是最佳选择。

b. 句子分块 (Sentence Splitting)

  • 核心思想: 使用自然语言处理(NLP)库(如 NLTK, spaCy)来识别句子的边界(如句号、问号、感叹号),确保每个块都是一个或多个完整的句子。
  • 工作原理: 调用 NLP 库的句子分割器(Sentence Tokenizer)将文本分割成句子列表,然后按需将连续的句子合并成大小合适的块。
  • 区别与特点:
    • 优点: 保证了最基本的语法单元——句子的完整性,比递归字符分块在某些情况下更精细。
    • 缺点: 单个句子可能上下文不足,导致其向量表示不够丰富。并且,合并多个句子成块的逻辑需要额外设计。
    • 适用场景: 当对语义完整性的要求极高,且文档中的句子普遍较长、信息量充足时可以考虑。通常会作为递归分块的一种补充或变体。

10.Embedding

在 RAG 中的 Embedding 嵌入是什么?

Embedding 指的是使用一个深度学习模型(即 Embedding Model),将人类的自然语言文本(无论是单词、句子还是整个文档块)转换成一个由数字组成的、高维度的数学向量(Vector)

Embedding Model 能够捕捉并编码文本的“语义含义”(Semantic Meaning)。它不仅仅是简单地将文字变成数字,而是将文本映射到一个被称作**“语义空间”(Semantic Space)**的多维坐标系中。在这个空间里:

  1. 语义相近的文本,其向量在空间中的位置也相互靠近。
  2. 语义无关的文本,其向量在空间中的位置则相距遥远。

Embedding 是实现 RAG 核心功能——语义检索(Semantic Search) 的基石。整个流程如下:

  1. 数据索引阶段(离线):我们对知识库中所有分割好的文本块(Chunks)都进行 Embedding 操作,将文本和其对应的向量存入向量数据库。这相当于预先为图书馆里所有的书都标好了“意义坐标”。
  2. 查询检索阶段(在线):当用户提出一个问题时,我们使用同一个 Embedding Model 将用户的问题也转换成一个向量。这相当于确定了用户想找的书的“意义坐标”。
  3. 相似度搜索:我们拿着这个“问题向量”,去向量数据库中寻找与之“坐标”最接近的那些“文本块向量”。这个寻找过程就是向量相似度计算(通常是余弦相似度)。

在 RAG 中,你知道有哪些 Embedding Model 嵌入模型?

阵营模型名称提供商/来源关键特点与区别
商业闭源 APItext-embedding-3-large text-embedding-3-smallOpenAI行业标杆。性能强大,支持通过参数缩短向量维度以平衡成本和性能。small版本性价比极高。
text-embedding-ada-002OpenAI上一代的王者,曾是事实标准,现在已被text-embedding-3系列超越,但仍被广泛使用。
embed-english-v3.0 embed-multilingual-v3.0Cohere性能非常出色,特别是在多语言支持和企业级应用上与 OpenAI 激烈竞争。
text-embedding-geckoGoogle (Vertex AI)Google Cloud 生态的一部分,性能稳健,适合深度集成 GCP 服务的项目。
社区开源模型bge-large-zh-v1.5BAAI (北京智源)中文领域目前的 SOTA (State-of-the-art) 模型。在 Hugging Face 的 MTEB(大规模文本嵌入基准)榜单上长期霸榜,是中文 RAG 项目的首选。bge= BAAI General Embedding。
m3e-baseMokaAI (墨卡科技)另一款非常优秀的中文 Embedding 模型,轻量且高效,在中等规模项目中表现优异。
all-mpnet-base-v2Sentence-Transformers英文领域经典的开源模型,虽然已被更新的模型超越,但因其均衡的性能和广泛的教程,仍是许多开源项目的基线模型。
Jina Embeddings V2Jina AI专为 RAG 设计,支持高达 8K 的长上下文输入,在处理长文档分块时有独特优势。

在 RAG 中,你如何选择 Embedding Model 嵌入模型?

  • 明确需求:首先明确业务场景、数据语言、预算、隐私和性能要求。
  • 初步筛选:基于语言和性能榜单,选出 2-3 个候选模型(通常会包含一个商业 API 模型和一个顶尖的开源模型)。
  • 离线评测:在我的自有数据集上对候选模型进行小规模的量化评估,用数据说话。
  • 成本分析:对通过评测的模型进行详细的成本效益分析(TCO - 总拥有成本)。
  • 最终决策:结合评测结果和成本分析,做出最符合当前项目阶段和长远规划的选择。对于初创项目,我通常建议从高性价比的商业 API 开始,快速验证业务,待规模化后再考虑自建开源模型的可能性
考量因素关键问题与权衡
1. 性能与准确度 (Performance)这是最重要的前提。模型能否准确捕捉我的业务领域文本的语义?-评估方法:我会参考 MTEB 等公开权威榜单的排名,但更重要的是,我会在我自己的真实业务数据集上,建立一个小的评测集,对候选模型进行离线评估(计算 Hit Rate, MRR 等指标)。-领域适配性:一个在通用语料上表现好的模型,不一定在我的专业领域(如法律、医疗)上表现最佳。可能需要考虑在特定领域数据上微调(Fine-tuning)过的模型。
2. 语言支持 (Language Support)我的知识库是中文、英文,还是多语言混合的?-中文场景:我会优先考虑像bge-large-zh-v1.5这样在中文上表现顶尖的开源模型,或者 OpenAI 的新模型(它们的多语言能力很强)。-多语言场景:需要选择明确支持多语言的模型,如 Cohere 的embed-multilingual或 OpenAI 的模型。
3. 成本 (Cost)这是决定项目能否大规模落地的商业生命线。-API 模型:按 Token 数量计费,简单直接。需要估算索引和查询的总 Token 消耗,评估长期运营成本。例如,OpenAI 的text-embedding-3-small就是一个高性价比的选择。-开源模型“免费”但不是“零成本”。需要考虑私有化部署的成本,包括: -硬件成本:需要购买或租赁带高性能 GPU 的服务器。 -运维成本:需要 MLOps 工程师来部署、扩缩容、监控和维护模型服务。
4. 部署与运维复杂度 (Deployment & MLOps)团队是否有能力和资源来维护一个自托管的模型服务?-API 模型近乎零运维。对于开发速度要求高、AI/ML 基础设施薄弱的团队来说是最佳选择。只需要处理好 API key 管理和网络请求即可。-开源模型:需要较高的技术门槛。适合对数据隐私有严格要求(数据不能离开私有环境)、追求极致性能和低延迟、且具备相应技术实力的团队。
5. 延迟与吞吐量 (Latency & Throughput)模型的推理速度是否满足我的应用场景?-索引阶段:影响批量处理知识库的速度。-查询阶段:直接影响用户的实时体验。通常,轻量级的开源模型(如m3e-base)或性能优化的商业模型(如text-embedding-3-small)在延迟上表现更好。
6. 向量维度 (Vector Dimension)生成的向量维度大小会影响存储成本和检索速度。- 传统的ada-002是 1536 维,bge-large是 1024 维。维度越高,通常包含的信息越多,但占用的存储空间越大,向量检索时的计算量也越大。- OpenAI 的新模型支持可变维度,可以在不显著牺牲性能的情况下,将维度缩短到 512 甚至 256,这是一个巨大的工程优势。

11.文档解析是怎么做的

背景:

我们处理的知识库来源非常多样,可能是 PDF 格式的技术白皮书、HTML 格式的在线文档、Word 格式的会议纪要,甚至是数据库中的记录。因此,我们的解析流程必须具备强大的格式适配能力,并始终遵循内容保真的原则,即最大限度地保留原文的语义和结构信息。

流程:

阶段 1:文档加载 (Document Loading)

这是解析的入口。我们首先需要根据不同的数据源,将原始文档加载到内存中。我们会实现一个统一的 Loader 接口,并为不同的数据源提供具体的实现。

  • 文件系统: 读取本地或网络共享(NFS)上的文件。
  • 网页: 从给定的 URL 列表爬取 HTML 内容。
  • 数据库: 连接数据库,执行 SQL 查询获取特定字段的文本内容。
  • API: 调用企业内部的知识管理系统(如 Confluence, SharePoint)的 API 来获取文档。

阶段 2:内容提取与转换 (Content Extraction & Transformation)

这是解析流程的核心,技术挑战也最大。我们采用**“通用工具为主,特定场景定制为辅”**的策略。

1. 主力工具:Apache Tika

  • 为什么用它?: 在 Java 技术栈中,Apache Tika 是处理文档解析当之无愧的“瑞士军刀”。它能自动检测上千种文件类型(PDF, Word, Excel, PPT, HTML, ...),并从中抽取出纯文本内容和元数据。这使得我们无需为每种格式都编写一套解析代码,极大地提高了开发效率和系统的兼容性。
  • 我们怎么做?:
    • 我们会封装一个 Tika 服务,输入是文件流,输出是一个包含 contentmetadata 的标准对象。
    • content: 提取出的纯文本。
    • metadata: Tika 自动解析出的元数据,如 Author, Creation-Date, Title 等。

2. 针对特定格式的精细化处理

虽然 Tika 很强大,但它的默认配置是为了通用性,有时会丢失一些关键的结构信息。因此,我们会针对一些重要格式进行优化:

  • HTML 文档:
    • 问题: Tika 提取 HTML 时可能会带入大量噪音,如导航栏、广告、页脚、脚本等。
    • 我们的解决方案: 使用 Jsoup 库。Jsoup 提供了类似 jQuery 的选择器语法,让我们可以非常精准地定位到包含正文的核心 DOM 元素(例如 main, article, .post-body),然后只提取这部分的内容。同时,可以轻松地移除不需要的标签(如 script, style)。
  • PDF 文档 (最复杂的场景):
    • 区分类型: 我们首先会判断 PDF 是原生 PDF 还是扫描件 PDF
      • 原生 PDF: 文本信息是直接嵌入的。我们会使用 PDFBox 库(Tika 底层也用它)进行更细粒度的控制,比如可以按段落或表格来提取,而不仅仅是获取混乱的文本流。
      • 扫描件 PDF: 本质是图片,必须通过 OCR (光学字符识别) 来提取文字。我们会集成 OCR 引擎,如 Tesseract(可以通过 Tess4J 在 Java 中调用),将图片转换为文本。这一步的识别准确率至关重要。
    • 处理表格: PDF 中的表格直接提取出来会变成没有格式的文字,完全丢失结构。我们会尝试将表格内容转换为 Markdown 格式,或者直接将其内容描述成一句话(例如:“表格展示了...内容为...”),以保留其结构化信息。
  • Markdown 文档:
    • 这是最友好的格式。我们会直接读取其内容,并利用其标题结构(#, ##)在后续的分块步骤中进行高质量的结构化分割。

阶段 3:内容清洗与规范化 (Cleaning & Normalization)

从各种来源提取的原始文本往往很“脏”,需要进行标准化清洗:

  • 修复编码问题,统一转换为 UTF-8。
  • 去除不可见字符、多余的空格、换行符、制表符。
  • 处理 OCR 错误(如果适用),比如通过字典或规则替换常见的识别错误(如 1 -> l)。
  • 规范化专有名词,例如将 “java”、“JAVA” 统一转换为 “Java”。

12.跟PE的联动

要求:

  • 信任上下文,而非模型记忆:Prompt 的首要任务是强制 LLM 将我们提供的上下文(Context)作为其回答的唯一信息来源。我们不是在考验模型的知识储备,而是在利用它的阅读理解和归纳总结能力
  • 明确角色与任务:必须为 LLM 设定一个清晰的角色(Role)和具体的任务(Task)。它不是一个开放式的聊天伙伴,而是一个有明确工作职责的“信息处理器”。
  • 结构化优于非结构化:给 LLM 的输入应该是清晰、结构化的,而不是一团模糊的文本。使用分隔符、标签、甚至是 XML/JSON 格式,能极大地帮助模型理解不同部分的职责。