支持私有化部署
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


综述:从零构建RAG系统全面指南(含代码)

发布日期:2025-05-15 11:25:04 浏览次数: 1556 作者:大模型之路
推荐语

掌握RAG技术,提升语言模型性能。

核心内容:
1. RAG系统概念与核心原理解析
2. RAG如何解决传统大语言模型的关键问题
3. RAG的发展历程及实际应用案例

杨芳贤
53A创始人/腾讯云(TVP)最具价值专家

点击“蓝字” 关注我们

尽管大语言模型具备出色的推理能力和广泛的通用知识,但它们在检索精确信息、获取最新数据或提供可验证的回答时常常遇到困难。检索增强生成(Retrieval-Augmented Generation,RAG)应运而生,这一创新性方法通过将大语言模型与外部知识源相结合,有效提升了其性能。本文将深入探讨RAG的概念、重要性,并使用Python和流行的开源库从零开始构建一个完整的RAG系统。

一、RAG是什么

RAG是一种将信息检索与文本生成相结合的架构。其核心原理是在生成回答之前,从外部知识库中检索相关信息,以此增强语言模型的能力。这一过程主要包含以下几个关键步骤:

  1. 检索
    当系统接收到一个查询时,检索系统会在知识库中搜索最相关的文档或文本块。例如,当用户询问“苹果公司最新的产品有哪些”,检索系统会在包含苹果公司产品信息的知识库中进行查找。
  2. 增强
    检索到的信息会被注入到发送给语言模型的提示中。这些额外的信息为语言模型提供了更丰富的上下文,帮助它生成更准确的回答。
  3. 生成
    语言模型结合其预训练的知识和检索到的特定信息,生成最终的回答。在上述例子中,语言模型会参考检索到的苹果公司产品信息,给出如“苹果公司最新的产品包括iPhone 15系列手机、Apple Watch Series 9等”这样的回复。

RAG的出现有效解决了传统大语言模型存在的多个关键问题:

  1. 知识局限
    标准的大语言模型知识受限于训练数据,而RAG允许模型访问更新或更专业的信息。以医学领域为例,大语言模型可能在训练时使用的是几年前的医学研究成果,而RAG可以通过连接最新的医学数据库,为用户提供最新的医学研究进展和治疗方案。
  2. 幻觉问题
    大语言模型有时会生成看似合理但实际错误的信息。RAG通过将回答基于可验证的来源,大大减少了这种“幻觉”情况的发生。例如,在回答历史事件相关问题时,RAG会依据历史文献等可靠来源,避免编造不存在的事件细节。
  3. 透明度
    RAG系统中的模型能够引用其信息来源,这使得验证回答变得更加容易。在学术研究场景中,这一特性尤为重要,研究人员可以根据模型提供的来源进一步查阅资料,确保信息的准确性。
  4. 适应性
    RAG系统可以通过更新知识库来适应新信息,而无需重新训练整个模型。这意味着在面对快速变化的信息,如金融市场数据、科技新闻时,RAG系统能够及时提供最新的信息。

二、RAG的发展历程

RAG的概念在2020年由Facebook AI Research(现Meta AI)的研究人员在一篇题为“Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks”的论文中正式提出。该论文建议将稀疏和密集检索器与序列到序列模型相结合,用于处理知识密集型任务。

然而,RAG背后的理念在多个领域有着深厚的根源:

  1. 问答系统
    早期的问答系统在尝试回答问题之前,就已经使用文档检索来查找相关信息。这些早期系统为RAG的发展奠定了基础,启发了将信息检索与答案生成相结合的思路。
  2. 信息检索
    搜索引擎领域数十年的研究为高效的文档检索提供了坚实的基础。从简单的关键词匹配到复杂的语义理解,信息检索技术的不断进步为RAG中的检索环节提供了有力支持。
  3. 神经信息检索
    神经网络在信息检索领域的应用,使得检索能够更加关注语义层面的意义。通过将文本转化为向量表示,神经网络可以更好地理解文本之间的语义关联,提高检索的准确性。
  4. 自然语言处理中的迁移学习
    像BERT这样的预训练语言模型的出现,使得文档表示和检索变得更加有效。预训练语言模型可以学习到丰富的语言特征和语义信息,为RAG系统中的文本处理提供了强大的工具。

