从AI知识库到RAG

在构建AI应用时,会遇到“AI并未见到过任务中数据的问题”。比如对于企业来说,AI无法掌握每个客户的资料;对于个人来说,AI对一些个人信息、隐私信息不甚了解。即使AI能力很强(理想的世界模型也不例外),缺少具体任务的数据后,就失去了”具体问题具体分析“的能力。

什么是RAG

通过检索外部资料来提高生成式AI模型的准确性和可靠性,就是检索增强生成技术(Retrieval-Augmented Generation)。如果把大语言模型(LLM)完成任务的过程比作考试,那么有RAG的大模型就相当于是开卷考试,而没有RAG的加持,仿佛就是闭卷考试。RAG就是通过帮LLM检索资料,以提高生成效果的技术。

RAG最早由Patrick Lewis等人在这篇论文提出,而他们所在的公司就是Cohere,这家公司目前提供包括Embedding和Rerank模型在内的API服务,性能也很不错。

为什么需要RAG

RAG的出现是为了解决大语言模型在应用时的一些问题与不足。最突出的一点是大模型的幻觉问题,也就是大模型的输出会与事实不符,或是编造一些答案。还有就是用于训练LLM的数据可能比较落后,LLM对比较新的资料一无所知。

RAG则让LLM能够访问最新的或者自定义的资料,并且允许用户验证LLM的信息来源,确保其准确性。RAG检索的数据可以是公开的(如搜索引擎),也可以是私有的(如公司资料,个人敏感数据),这一点让RAG有了广阔的应用前景。RAG目前就已经被广泛使用,比如英伟达的NeMo Retriever读取公司内部资料、月之暗面的Kimi Chat利用搜索引擎回答等。

黄仁勋在GTC2024介绍的NeMo Retriever
黄仁勋在GTC2024介绍的NeMo Retriever

围绕RAG构建的知识库

AI知识库就是让AI能够”量体裁衣“的重要工具。通过知识库帮助AI更好地完成任务,目前AI知识库构建可以有以下三种方式:

  • 提示词工程 (Prompt Engineering)
  • 微调 (Fine Tuning)
  • 嵌入 (Embedding)

提示词工程就是直接在提示词中构建知识库,把所有的资料放到提示词中。这种方式适合小规模地使用,但目前的AI模型输入的token数量基本无法满足这种实现方式。实际上即使随着AI发展,到了某一天AI的输入窗口足够大到容纳一般的知识库,构建知识库也仍有其价值。因为输入的内容长度会影响AI的性能(至少目前的模型是这样),具体可查看Needle In A Haystack - Pressure Testing LLMs

微调是学界喜闻乐见的形式了,使用特定的任务数据在预训练模型上进行微调。这种做法其实是适合做一个行业通用的大模型,比如法律行业大模型、医学大模型等。一方面,微调需要的训练数据也不算少,成本也高;另一方面,微调不够灵活,比如根据一两份文档及时调整。微调的过程其实是把训练数据进行学习和泛化,与其说是记忆内容,不如说是增强某个领域的能力。

所以目前最主流的构建知识库的方式,大都采用Embedding的方式。而这种形式的知识库,也需要配合RAG才能发挥作用。

RAG的基本组成

一个经典的、基本的RAG组成如下图所示。

RAG的基本组成
RAG系统主要包含索引、检索、生成等三个阶段。

Embedding 嵌入

在这个流程中,用户需要先上传文档,系统将上传的文档经过Embedding之后,存储到向量数据库中。Embedding就是将语义相似的文本转换为距离相近的向量,因此这个过程俗称向量化。

Retrival 检索

当用户向LLM提问时,提问的内容会经过Embedding之后,在向量数据库中进行匹配,查询到一系列内容。这是第一阶段的检索。

Rerank 重排序

直接在向量数据库中查询到的内容可能并不完美,结果与查询的内容往往匹配不上,因此还需要二阶段检索,也就是Rerank。这一阶段,Rerank模型会将前一阶段查询到的内容进行重排序,按照相关性输出排序结果。Rerank完成后,取Top K就能应用在后面的生成阶段了。

5行代码实现RAG

一个赋值语句才算一行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from transformers import RagTokenizer, RagRetriever, RagTokenForGeneration
from datasets import load_dataset

retriever = RagRetriever.from_pretrained(
    config_name = "facebook/rag-token-nq",
    index_name = "compressed",  # 索引的类型
    use_dummy_dataset = True,  # 使用虚拟数据集来测试
    dataset = "wiki_dpr"  # 用于检索的数据集
)

# 加载预训练的tokenizer和模型
tokenizer = RagTokenizer.from_pretrained("facebook/rag-token-nq")
model = RagTokenForGeneration.from_pretrained("facebook/rag-token-nq", retriever=retriever)

# 输入问题并转换为向量
input_ids = tokenizer(input_text = "What is the capital of France?", 
		return_tensors="pt").input_ids

# 生成回答
outputs = model.generate(input_ids)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

RagTokenizer用于文本的分词,RagTokenForGeneration是RAG模型的生成器部分,而RagRetriever是负责检索的部分。RagTokenizer.from_pretrained("facebook/rag-token-nq")加载了一个预先训练好的分词器,用于将文本转换成模型能理解的格式(即分词)。RagTokenForGeneration.from_pretrained("facebook/rag-token-nq", retriever=retriever)加载了预训练的RAG模型。facebook/rag-token-nq是模型和分词器的名称,它们是在Natural Questions数据集上预训练的。

开源的RAG实现

Dify是一个 LLM 应用开发平台,已经有超过 10 万个应用基于 Dify.AI 构建。它融合了 Backend as Service 和 LLMOps 的理念,涵盖了构建生成式 AI 原生应用所需的核心技术栈,包括一个内置 RAG 引擎。使用Dify,你可以基于任何模型自部署类似 Assistants API 和 GPTs 的能力。这个项目由苏州的一家公司主持,并且提供了SasS服务。

Langchain-Chatchat是基于 ChatGLM 等大语言模型与 Langchain 等应用框架实现,开源、可离线部署的检索增强生成(RAG)大模型知识库项目。最开始只支持ChatGLM模型,后来增加支持了许多开源模型以及在线模型。

两家的功能对比如下表:

Dify-api ChatChat
外围能力 普通文档读取 普通文档
图片OCR
数据源 文档文本内容
向量数据库
搜索引擎
向量数据库
模型支持 在线embedding模型
在线rerank模型
在线LLM
在线embedding模型
离线embedding模型
离线LLM
高级功能 ES混合检索
高级RAG 不支持 不支持

其实还有一些功能,目前的开源项目没有完全覆盖到,比如:

  • 多模态能力
  • 传统关系型数据库支持
  • 多库联合/跨库取资料
  • 引用功能
  • 高级RAG
  • 评估指标

参考资料

  1. gkamradt/LLMTest_NeedleInAHaystack: Doing simple retrieval from LLM models at various context lengths to measure accuracy (github.com)
  2. What is retrieval-augmented generation? | IBM Research Blog
  3. Retrieval (langchain.com)
  4. langgenius/dify (github.com)
  5. Langchain-Chatchat (github.com)
Buy me a coffee~
Tim 支付宝支付宝
Tim 贝宝贝宝
Tim 微信微信
0%