解锁 RAG 技术:企业数据与大模型的完美融合之道

为什么需要 RAG?

我们可以使用像 ChatGPT 这样的大语言模型(LLM)来创建星座运势等内容,或者应用于工作等更实际的场景。然而,问题在于企业通常拥有大量的文档、规则、条例等信息,而 ChatGPT 对此一无所知。

此时有两种选择:一是用企业数据重新训练模型,但这过程漫长、昂贵,且成功的可能性较低;二是采用 RAG 技术。RAG 的理念很简单,就是选取一个现有的优秀模型(如 OpenAI 的模型),并为其附加一个公司信息搜索功能。虽然模型本身对公司了解有限,但它有了查找信息的途径,这对于大多数任务来说已经足够。

RAG 结构解析

RAG 主要由两部分组成:

  • 检索器(Retriever):它类似于在公司维基、文档或谷歌上进行搜索,负责查找与用户查询相关的信息。通常会使用向量数据库(如 Qdrant)来存储公司的索引文档,但实际上也可以使用其他方式。在企业复杂的文档环境中,信息可能存储在不同地方,格式也不统一,检索器的作用就显得尤为关键。
  • 生成器(Generator):接收检索器找到的数据,并对其进行组合、浓缩和提取重要信息,从而为用户提供答案。一般会使用像 OpenAI 这样的 LLM 来完成这一过程,它会理解找到的信息并生成合适的回答。

简单示例:Python 和 LangChain 中的 RAG 实现

以下是一个在 Python 和 LangChain 中实现 RAG 的简单示例代码:

import os
import wget
from langchain.vectorstores import Qdrant
from langchain.embeddings import OpenAIEmbeddings
from langchain import OpenAI
from langchain_community.document_loaders import BSHTMLLoader
from langchain.chains import RetrievalQA

# 下载示例文档
wget.download("http://az.lib.ru/t/tolstoj_lew_nikolaewich/text_0073.shtml")
loader = BSHTMLLoader("text_0073.shtml", open_encoding='ISO-8859-1')
war_and_peace = loader.load()

embeddings = OpenAIEmbeddings()
doc_store = Qdrant.from_documents(
    war_and_peace,
    embeddings,
    location=":memory:",
    collection_name="docs",
    llm = OpenAI()
)

while True:
    question = input('Your question: ')
    qa = RetrievalQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        retriever=doc_store.as_retriever(),
        return_source_documents=False
    )
    result = qa(question)
    print(f"Answer: {result}")

RAG 技术的关键细节与优化