随着GPT-3、GPT-4、Claude以及LLaMA等开源替代模型的兴起,RAG的受欢迎程度迅速飙升。企业很快意识到,尽管这些模型功能强大,但为了在商业应用中可靠使用,它们需要与可信的信息来源相结合。如今,RAG已成为应用大语言模型开发的基石,LangChain、LlamaIndex等框架为简化RAG的实现提供了丰富的工具。

三、RAG为何重要

RAG在人工智能领域具有诸多显著优势:

  1. 获取最新信息
    RAG系统能够访问最新的信息,克服了大语言模型知识截止的局限性。在新闻资讯、科技动态等领域,用户可以通过RAG系统获取到最新的事件报道和技术进展。
  2. 领域专业化
    通过提供特定领域的知识库,RAG可以使通用的大语言模型表现得像专业模型一样。在法律领域,结合法律条文和案例的知识库,RAG系统可以为用户提供专业的法律咨询;在金融领域,连接金融数据和市场分析的知识库,RAG系统可以为投资者提供精准的投资建议。
  3. 减少幻觉
    RAG将回答建立在检索到的文档基础上,显著降低了大语言模型生成错误信息的可能性。这一特性在医疗健康领域尤为关键,确保为患者提供的医疗建议准确可靠,避免因错误信息导致的医疗风险。
  4. 降低成本
    与微调或重新训练大型模型相比,RAG只需更改知识库就能适应新的领域,大大降低了成本。对于资源有限的小型企业或研究团队来说,这一优势使得他们能够以较低的成本开发出高效的智能应用。
  5. 可验证性
    RAG系统能够引用信息来源,使其输出更加透明和可验证。在学术研究、商业报告等场景中,这一特性增加了信息的可信度,方便用户进一步查阅和核实信息。
  6. 隐私和安全
    敏感信息可以保留在受控的知识库中,而无需包含在模型的训练数据中。这在处理个人医疗记录、企业商业机密等敏感信息时,有效保护了数据的隐私和安全。

四、构建RAG系统:核心组件

一个典型的RAG系统由多个关键组件构成:

  1. 文档加载器
    负责从各种来源(如PDF文件、网页、数据库等)导入文档。在处理PDF文件时,它能够提取其中的文本内容,为后续的处理做准备。
  2. 文本分块器
    将文档分割成便于索引和检索的小块。合理的分块策略对于系统性能至关重要,分块过大可能包含过多无关信息,分块过小则可能丢失重要上下文。
  3. 嵌入模型
    将文本块转换为数值向量,这些向量能够捕捉文本的语义含义。通过向量表示,文本之间的语义相似度可以通过计算向量之间的距离来衡量。
  4. 向量存储
    对向量进行索引和存储,以便高效地检索。常见的向量存储工具如FAISS,提供了快速的相似性搜索功能。
  5. 检索器
    根据给定的查询,在向量存储中找到最相关的文档。检索器的性能直接影响系统返回结果的质量。
  6. 语言模型
    根据查询和检索到的信息生成回答。语言模型的选择和配置会影响回答的质量和风格。
  7. 提示模板
    指导语言模型如何使用检索到的信息。精心设计的提示模板可以引导语言模型生成更符合用户需求的回答。

五、实现:逐步构建RAG系统

(一)设置环境

构建RAG系统需要使用多个Python库,包括langchain、langchain-core、langchain-community、langchain-experimental、pymupdf、langchain-text-splitters、faiss-cpu、langchain-Ollama、langchain-openai等。这些库各自承担着不同的功能:

  1. LangChain
    提供了构建大语言模型应用的整体框架和组件,简化了开发流程。
  2. PyMuPDF
    能够从PDF文档中提取文本,支持多种PDF特性的处理。
  3. FAISS
    为向量数据库提供高效的相似性搜索能力。
  4. Ollama和OpenAI集成
    允许使用不同的语言模型,为用户提供了更多选择。

