news 2026/8/14 2:43:53

RAG系统核心原理:从文本切分到向量检索的完整技术栈解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RAG系统核心原理:从文本切分到向量检索的完整技术栈解析

1. 项目概述:从信息检索到智能问答的范式跃迁

如果你最近在关注大模型应用,尤其是如何让大模型“读懂”并回答你公司内部文档、知识库里的问题,那么“RAG”这个词你一定不陌生。RAG,全称检索增强生成,它解决的核心痛点非常直接:大模型虽然知识渊博,但它不知道你私有的、非公开的、实时更新的数据。直接问它,它要么胡说八道,要么告诉你“我的知识截止到某年某月”。RAG的思路很巧妙,它不试图把海量数据全部塞进模型里重新训练(那成本太高了),而是像给模型配了一个超级智能的“外接硬盘”和“搜索引擎”。当用户提问时,系统先从这个“外接硬盘”(你的知识库)里快速找到最相关的几段信息,然后把问题和这些信息一起“喂”给大模型,让它基于这些“参考资料”来组织答案。这样一来,答案的准确性、时效性和专业性都得到了质的提升。

今天,我们就来深入拆解这个“外接硬盘”和“搜索引擎”的核心工作原理。这不仅仅是调用几个API那么简单,其背后是一套环环相扣的技术栈,任何一个环节的疏漏都可能导致最终效果大打折扣。我们将聚焦五个最核心的概念:Chunking(文本切分)、Embedding(向量化)、相似度计算、HNSW(近似最近邻搜索算法)以及多路召回策略。理解它们,你就能真正看懂一个RAG系统是如何工作的,也能在构建自己的系统时,知道问题出在哪里,以及如何优化。无论你是算法工程师、后端开发,还是对AI应用感兴趣的产品经理,这些概念都是绕不开的基石。

2. 核心流程拆解:RAG系统的“五脏六腑”

一个典型的RAG系统工作流程可以清晰地分为两个阶段:索引构建(Indexing)查询与生成(Query & Generation)。我们可以把它想象成图书馆的管理与借阅。

索引构建阶段,就是图书馆管理员(系统)对新到书籍(你的文档)进行加工入库的过程:

  1. 文本加载与清洗:获取原始文档(PDF、Word、网页等),去除无关的格式、广告、页眉页脚。
  2. 文本切分(Chunking):把整本书拆分成一个个有意义的“章节”或“段落”。这一步至关重要,拆得太碎,上下文丢失;拆得太大,检索精度下降。
  3. 向量化(Embedding):为每一个“段落”计算一个高维向量(一组数字),这个向量就像是该段落内容的“数学指纹”,语义相近的段落,其向量在空间中的距离也相近。
  4. 向量存储:将所有“段落”的向量“指纹”及其对应的原始文本,以一种支持快速查找的结构,存入专门的数据库(向量数据库)。

查询与生成阶段,就是读者(用户)来图书馆查资料的过程:

  1. 问题向量化:用户提出问题,系统同样将问题转化为一个向量“指纹”。
  2. 向量检索(相似度计算 + HNSW):系统在向量数据库中,快速找到与问题向量最相似的几个“段落”向量。这个过程依赖相似度度量(如何定义“相似”)和高效的搜索算法(如HNSW)。
  3. 上下文组装:将检索到的Top K个“段落”的原始文本拼接起来,作为给大模型的“参考资料”或“上下文”。
  4. 提示工程与生成:将用户问题和组装好的上下文,按照一定的模板(Prompt)组织成一段完整的指令,发送给大模型(如GPT、Claude等)。
  5. 答案返回:大模型基于提供的上下文,生成最终答案并返回给用户。

可以看到,Chunking、Embedding、相似度、HNSW是索引和检索阶段的核心技术,而多路召回则是在检索环节提升效果的高级策略。下面,我们就逐一深入。

3. 基石一:文本切分(Chunking)的艺术与科学

