大模型应用架构:从零解读检索增强生成 RAG
RAG(Retrieval-Augmented Generation,检索增强生成)是 2023 年以来最流行的基于大语言模型(LLM)的应用系统架构。许多产品几乎完全建立在 RAG 之上,涵盖了结合网络搜索引擎和 LLM 的问答服务,到成千上万个私有数据聊天的应用程序。很多人将 RAG 和 Agent(智能体)作为大模型应用的两种主流架构,但什么是 RAG?它涉及了哪些具体的技术细节?本文将深入解析。
1. 什么是 RAG
RAG 即检索增强生成,其核心思想是为 LLM 提供从特定数据源检索到的信息,并基于此修正生成的答案。RAG 本质上是 Search + LLM Prompt 的结合体。通过大模型回答查询,并将搜索算法所找到的信息作为大模型的上下文注入。查询语句和检索到的上下文都会被注入到发送给 LLM 的提示语中,从而让模型能够利用外部知识生成更准确、可溯源的回答。
在向量搜索领域,嵌入式搜索引擎可以通过 Faiss 等工具实现,这成为了 RAG 的重要助力。像 Pinecone 这样的服务可以构建开源搜索索引,为输入文本增加了额外的存储空间和管理工具。关于向量数据库和嵌入技术的更多细节,可以参考相关技术文档。
面向 RAG 的开发框架主要有两个最著名的开源工具——LangChain 和 LlamaIndex。它们分别创建于 2022 年 10 月和 11 月,随着 ChatGPT 的爆发,在 2023 年获得了大量采用。这两个项目发展速度极快,提供了丰富的组件来构建基于 LLM 的流水线和应用程序。
2. 基础的 RAG 技术流程
RAG 系统的起点通常是一个文本文档的语料库。基础流程大致如下:
- 文档分块:把长文本分割成较小的块(Chunks)。
- 向量化:把这些分块嵌入到向量与 Transformer 编码器模型中。
- 建立索引:把所有这些向量建立索引。
- 创建提示语:创建一个 LLM 提示语,告诉模型回答用户的查询,并提供在搜索步骤中找到的上下文。
在运行时,我们用相同的编码器模型完成用户查询的向量化,然后执行这个查询向量的索引搜索,找到 Top-K 的结果。从数据库中检索到相应的文本块,并提供给 LLM 提示语(Prompt)作为上下文。
2.1 提示词示例
在 OpenAI 平台上,提示词 Prompt 可以是这样的结构:
def question_answering(context, query):
prompt = f"""
请根据以下上下文回答问题:
上下文:{context}
问题:{query}
如果上下文中没有相关信息,请说明无法回答。
"""
response = get_completion(instruction=prompt, model="gpt-3.5-turbo")
answer = response.choices[0].message["content"]
return answer
关于提示词和提示词工程的更多介绍,可以参考 OpenAI 的官方手册。尽管 OpenAI 在 LLM 市场上处于领先地位,但还有很多替代方案,比如 Anthropic 的 Claude,以及最近流行的更小但功能强大的模型,如 Mistral、微软的 Phi-2 以及许多开源选项,如 Llama2、OpenLLaMA、Falcon 等都可以用来开发面向 RAG 的大模型产品。
3. RAG 中的高级技术
虽然并非所有 RAG 系统中的高级技术都可以轻松地在一张图中可视化,但描述核心步骤和算法的方案对于理解至关重要。
3.1 分块和矢量化
首先,要创建一个向量索引来表示我们的文档内容,然后在运行时搜索所有这些向量和查询向量之间最小距离对应的最接近语义。
由于 Transformer 模型有固定的输入序列长度,即使输入上下文的窗口很大,一个或几个句子的向量也比在一个几页文本上取平均值的向量更能代表它们的语义意义。因此,数据分块是一项有意义的技术。把初始文档分成一定大小的块,同时又不失去它们的意义,也就是把文本分成句子或段落,而不是把一个句子分成两部分。目前已有各种能够执行此任务的文本分割器实现。例如,在 LlamaIndex 中,NodeParser 就提供了一些高级选项,如定义自己的文本分割器、元数据、节点/块关系等。