可以使用pip命令安装这些库:

pip install langchain langchain-core langchain-community langchain-experimental pymupdf langchain-text-splitters faiss-cpu langchain-ollama langchain-openai

(二)组件1:PDF加载器

from langchain_community.document_loaders import PyMuPDFLoader


class PdfLoader:
    def __init__(self):
        pass

    def read_file(self, file_path):
        loader = PyMuPDFLoader(file_path)
        docs = loader.load()
        return docs

上述代码定义了一个PdfLoader类,其read_file方法使用PyMuPDFLoader从指定的PDF文件路径中加载文档。PyMuPDFLoader基于PyMuPDF库(也称为fitz),能够高效地处理各种PDF特性,包括文本、表格,甚至通过OCR处理一些图像。load()方法返回一个Document对象列表,每个对象代表PDF文件中的一页,包含提取的文本内容(page_content)和元数据(metadata),如源文件路径和页码。在实际应用中,可扩展该类以处理其他文档类型。

(三)组件2:文本分块

from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Document


class Chunker:
    def __init__(self, chunk_size=1000, chunk_overlap=100):
        self.text_splitter = RecursiveCharacterTextSplitter(
            separators=["\n\n", "\n", " ", ".", ",", "\u200b", "\uff0c", "\u3001", "\uff0e", "\u3002", ""],
            chunk_size=chunk_size,
            chunk_overlap=chunk_overlap,
            length_function=len,
            is_separator_regex=False
        )

    def chunk_docs(self, docs):
        list_of_docs = []
        for doc in docs:
            tmp = self.text_splitter.split_text(doc.page_content)
            for chunk in tmp:
                list_of_docs.append(
                    Document(
                        page_content=chunk,
                        metadata=doc.metadata
                    )
                )
        return list_of_docs

Chunker类负责将加载的文档分割成较小的文本块。在初始化时,通过设置chunk_size(默认1000个字符)和chunk_overlap(默认100个字符)来控制分块的大小和重叠程度。RecursiveCharacterTextSplitter使用一系列分隔符(包括段落分隔符、换行符、空格、标点符号等)来分割文本,优先在自然边界处分割。chunk_docs方法对输入的文档列表进行处理,为每个文本块创建新的Document对象,并保留原始文档的元数据。

(四)组件3:向量存储

import faiss
from langchain_community.docstore.in_memory import InMemoryDocstore
from langchain_community.vectorstores import FAISS
from langchain_ollama import OllamaEmbeddings
from uuid import uuid4


class VectorStore:
    def __init__(self):
        self.embeddings = OllamaEmbeddings(model="llama3.2:3b")
        self.index = faiss.IndexFlatL2(len(self.embeddings.embed_query("hello world")))
        self.vector_store = FAISS(
            embedding_function=self.embeddings,
            index=self.index,
            docstore=InMemoryDocstore(),
            index_to_docstore_id={}
        )

    def add_docs(self, list_of_docs):
        uuids = [str(uuid4()) for _ in range(len(list_of_docs))]
        self.vector_store.add_documents(documents=list_of_docs, ids=uuids)

    def search_docs(self, query, k=5):
        results = self.vector_store.similarity_search(
            query,
            k=k
        )
        return results

VectorStore类是检索系统的核心。在初始化时,创建一个OllamaEmbeddings嵌入模型(这里使用llama3.2:3b模型),并基于FAISS创建一个用于L2距离计算的索引,同时初始化一个包含嵌入函数、索引和文档存储的向量存储。add_docs方法为每个文档生成唯一ID,并将文档添加到向量存储中,向量存储会计算文档内容的嵌入并进行索引。search_docs方法将输入的查询转换为嵌入,在向量存储中执行相似性搜索,并返回最相似的k个文档。在实际生产中,可考虑使用持久化向量存储、添加元数据过滤功能或实现混合搜索。

(五)组件4:RAG系统

from langchain_core.prompts import PromptTemplate
from langchain_openai import OpenAI
from langchain_ollama import OllamaLLM
from pdf_loader import PdfLoader
from vector_store import VectorStore
from chunk_text import Chunker