虽然 RAG 听起来简单,但实际应用中有很多细节需要注意。

  • 用户问题的初始处理:用户输入的问题可能形式多样,甚至非常不合理。为了将其转化为可用于搜索信息的查询,我们需要借助 LLM 来重新表述用户请求。例如,可以直接让 LLM 改写用户的问题。还有一种更复杂的技术——RAG Fusion,它会让 LLM 提供用户问题的多个版本,基于这些版本进行搜索,然后使用如 Cross-Encoder 等算法对结果进行排名和合并。Cross-Encoder 会比较两个对象(文本、图像等)的相关性,虽然它工作速度较慢,但能提供更相关的结果,适合用于对搜索结果进行排名。用户请求预处理还包括分类,例如将请求分为问题、投诉、请求等类型,还可以按紧急程度、部门等进行分类,这有助于缩小搜索范围,提高响应速度和质量。
  • 数据搜索:检索器负责在存储库中搜索数据,通常使用向量数据库,但也可以使用其他方式,如 Elasticsearch 或谷歌搜索。为了提高搜索结果的质量,有几种主要技术:
    • 检索器和/或数据源的集成(Ensemble):就像请教多位专家一样,对同一问题向多个检索器提问,然后汇总答案(如求平均值),这样通常能得到更好的结果。例如,结合稀疏检索器(如 BM25)和密集检索器(基于嵌入相似性,如向量数据库)能起到很好的互补作用。密集检索器通常使用 BERT 等 transformers 将查询和文档编码为多维空间中的向量,通过向量的接近程度(如余弦相似性)来衡量相关性,能更好地理解语义;稀疏检索器则使用传统的信息检索方法,如 TF-IDF 或 BM25,对于基于关键词的查询和文档中直接包含查询词的情况比较有效,虽然准确性可能不如密集检索器,但搜索和训练速度更快,资源消耗更少。
    • RELP(Retrieval Augmented Language Model based Prediction):这是另一种数据检索方法。在向量存储中找到信息后,不是直接用 LLM 生成答案,而是用它生成示例答案(通过 few-shot prompting),让 LLM 基于这些示例进行学习和回答,这是一种动态学习方式,成本比标准的模型重新训练低得多。few-shot prompting 是先给 LLM 几个示例进行训练,相比 zero-shot(直接提问不提供示例)能显著提高获得相关答案的可能性。
  • 结果的排名、合并和评估:从存储中提取结果后,在将数据发送给 LLM 生成答案之前,需要对结果进行排名,甚至丢弃不相关的结果。常见的排名方法包括:
    • 使用 Cross-Encoder 对获得的结果重新排名并丢弃最不相关的,例如从向量数据库中提取前 30 个结果(top k),用 Cross-Encoder 排名后取前 10 个。
    • 互惠排名融合(Reciprocal Rank Fusion,RRF):其主要思想是给在每组搜索结果中排名较高的元素赋予更大的权重。每个元素的分数通过公式 1/(k + rank) 计算,其中“rank”是元素在特定搜索结果集中的位置,“k”是一个常数(通常设置在 60 左右),然后将不同结果集中元素的分数相加得到最终分数,再根据最终分数对元素进行排序形成合并后的结果列表。这种方法不依赖于单个搜索系统分配的绝对分数,能有效组合不同系统的结果,突出排名始终较高的元素。
    • 基于 LLM 的排名和评估:直接让 LLM 对结果进行排名和评估,但使用这种方法成本较高。

对于搜索结果的评估,我们可以使用 P@K、MAP@K、NDCG@K 等指标来衡量结果与查询的相关性。这些指标通常返回 0 到 1 之间的数值,1 表示最高准确性。例如,P@K 表示前 K 个元素的准确率,计算方式为相关元素数量除以(相关元素数量 + 不相关元素数量)。但它不考虑结果的顺序,所以引入了 AP@K(平均准确率)来改进,AP@K 会考虑顺序因素。而 MAP@K 则是所有问题的 AP@K 总和的平均值。在 RAG 中,我们通常会让 LLM 或其他模型来评估相关性,并且需要根据具体情况向 LLM 提出更具体的问题,然后进行汇总评估。

此外,还可以通过让 LLM 返回 logits(即 token 的概率分布)来评估其回答的可信度。如果分布中的概率较低,说明模型可能在编造(产生幻觉),此时可以向用户返回“我不知道”。

  • 格式、风格和语气的设置:这一步相对简单,只需让 LLM 按照特定方式格式化答案并使用特定语气即可。最好给模型提供示例,以便它更好地遵循指令。

模型微调与基于 RAG 的系统

在某些情况下,可能需要对模型进行进一步训练。例如,如果企业使用了模型不了解的缩写、人名/姓氏或术语,RAG 可能表现不佳,此时可以使用 LORA 等方法对模型进行微调,使其能够理解这些特定情况。

除了基本的 RAG 技术,还有一些更高级的变体,如 FLARE(Forward Looking Active REtrieval Augmented Generation)。它的独特之处在于只有当 LLM 自己需要时才使用 RAG,如果 LLM 能够自信地回答问题,则无需进行检索。在回答过程中,如果 LLM 感觉需要更多数据,它会执行 RAG 搜索,这类似于人类在遇到问题时的思考过程。

以上就是今天关于 RAG 技术的全部内容,如果你对人工智能技术感兴趣,欢迎持续关注我们的公众号**【柏企科技圈】**,获取更多前沿技术资讯。

推荐阅读

1. 专家混合(MoE)大语言模型:免费的嵌入模型新宠

2. LLM大模型架构专栏|| 从NLP基础谈起

3. AI Agent 架构新变革:构建自己的 Plan-and-Execute Agent

4. 探索 AI 智能体工作流设计模式