Chunking是RAG流水线的第一步,也是决定系统上限的基础。它的目标是将长文档分解为语义上相对完整、独立的小块,以便后续嵌入和检索。如果块切得不好,后续步骤再优秀也无济于事。

3.1 常见切分策略及其适用场景

没有一种切分策略是放之四海而皆准的,需要根据文档类型和查询特点来选择。

1. 固定长度重叠切分这是最简单、最常用的方法。设定一个固定的块大小(如500个字符或token)和一个重叠步长(如100个字符)。

  • 优点:实现简单,速度快,能保证相对均匀的块大小。
  • 缺点:可能粗暴地切断句子或段落,破坏语义完整性。例如,一个句子可能被拦腰截断,前半句在一个块尾,后半句在下一个块头。
  • 适用场景:格式相对规整、语义单元长度波动不大的文档,如技术手册、新闻稿。
  • 实操参数:块大小通常选择256、512、1024等(与Embedding模型的最大长度对齐)。重叠长度一般为块大小的10%-20%,用于缓解边界切断问题。

2. 基于分隔符的切分利用文档中天然的分隔符进行切分,如段落(\n\n)、标题(#)、句子(.!?)、Markdown结构(##,-)等。

  • 优点:能更好地保持语义和格式上的完整性,切分出的块更“自然”。
  • 缺点:可能导致块大小差异极大,一个标题可能只有几个词,而一个长段落可能有上千字。
  • 适用场景:结构清晰的文档,如论文、带标题的Wiki页面、Markdown文档。
  • 实操技巧:可以采用递归切分,先用大分隔符(如\n\n)切,如果块还是太大,再用小分隔符(如句子)进行二次切分,直到满足大小限制。

3. 语义切分利用NLP技术,如句子边界检测、文本分割模型,识别文档中语义发生转换的边界。

  • 优点:理论上能产生语义最完整的块,质量最高。
  • 缺点:计算成本高,依赖额外的模型,实现复杂。
  • 适用场景:对检索质量要求极高,且文档结构复杂、语义转换频繁的场景,如小说、访谈记录、自由格式的长篇报告。

4. 混合策略与智能切分在实际生产中,单一策略往往不够。更常见的做法是分层切分策略组合。例如,先按章节/标题进行大块划分,再在每个大块内根据内容类型(是描述、列表还是代码)选择不同的细粒度切分策略。

注意:Chunking的“黄金法则”切分的核心原则是:让检索回来的“块”,恰好包含回答用户问题所需的所有信息,且尽可能少地包含无关信息。这要求我们根据预期的用户问题类型来设计切分策略。如果用户常问细节事实(如“某产品的规格参数”),块可以小一些、精确一些;如果用户常问需要推理总结的问题(如“对比A方案和B方案的优劣”),块就需要大一些,以保留足够的上下文。

3.2 实操心得与避坑指南

  • 不要忽视元数据:在切分时,一定要保留块的来源信息(如文件名、章节标题、页码等)。当多个块被召回时,这些元数据能帮助你理解块之间的关系,甚至可以在组装Prompt时告诉模型“以下是来自《用户手册》第三章的内容”,提升模型对上下文的理解。
  • 重叠不是万能的:设置重叠可以缓解切断问题,但也会引入冗余。如果重叠部分恰好包含关键信息,它会在多个块中重复出现,可能影响检索排名和模型判断。需要权衡重叠大小。
  • 动态块大小尝试:对于质量要求高的项目,可以进行A/B测试。准备几套不同策略(如固定512字符、按段落切分、语义切分)生成的索引,用一批标准问题查询,对比检索结果的相关性。这是找到最优策略的最可靠方法。
  • 处理特殊内容:对于表格、代码块、数学公式,要特别小心。尽量将它们保持在一个完整的块内,避免切分。可以考虑用特殊的标记或格式来标识它们,以便后续处理。

4. 基石二:嵌入(Embedding)—— 将文本映射为空间点

如果说Chunking是把书拆成了段落,那么Embedding就是给每个段落拍了一张“高维照片”。这张“照片”(即向量)不再是由文字组成,而是由几百甚至上千个数字构成的坐标点。语义相似的段落,它们的向量点在空间中的位置也彼此靠近。

4.1 Embedding模型的选择与考量

市面上有众多开源的、商用的Embedding模型,如OpenAI的text-embedding-ada-002,Cohere的Embed模型,以及开源的BGEE5Sentence-Transformers系列等。选择时需权衡以下几点:

  1. 维度:向量维数,常见的有384、768、1024、1536等。更高的维度通常能承载更丰富的语义信息,但也会增加存储和计算成本。不是维度越高越好,要与模型能力匹配。
  2. 上下文长度:模型单次能处理的最大文本长度。如ada-002是8191个token。如果你的块超过这个长度,需要截断,可能损失信息。
  3. 语义表示能力:这是核心。好的Embedding模型应该在语义相似性任务上表现优异,能将“狗”和“宠物”的向量拉近,而将“狗”和“汽车”的向量推远。需要关注其在MTEB等权威榜单上的排名。
  4. 语言与领域:是否有针对特定语言(如中文)或特定领域(如法律、医疗)优化的模型?通用模型在专业领域可能表现不佳。
  5. 速度与成本:本地部署的模型需要考虑推理速度;调用API则需考虑费用和延迟。

当前(2024年)的一个实用建议是:对于中文场景,可以优先考虑BGE(BAAI General Embedding)系列模型,如BGE-large-zh。它在中文语义相似度任务上表现突出,且完全开源可本地部署。对于多语言或中英混合场景,text-embedding-ada-002或Cohere的模型仍然是稳定可靠的选择,尤其是当你希望省去模型维护的麻烦时。

4.2 Embedding的实践细节与调优

  • 输入规范化:在将文本送入Embedding模型前,进行适当的清洗和规范化非常重要。包括:统一转换为Unicode,去除多余空白符,处理特殊字符等。对于某些模型,在输入前添加指令前缀(如BGE模型建议对于查询文本添加“为这个句子生成表示以用于检索相关文章:”)可以显著提升检索效果。
  • 批量处理:当需要处理大量文本时,务必使用模型的批量推理接口,这比循环单条处理效率高出几个数量级。
  • 维度归一化:许多相似度计算(如余弦相似度)在向量被归一化(即转换为单位向量,模长为1)后更为高效和稳定。大部分向量数据库在存入时会自动做归一化,但如果你自己计算相似度,需要注意这一点。
  • 监控Embedding质量:Embedding不是一劳永逸的。建议定期用一批标准查询语句,检查其检索出的Top结果是否相关。如果发现效果下降,可能是数据分布发生了变化,需要考虑更新或重新训练Embedding模型。

5. 核心引擎:相似度计算与HNSW索引

当我们有了海量的向量“指纹”后,如何快速找到与问题向量最相似的那几个?这需要解决两个问题:如何定义“相似”(相似度计算),以及如何快速找到(近似最近邻搜索)。

5.1 相似度度量:如何定义“像”

在向量空间中,我们通过计算两个向量之间的距离或角度来衡量它们的相似度。常用的方法有:

  1. 余弦相似度(Cosine Similarity):计算两个向量夹角的余弦值。范围在[-1, 1]之间,值越大越相似。这是文本Embedding最常用、效果通常最好的度量方式,因为它只关注向量的方向而非长度,对文本的“表达强度”不敏感。
    • 计算公式:cos(θ) = (A·B) / (||A|| * ||B||)
  2. 点积(Dot Product):两个向量对应维度相乘后求和。当向量经过归一化后,点积等价于余弦相似度。未归一化时,向量的模长也会影响结果。
  3. 欧氏距离(Euclidean Distance):计算两点间的直线距离。距离越小越相似。在某些特定的Embedding空间或模型中可能被使用。

注意:度量的选择与数据预处理强相关。如果你使用的向量数据库(如Milvus, Pinecone, Weaviate)默认使用余弦相似度,那么你在生成Embedding时,最好确保向量是归一化的,或者数据库支持存入时自动归一化。混合使用可能导致不准确的结果。

5.2 HNSW:在十亿级向量中实现毫秒级检索

暴力计算问题向量与库中所有向量的相似度,在向量数量巨大时(百万、千万级)是完全不可行的。这就是近似最近邻搜索(ANN)算法登场的原因。HNSW(Hierarchical Navigable Small World)是当前最流行、综合性能最好的ANN算法之一。

你可以把HNSW想象成建立一个多层次的航空网络:

  • 底层(第0层):包含所有向量点,就像包含所有城市的公路网,连接密集。
  • 高层(第1、2...层):是底层的一个随机子集,层数越高,包含的点越少,连接越稀疏。这就像枢纽机场网络,只有主要城市(枢纽)之间有直飞航班。

检索过程(类比找航班)

  1. 从最高层开始(比如北京到悉尼,先找国际枢纽)。
  2. 在当前层,找到离目标点(问题向量)最近的那个枢纽点。
  3. 跳到下一层,以上一步找到的点为起点,继续寻找更近的点。
  4. 重复步骤2-3,直到最底层。在最底层,在局部区域内进行精细搜索,找到最近的几个点。

HNSW的优势

  • 查询速度快:得益于“跳远”式的分层搜索,它避免了遍历大部分无关节点。
  • 精度高:在相同速度下,其召回精度通常优于其他ANN算法(如IVF)。
  • 支持动态插入:新的向量可以增量添加到索引中,无需重建整个索引。

HNSW的关键参数调优

  • M:每个节点在构造时建立的连接数。M越大,图越稠密,精度越高,但构建和搜索速度越慢,内存占用越大。通常设置在16-64之间。
  • efConstruction:构建索引时,为每个节点寻找邻居的候选集大小。影响索引构建的质量,值越大,构建越慢,但索引质量越高。
  • efSearch:搜索时的候选集大小。这是查询时最重要的参数efSearch越大,搜索越精细,召回率越高,但速度越慢。需要在精度和速度之间做权衡。

实操建议:对于大多数RAG应用,可以从默认参数开始(如M=16,efConstruction=200,efSearch=50)。上线后,通过查询日志分析,如果发现召回结果不相关,可以适当调高efSearch(如100);如果查询延迟过高,则可以适当调低efSearchMefConstruction一般在索引构建后就不再调整。

6. 进阶策略:多路召回与重排序

基础的RAG使用单一的Embedding模型和ANN索引进行检索,这被称为“单路召回”。但在复杂场景下,单路召回可能不够可靠。多路召回策略旨在通过多种不同的方式或角度进行检索,然后合并或筛选结果,以提升召回内容的覆盖率和相关性。

6.1 为什么需要多路召回?

  1. Embedding模型的局限性:没有哪个Embedding模型是完美的。它可能擅长理解语义关联,但对精确的关键词匹配不敏感。
  2. 查询的多样性:用户的问题可能包含精确的实体名(需要关键词匹配),也可能是模糊的描述(需要语义理解)。
  3. 缓解“语义鸿沟”:用户提问用的词和知识库中文档用的词可能不同,但表达同一意思。单一模型可能无法完全桥接。

6.2 常见的多路召回策略

1. 混合检索(Hybrid Search)这是最经典的多路召回,结合了稠密检索稀疏检索

  • 稠密检索:就是我们上面讲的,基于Embedding向量的语义搜索。
  • 稀疏检索:传统的关键词搜索,如BM25算法。它基于词频、逆文档频率等统计信息,擅长精确匹配。
  • 融合方式:分别用两种方法检索出Top K个结果,然后通过分数融合(如加权求和、RRF)得到一个最终排名。

2. 多Embedding模型召回使用多个不同的Embedding模型(如一个通用模型,一个领域专用模型)对同一查询和文档分别进行向量化和检索,然后合并结果。这可以捕捉不同模型视角下的语义信息。

3. 查询改写召回对原始用户查询进行改写或扩展,生成多个相关的查询,分别进行检索后合并结果。

  • 同义词扩展:“苹果” -> “苹果, Apple Inc., 水果”。
  • 问题分解:“如何配置RAG的Chunking和Embedding?” -> 分解为“如何配置Chunking?”和“如何选择Embedding模型?”两个子问题。
  • HyDE(假设性文档嵌入):让大模型根据用户问题,生成一个假设性的理想答案文档,然后用这个生成的文档去检索。这相当于用大模型“想象”了一下答案应该长什么样,再用这个“想象”去搜索,有时能取得奇效。

6.3 重排序:从“召回”到“精排”

多路召回会产生一个更大的候选集(例如,每路召回10个,3路合并后得到30个候选文档)。直接把这30个都扔给大模型,会浪费上下文窗口,也可能引入噪声。因此,需要一个重排序步骤,从这30个中精选出最相关的3-5个。

重排序模型通常是一个比Embedding模型更精细的、专门用于计算“查询-文档”相关性的模型(如BGE-reranker,Cohere rerank)。它会对“查询-文档”对进行深度交互计算,给出一个更准确的相关性分数。虽然计算成本比Embedding高,但因为它只对少量候选(如30个)进行计算,所以总体开销可控,却能显著提升最终上下文的质量。

一个典型的多路召回+重排序流水线

用户查询 -> [查询改写] -> 多个查询变体 -> 稠密检索(主Embedding模型)-> 召回结果A -> 稀疏检索(BM25)-> 召回结果B -> 稠密检索(备用Embedding模型)-> 召回结果C -> 合并去重(A, B, C)-> 得到粗排候选集(如30个) -> 重排序模型对30个候选进行精排 -> 得到Top 5最终上下文 -> 送入大模型生成答案。

7. 实战:构建一个简易RAG检索系统的核心代码逻辑

理解了原理,我们来看一个高度简化的、聚焦于检索环节的Python伪代码示例,它串联了上述几个核心概念。

import numpy as np from sentence_transformers import SentenceTransformer from rank_bm25 import BM25Okapi from typing import List, Dict import jieba # 用于中文分词 class SimpleRAGRetriever: def __init__(self, embedding_model_name: str = 'BAAI/bge-large-zh'): # 1. 初始化Embedding模型 self.embedding_model = SentenceTransformer(embedding_model_name) # 用于稀疏检索的BM25需要分词后的语料 self.tokenized_corpus = [] # 存储原始文本块 self.chunks = [] # 存储向量 self.embeddings = None # BM25对象 self.bm25 = None def build_index(self, documents: List[str]): """构建索引:包括切分、嵌入、构建BM25和ANN(此处简化)""" # 2. 文本切分 (这里使用简单的按句号切分,实际项目需更复杂) self.chunks = [] for doc in documents: # 简单按句号、问号、感叹号切分,并过滤空字符串 sentences = [s.strip() for s in doc.replace('。', '.').replace('?', '?').replace('!', '!').split('.') if s.strip()] self.chunks.extend(sentences) # 3. 为稠密检索准备:生成嵌入向量 print(f"正在为 {len(self.chunks)} 个文本块生成嵌入向量...") self.embeddings = self.embedding_model.encode(self.chunks, normalize_embeddings=True, # 归一化,用于余弦相似度 show_progress_bar=True) # 4. 为稀疏检索准备:构建BM25索引 print("正在构建BM25索引...") # 中文分词 self.tokenized_corpus = [list(jieba.cut(chunk)) for chunk in self.chunks] self.bm25 = BM25Okapi(self.tokenized_corpus) # 5. 为稠密检索构建ANN索引(此处简化,实际需用FAISS, Milvus等) # 假设我们将向量存储在内存的numpy数组中,后续用余弦相似度暴力计算TopK # 生产环境务必替换为HNSW索引(如通过FAISS) print("索引构建完成。") def hybrid_retrieve(self, query: str, top_k: int = 5, dense_weight: float = 0.7) -> List[Dict]: """混合检索:结合稠密和稀疏检索结果""" # 6. 查询嵌入 query_embedding = self.embedding_model.encode([query], normalize_embeddings=True)[0] # 7. 稠密检索(简化版:暴力计算余弦相似度) # 计算查询向量与所有块向量的余弦相似度 (因为已归一化,点积即余弦相似度) dense_scores = np.dot(self.embeddings, query_embedding) dense_indices = np.argsort(dense_scores)[-top_k*2:][::-1] # 取2倍top_k用于后续融合 # 8. 稀疏检索(BM25) query_tokens = list(jieba.cut(query)) sparse_scores = self.bm25.get_scores(query_tokens) sparse_indices = np.argsort(sparse_scores)[-top_k*2:][::-1] # 9. 结果融合 - 使用简单的加权分数融合 # 先归一化两种分数到[0,1]区间 if len(dense_scores) > 0: dense_scores_norm = (dense_scores - dense_scores.min()) / (dense_scores.max() - dense_scores.min() + 1e-8) if len(sparse_scores) > 0: sparse_scores_norm = (sparse_scores - sparse_scores.min()) / (sparse_scores.max() - sparse_scores.min() + 1e-8) combined_scores = {} for idx in set(list(dense_indices) + list(sparse_indices)): dense_score = dense_scores_norm[idx] if idx in dense_indices else 0 sparse_score = sparse_scores_norm[idx] if idx in sparse_indices else 0 combined_scores[idx] = dense_weight * dense_score + (1 - dense_weight) * sparse_score # 10. 按融合分数排序,返回Top K sorted_indices = sorted(combined_scores.items(), key=lambda x: x[1], reverse=True)[:top_k] results = [] for idx, score in sorted_indices: results.append({ 'chunk': self.chunks[idx], 'score': score, 'dense_score': dense_scores_norm[idx], 'sparse_score': sparse_scores_norm[idx] }) return results # 使用示例 if __name__ == "__main__": # 模拟文档数据 docs = [ "RAG是一种结合检索和生成的技术。它先检索相关文档,再基于文档生成答案。", "文本切分是RAG的第一步,目的是将长文档切成小块。常见的切分方法有固定长度切分和按分隔符切分。", "嵌入模型将文本转换为向量。语义相似的文本,其向量在空间中的距离也近。", "HNSW是一种高效的近似最近邻搜索算法,用于快速查找相似向量。", "多路召回通过多种方式检索,如混合检索,可以提高召回率。" ] retriever = SimpleRAGRetriever() retriever.build_index(docs) query = "如何对文本进行切分?" results = retriever.hybrid_retrieve(query, top_k=3) print(f"查询: '{query}'") for i, res in enumerate(results): print(f"{i+1}. [分数: {res['score']:.3f}] {res['chunk']}")

这段代码展示了从文档加载到混合检索的核心流程。请注意,这是一个用于教学原型的极度简化版本。生产环境需要考虑:

  • 高效的ANN索引:用FAISS(Facebook AI Similarity Search)或专业向量数据库(Milvus, Weaviate, Qdrant)替代暴力计算,它们内置了HNSW等算法。
  • 更复杂的Chunking:使用LangChainRecursiveCharacterTextSplitter或专门的分割库。
  • 异步处理与批处理:构建索引时处理大量文档。
  • 持久化存储:将索引和向量存入磁盘或数据库。
  • 重排序模块:集成一个重排序模型来精炼最终结果。

8. 常见问题、排查技巧与效果评估

构建RAG系统时,你会遇到各种各样的问题。以下是一些典型问题及其排查思路:

问题1:检索结果完全不相关。

  • 检查Embedding模型:确认使用的模型是否适合你的语言和领域。尝试用几个简单的句子测试模型本身的相似度计算是否合理。
  • 检查Chunking:你的文本块是否大小合适?是否被不恰当地切断?尝试打印出被召回的文本块,看其内容是否完整。
  • 检查相似度计算:确认向量数据库使用的相似度度量(如余弦相似度)与你的Embedding生成方式(是否归一化)匹配。
  • 调整HNSW参数:尝试增大efSearch参数,让搜索更彻底。

问题2:检索结果似乎相关,但大模型给出的答案还是不对。

  • 检查上下文组装:提供给大模型的上下文是否过长或过短?是否包含了足够回答问题的信息?尝试调整top_k参数。
  • 检查Prompt:你的Prompt是否清晰指示了模型基于上下文回答?尝试优化Prompt,例如使用“请严格根据以下上下文回答问题,如果上下文不包含答案,请说不知道。”这样的指令。
  • 启用模型引用功能:如果模型支持(如GPT-4),让其引用上下文中的具体段落,这有助于你判断模型是否真的“看到”了关键信息。

问题3:系统响应速度慢。

  • 定位瓶颈:使用 profiling 工具,确定是Embedding推理慢、向量检索慢,还是大模型生成慢。
  • 优化检索:对于向量检索,可以尝试减小efSearch参数(以精度换速度),或使用更快的ANN算法(如IVF)。
  • 缓存:对常见的查询结果进行缓存。
  • 异步处理:将Embedding计算、检索等步骤设计为异步。

问题4:如何处理新数据?

  • 增量更新:确保你的向量数据库支持增量插入。对于新文档,进行同样的Chunking和Embedding流程后,直接插入索引。注意,HNSW支持增量插入,但频繁插入可能影响索引结构,需要定期优化。
  • 定期重建:对于数据更新非常频繁的场景,可以定期(如每天)全量重建索引,以保证索引质量。

如何评估RAG系统的效果?不能只靠感觉,需要量化评估。可以从两个层面进行:

  1. 检索阶段评估
    • 命中率:对于一组测试问题,检索到的Top K个文档中,至少包含一个正确答案文档的比例。
    • 平均排序倒数:正确答案在检索结果列表中的平均排名的倒数。
  2. 端到端评估
    • 人工评估:设计一批测试问题,让人工评判答案的准确性、相关性和流畅度。
    • 基于LLM的自动评估:使用一个更强的LLM(如GPT-4)作为裁判,根据标准答案或上下文,对生成的答案进行评分。可以评估忠实度(答案是否严格基于上下文)、相关性信息完整性等维度。

构建一个高效的RAG系统是一个迭代过程,需要持续地在Chunking策略、Embedding模型、检索参数和Prompt工程之间进行调试和权衡。每一次调整,都最好能有评估数据作为依据,而不是盲目尝试。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/14 2:41:07

Java final关键字深度解析:从基础语法到并发编程实战

1. 从“final”的面试高频拷问说起如果你正在准备Java面试,或者已经是一个有几年经验的开发者,我敢打赌,你肯定被问过关于final关键字的问题。它太基础了,基础到很多人觉得“不就是个修饰符嘛,有啥好说的”。但恰恰是这…

作者头像 李华
网站建设 2026/8/14 2:38:13

3GPP跨厂商Agent信任管理:构建自动驾驶网络协同框架

1. 先搞清楚“跨厂商Agent工具信任管理”到底要解决什么问题如果你在搞自动驾驶网络,或者负责网络运维自动化,肯定遇到过这种场景:一个网络里用了A厂商的故障诊断Agent、B厂商的性能优化Agent和C厂商的安全策略Agent。这些Agent各自为战&…

作者头像 李华
网站建设 2026/8/14 2:37:46

CSS核心基础与实战:从盒模型到现代布局,一篇掌握网页样式精髓

1. 项目概述:为什么说“一篇就够用”? 在网页开发这个行当里,CSS(层叠样式表)的地位,就像装修房子时的“软装设计图”。HTML搭好了毛坯房的骨架,而CSS决定了这房子最终是北欧极简风、工业复古风…

作者头像 李华