class RAG:
    def __init__(self):
        self.instructor_prompt = """Instruction: You're an expert problem solver you answer questions from context given below. You strictly adhere to the context and never move away from it. You're honest and if you do not find the answer to the question in the context you politely say "I Don't know!"
        So help me answer the user question mentioned below with the help of the context provided
        User Question: {user_query}
        Answer Context: {answer_context}
        """
        self.prompt = PromptTemplate.from_template(self.instructor_prompt)
        self.llm = OllamaLLM(model="llama3.2:3b")  # OpenAI()
        self.vectorStore = VectorStore()
        self.pdfloader = PdfLoader()
        self.chunker = Chunker()

    def run(self, filePath, query):
        docs = self.pdfloader.read_file(filePath)
        list_of_docs = self.chunker.chunk_docs(docs)
        self.vectorStore.add_docs(list_of_docs)
        results = self.vectorStore.search_docs(query)
        answer_context = "\n\n"
        for res in results:
            answer_context = answer_context + "\n\n" + res.page_content
        chain = self.prompt | self.llm
        response = chain.invoke(
            {
                "user_query": query,
                "answer_context": answer_context
            }
        )
        return response


if __name__ == "__main__":
    rag = RAG()
    filePath = "investment.pdf"
    query = "How to invest?"
    response = rag.run(filePath, query)
    print(response)

RAG类将前面构建的各个组件整合在一起,形成一个完整的RAG系统。在初始化时,定义一个指导语言模型的提示模板,创建PromptTemplate对象,并初始化语言模型、向量存储、PDF加载器和文本分块器。run方法实现了完整的RAG工作流程:加载PDF文档,分块处理,添加到向量存储,根据用户查询搜索相关文本块,组合检索到的文本块形成上下文,将提示模板与语言模型结合生成回答。在主程序中,创建RAG实例,指定PDF文件路径和查询,运行系统并打印结果。

六、高级考虑与改进

尽管上述实现为RAG系统奠定了坚实的基础,但在实际生产应用中,还有许多方面可以进一步优化和改进:

  1. 文档处理增强
    支持多种文档格式,如Word文档、网页、数据库等;提取文档的元数据,如创建日期、作者、标题等;集成OCR技术,处理扫描文档或图像;实现表格数据的专门提取和处理。
  2. 分块策略优化
    采用语义分块,基于文本的语义含义进行分割,而非单纯依据字符数量;实施层次分块,维护文档结构,建立块之间的父子关系;在分块元数据中包含章节标题或文档结构信息,提升检索和理解效果。
  3. 嵌入和检索改进
    增加重排序步骤,对初始检索结果进行优化;结合向量相似性和基于关键词(如BM25)的混合搜索,提高检索的准确性;自动扩展查询,提升检索性能;使用交叉编码器重排序,虽然计算成本较高,但能获得更精确的结果。
  4. 大语言模型集成优化
    实现流式响应,提升用户体验,特别是在处理长回答时;修改提示,引导模型进行逐步推理;让模型对自己的回答进行评估和优化;将复杂查询分解为子问题,提高处理复杂任务的能力。
  5. 评估和监测
    评估检索到的文档与查询的相关性;在有标准答案的情况下,对比生成的答案与标准答案,评估回答的准确性;检测模型是否产生幻觉信息;建立用户反馈循环,根据用户反馈不断改进系统性能。

七、生产环境中的RAG扩展

(一)安全和合规

在生产环境中,RAG系统处理的数据可能包含敏感信息,如企业的商业机密、客户的个人数据等。因此,实施严格的安全和合规措施至关重要。

  1. 访问控制
    对敏感文档设置多层次的访问权限,确保只有经过授权的人员或服务才能访问特定的知识库内容。可以基于用户角色、部门、数据敏感度等因素进行权限划分,例如,财务部门的用户只能访问与财务相关的文档,且不同职级的人员访问权限也有所区别。
  2. 日志记录
    详细记录系统操作日志,包括文档的访问记录、查询内容、模型的响应等。这些日志不仅有助于追踪系统的使用情况,还能为安全审计提供依据。通过分析日志,可以及时发现潜在的安全风险,如异常的查询行为或未经授权的访问尝试。
  3. 数据合规处理
    确保对个人可识别信息(PII)的处理符合相关法规,如GDPR、CCPA等。在数据收集、存储、使用和共享过程中,遵循严格的数据保护原则,对PII进行加密存储和传输,避免数据泄露带来的法律风险。

