深度解析 RAG:核心优化方法与实施策略
RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合检索和生成能力的技术框架,旨在通过从外部知识库中检索相关信息来增强生成模型的输出。其基本思想是利用大型语言模型(LLM)的生成能力,同时通过检索机制获取更准确和相关的信息,从而提高生成内容的质量和准确性。RAG 的应用场景广泛,尤其适用于需要结合外部知识或实时信息的任务,如问答系统、信息摘要和聊天机器人等。
传统模型通常被视为黑盒,因为它们的内部机制和决策过程对用户而言是不透明的。这种不透明性使得用户难以理解和解释模型的输出,尤其是在复杂任务或大量数据处理的情况下。正是在这样的背景下,检索增强生成技术应时而生,成为 LLM 时代的一大趋势。它有效缓解了大模型的知识幻觉问题,并允许在不重新训练模型的情况下更新知识库。
下文将从 RAG 的每个环节深入探讨如何优化 RAG 的效果。
文本预处理
高质量的输入数据是 RAG 效果的基础。预处理阶段主要关注数据的清洗、标准化和结构化。
- 实体解析:消除实体术语的歧义,实现实体和术语的一致性。例如,统一"RAG"与'检索增强生成'的指代,避免检索时的匹配偏差。
- 文档划分:合理的区分不同主题文档。如果人类无法区分,那么检索系统也不行。例如:将上课安排相关、售卖相关等不同主题的文档物理隔离或打上明确标签。
- 数据增强:简单的理解就是扩充数据维度。扩充检索系统使其可以理解同义词、词汇意思的解释等;增加元数据描述,帮助模型理解上下文。
- 数据过期机制:多变的数据要能过期或者更新。建立版本控制,确保检索到的信息是当前有效的,避免过时信息误导生成结果。
- 增加周边数据:例如摘要、时间戳、问题的附加信息等。这些元数据可以作为过滤条件或重排序的依据。
文本分割
因为文本长度通常非常长,可能超过 LLM 所能承受的上限,所以要对文本进行分割。理想的情况是在不超过 LLM 输入长度上限的基础上,每个分割的块(chunk)内部是一致的,块之间是有差异的。这样的好处是可以尽量提供给 LLM 有效信息,而不会分散其注意力。
常用的分割方法有以下几种:
- 根据长度分割:例如设定每个块 512 个 token,然后分割的每个块保证不超过 512 个 token。可以通过 OpenAI 的相关库来计算 token。还有一种方法也是比较常用的,就是后一个块包含前一个块的部分内容(overlap),以保持上下文的连贯性。
- 按照句子进行分割:这部分可以通过 NLTK 等库来做。适合结构清晰的文本,但可能会切断长句的逻辑。
- 基于段落分割:然后在基于行分割。在 Dify 等工具中就有类似的分割方式实现。例如先根据
\n\n进行按段分割。如果超长度,再根据\n分割。这保留了文档的自然结构。 - 自定义分割:自己可以根据数据类型进行分割。例如 Word、Excel 或者 JSON 这样的数据可能就会根据其自身需要进行分割,保持字段完整性。
- 基于语义分割:这种方法的目的还是要保证块内部信息的一致性。我们可以简单的理解就是先对文本分成句子,然后根据前后句子的相关度来进行合并。具体方法有可以依据嵌入的方法(在 LangChain 中有实现)、基于模型的方法以及基于 LLM 的方法(实际就是让模型帮我们分段)。语义分割能更好地保留逻辑单元。
Embedding(嵌入)
Embedding 是将文本转换为向量表示的过程,直接影响检索的准确度。
- 尽可能使用动态嵌入:一开始看到这个词可能会比较蒙。实际非常好理解,他和静态嵌入的区别就在于是否可以捕获上下文信息,然后根据上下文信息使得每个词有不同的含义。例如:'打飞机'可能在不同的语境中含义是不一样的。BERT 就是动态嵌入,因为它引入了多头自注意力机制(self-attention)。Word2Vec 就是静态嵌入,同一个词在不同语境下向量相同。
- 微调嵌入:这个上手较高,主要是对垂类数据来说的。大多数模型都是基于通用语料库进行训练,为了让嵌入有更好的效果可以对垂类数据的训练。增加模型对垂类领域数据的理解,提升特定领域的相似度计算精度。
- 混合嵌入:对不同问题或者不同的知识库使用不同的嵌入模型。例如,对于技术文档使用代码优化的模型,对于自然语言问答使用通用模型。
查询优化
利用 LLM 从不同的视角根据用户提出的问题生成多个问题。然后根据生成的问题进行查询。最后把所有的问题并集。理论上这对于解决复杂问题非常有用。