(二)性能优化

为了满足生产环境中大量用户和复杂查询的需求,需要对RAG系统进行全面的性能优化。

  1. 预计算嵌入
    对于大规模的文档集合,在系统初始化或文档更新时预先计算文本块的嵌入向量。这样在查询时,无需实时计算嵌入,大大减少了响应时间。可以定期重新计算嵌入,以适应文档内容的变化或采用更先进的嵌入模型。
  2. 缓存机制
    在多个层面实现缓存,包括查询缓存、嵌入缓存和响应缓存。查询缓存可以存储常见查询及其对应的检索结果,当相同查询再次出现时,直接返回缓存的结果;嵌入缓存用于保存已经计算过的文本块嵌入向量,避免重复计算;响应缓存则存储模型生成的回答,提高相同问题的响应速度。
  3. 量化技术
    采用量化技术将高维的嵌入向量转换为低精度的表示,在不显著损失语义信息的前提下,减小向量的存储空间和计算量。例如,将32位浮点数的向量转换为16位或8位的表示形式,加快相似性搜索的速度,同时降低内存和计算资源的消耗。

(三)基础设施

合理的基础设施架构是保障RAG系统在生产环境中稳定运行和可扩展的关键。

  1. 容器化部署
    使用容器技术(如Docker)将RAG系统的各个组件(文档加载器、文本分块器、向量存储、语言模型等)封装成独立的容器。容器化部署使得组件的部署、管理和更新更加便捷,同时隔离了不同组件的运行环境,提高了系统的稳定性和安全性。
  2. 微服务架构
    将RAG系统拆分为多个微服务,每个微服务负责特定的功能,如文档处理服务、检索服务、语言模型服务等。微服务架构提高了系统的可扩展性,可以根据业务需求独立扩展各个服务的资源,同时降低了系统的耦合度,便于维护和升级。
  3. 队列系统
    引入队列系统(如Kafka、RabbitMQ)来处理大量文档的异步任务,如文档加载、嵌入计算等。当有大量文档需要处理时,将任务放入队列中,由后台的工作进程依次处理,避免因任务堆积导致系统性能下降,确保系统在高负载情况下仍能稳定运行。

(四)持久性

确保RAG系统中的数据和模型状态能够持久保存,以便在系统重启或故障恢复时能够快速恢复运行。

  1. 持久化存储
    选择可靠的持久化数据库(如Pinecone、Weaviate、Chroma等向量数据库,以及关系型数据库或NoSQL数据库用于存储文档元数据)来存储嵌入向量和文档信息。这些数据库提供了数据的持久化存储、高效的索引和查询功能,保证数据的安全性和可访问性。
  2. 增量更新
    实现增量更新机制,当有新文档添加或现有文档更新时,只对变化的部分进行处理,而不是重新处理整个文档集合。例如,在向量存储中,只更新新增或修改文档的嵌入向量,减少数据处理的开销,提高系统的更新效率。

检索增强生成(RAG)作为大语言模型发展中的重要突破,通过结合外部知识源,显著提升了语言模型的实用性、可靠性和可信度。本文详细介绍了RAG的概念、发展历程、重要性,以及使用Python和开源库从零构建RAG系统的全过程,包括文档加载、文本分块、向量存储和响应生成等核心组件的实现。

同时,针对生产环境的需求,探讨了一系列高级改进策略和扩展要点,涵盖文档处理优化、分块策略改进、嵌入检索增强、大语言模型集成优化、系统评估监测以及生产环境部署等多个方面。通过这些措施,可以不断完善RAG系统,使其更好地适应各种实际应用场景。

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询