AI知识库

53AI知识库

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


RAG(检索增强生成)系统实践与调优
发布日期:2025-01-07 08:16:55 浏览次数: 1592 来源:AI遇见云




在人工智能领域,检索增强生成(Retrieval Augmented Generation, RAG)是一种结合信息检索和生成式人工智能的技术,它通过从外部数据源中检索相关信息,来辅助大语言模型(Large Language Model, LLM)生成更为准确、上下文相关的答案。




1

什么是RAG



   检索增强生成(Retrieval Augmented Generation, RAG)是一种结合信息检索和生成式人工智能的技术,它通过从外部数据源中检索相关信息,来辅助大语言模型(Large Language Model, LLM)生成更为准确、上下文相关的答案。具体来说,RAG 的工作流程包括两个关键步骤:首先,系统会根据用户的查询从预先构建的数据源中检索相关的文档或片段;然后,将这些检索到的内容作为上下文信息,和用户的问题一起输入到大语言模型中,以生成更丰富、更具参考价值的回答。RAG系统结合了搜索技术和大语言模型的生成能力:搜索技术用于找到与问题最相关的事实或数据,而大语言模型则通过处理这些信息,生成连贯、准确且更符合用户需求的自然语言回答。因此,RAG 不仅能够弥补语言模型在训练数据之外的知识盲区,还可以显著提升回答的精准性和可靠性,特别是在需要实时更新或扩展知识的应用场景中。


RAG 的工作流程主要包含三个模块:

索引(Indexing):文本索引的构建包括以下步骤:文档解析、文本分块、Embedding 向量化和创建索引。先将不同格式的原始文件解析转换为纯文本,再把文本切分成较小的文本块。通过 Embedding 为每一个文本块生成一个向量表示,用于计算文本向量和问题向量之间的相似度。创建索引将原始文本块和 Embedding 向量以键值对的形式存储,以便将来进行快速和频繁的搜索。

检索(Retrieval):使用 Embedding 模型将用户输入问题转换为向量,计算问题的 Embedding 向量和语料库中文本块 Embedding 向量之间的相似度,选择相似度最高的前 K 个文档块作为当前问题的增强上下文信息。

生成(Generation):将检索得到的前 K 个文本块和用户问题一起送进大模型,让大模型基于给定的文本块来回答用户的问题。


2

RAG实践



下面是一个使用Xinference 部署bge-embedding 模型并结合Langchain 实现简单的 RAG(检索增强生成)应用的实践步骤:


1. 使用 Xinference部署bge-embedding模型


bge-embedding 模型(bge-m3-embedding)可以通过Xinference部署,具体步骤如下:


1.1 安装Xinference


JSON
pip install --upgrade --quiet "xinference[all]"


1.2 启动bge-embedding模型


JSON
xinference launch --model-name bge-m3 --model-type embedding


启动后可通过xinference webui查看running model


 

2. LangChain中集成bge-embedding模型和LLM


2.1 安装LangChain


JSON
pip install langchain


2.2集成远端bge-embedding 模型


LangChain提供了对嵌入模型的抽象,可以创建一个自定义的嵌入模型类来调用远端的bge-embedding 服务。


Python
import requests
from langchain.embeddings.base import Embeddings

class RemoteBGEEmbedding(Embeddings):
    def __init__(self, api_url):
        self.api_url = api_url

    def embed(self, text: str):
        response = requests.post(self.api_url, json={"text": text})
        if response.status_code == 200:
            return response.json()["embedding"]
        else:
            raise Exception(f"Failed to get embedding: {response.content}")


api_url 在远端部署的bge-embedding 模型的 API地址。


调用POST 请求,将文本传递给远端的bge-embedding 模型,获取对应的嵌入向量。


2.3 调用远端LLM,此处采用QWEN14B


同理,LLM也需要集成


Python
class RemoteQwenLLM:
    def __init__(self, api_url):
        self.api_url = api_url

    def generate(self, prompt: str):
        response = requests.post(self.api_url, json={"prompt": prompt})
        if response.status_code == 200:
            return response.json()["response"]
        else:
            raise Exception(f"Failed to get response: {response.content}")


api_url 是远端 LLM生成API地址。


3.构建 RAG管道


使用 LangChainRetrievalAugmentedGeneration 类来集成上述两个模型,实现检索增强生成:


Python
from langchain.chains import RetrievalAugmentedGeneration
from langchain.vectorstores import FAISS
from langchain.document_loaders import TextLoader

# 初始化远端的 bge-embedding 嵌入模型
bge_embedding = RemoteBGEEmbedding(api_url="http://your-bge-embedding-server.com/embedding")

# 加载文档数据并创建向量存储
loader = TextLoader("path/to/your/data.txt") # 替换为你的文档路径
documents = loader.load()
vector_store = FAISS.from_documents(documents, bge_embedding)

# 初始化远端的 Qwen 生成模型
qwen_llm = RemoteQwenLLM(api_url="http://your-qwen-server.com/generate")

# 创建 RAG 管道
rag_chain = RetrievalAugmentedGeneration(
    llm=qwen_llm, # 使用远程 Qwen 模型
    retriever=vector_store.as_retriever(),
    input_key="input",
    output_key="output"
)


4.执行RAG应用


Python
# 测试 RAG 流程
query = "中国的历史发展是怎样的?"
result = rag_chain.run(query)
print(result)



3

调优和进阶技术



随着技术的发展,RAG系统经历了几个阶段的演变,包括Naive RAGAdvanced RAGModular RAGNaive RAG是最基本的RAG实现,它通常只涉及简单的检索和生成步骤,没有太多复杂的优化。Advanced RAGNaive RAG的基础上增加了更多的策略和优化,如索引优化、迭代检索和检索后处理,以提高系统的性能。Modular RAG则进一步发展,提供了更高的灵活性和可定制性,允许通过引入不同的模块和调整模块间的流程来适应各种复杂的任务和需求。在Modular RAG中,数据清洗、问题转换、多路召回和重排序和过滤等是一些有效的调优技术模块实现,下面是这些技术的介绍和说明。




1. 数据清洗


RAG中,数据清洗至关重要,直接关系到了检索召回的效果,常用的数据清洗手段有低质量数据知识增强和非结构化数据处理。

(1)低质量数据知识增强


一般来说,对称召回任务比非对称召回任务要简单,特别在很多垂直领域,向量模型对领域知识的理解有限,对称召回很多时候理解了字面意思就能满足要求。为了方便描述,下文把对称召回称为 QQQuery-Question)召回,把非对称召回称为QDQuery-Document)召回。


知识增强一般是指,根据上下文重新 Refine原始的文本使得原始的文本信息更完整,自解释性更强。这个过程由于是离线的一次性处理,所以这里可以借助能力更强的商用LLM模型,生成的内容可能会更好。另外由于现在的LLM能支撑的上下文context长度很长,建议在生成的过程中,在prompt中去融入一些该场景的丰富背景信息。具体过程如下图所示:


 

通过知识增强,可以把文本文档也转化成 FAQ的形式,使得对于一般的文档也能够同时进行QQQD召回。


(2)非结构化数据处理


在文档数据处理时,一些关键信息以非结构化数据,以下面的社保卡换领流程图为例


 

上面的关键信息为流程图,常用的文档解析方式无法处理,从而导致召回时无法检索到响应内容并回答,为了解决该问题,可通过LLM将流程图转markdown代码


Plain Text
graph TD 
    A[2019新版社保卡换领] --> B{分批换领} 
    B -->|2019年1月-2019年6月| C[退休人员换领] 
    B -->|2019年8月-2019年9月| D[中小幼人员换领] 
    B -->|2019年7月-2020年12月| E[在职人员换领] 

    C --> F[本人到银行(社区)网点申领] 
    F --> G[填写申请表并签字] 

    D --> H[登录上海社会保障卡服务中心网站] 
    D --> I[通过“上海社保卡”微信公众号/APP换领] 
    D --> J[在“上海社保”微信公众号后台办理] 

    E --> K[单位组织员工填写申请表] 
    K --> L[银行批量提交] 

    H --> M[注册并实名认证] 
    I --> M 
    J --> M 

    M --> N[输入申领信息] 
    N --> O[集中制卡] 
    O --> P[邮政快递邮寄] 
    P --> Q[到银行网点开通金融、社保功能]


在召回时将上面的markdown代码给到LLM即可完成流程图相关内容的问答。




2. 问题转换


问题转换 RAG系统中的一个重要步骤,尤其在面对复杂、多样化的用户问题时,能够对检索结果的质量产生深远影响。问题转换的核心思想是将用户输入的问题转化为适合检索的形式,以提高检索效率和准确性。常用方式有:


1.语义转换:很多用户提问时,可能会使用自然语言的表达,而这些表达未必最适合直接进行检索。问题转换模块通过分析问题的语义,将自然语言问题转换为适合关键词匹配或向量检索的形式。例如,将复杂问题分解为简单的子问题,或者提取出问题中的关键信息进行检索。


2.问题重构:对于多轮对话,问题转换模块可以结合之前的上下文,重构当前问题,使其在检索时更具连贯性。比如,如果当前问题是一个不完整的询问,问题转换模块会根据之前的对话历史补充必要的细节,以提升检索的精准度。


3.多模式转换:问题转换还可以针对不同类型的数据源(文本、图像、视频等)进行不同的处理。例如,针对多模态数据源的系统,问题转换模块需要将自然语言问题转化为对应模态的检索形式(如图像特征、视频片段等)。


 

以历史对话为例,通过输入用户与系统的多轮对话,目标是根据上下文重构问题,使其在检索时更具准确性。


对话上下文:


JSON
用户:请告诉我任务管理的最佳实践。
系统:任务管理的最佳实践包括任务优先级排序、时间管理、团队协作等。你是否想了解某个具体的方面?
用户:好的,关于任务优先级。


原始问题:


用户当前的问题是关于任务优先级。这是一个不完整的自然语言问题,在没有上下文的情况下,这个问题可能不明确,检索系统可能无法理解用户的具体需求。


问题重写提示词:


JSON
## 任务:根据用户和AI的历史对话内容进行总结。

## 要求:- 使用专业且简洁的语言。- 将用户当前的问题重新表述为一个清晰、简洁且自包含的查询,适合信息检索使用。- 如果当前问题已经足够清晰和完整,请保持原样输出。

## 示例:---### 历史信息:用户咨询了关于 Spring 动态 Bean 管理的技术问题,AI 提供了使用 ConcurrentHashMap 管理 Bean 的建议。### 当前问题:动态管理 Spring 的 Bean?### 总结:如何使用 ConcurrentHashMap 动态管理 Spring Bean?

## 历史信息:{{history_summary}}
## 当前问题:{{question}}


重写后问题:


JSON
“任务管理的最佳实践中,如何有效进行任务优先级排序?”


在多轮对话和复杂查询场景中,通过问题重写转换可以显著提升召回率。




3. 多路召回


多路召回(Multi-Channel Retrieval)是RAG系统中用于提升检索结果多样性和覆盖度的关键机制。通过使用不同的检索策略和通道,系统可以最大程度地覆盖问题相关的文档,确保生成的答案基于更全面的上下文信息。其中多路的概念可表示为对多个向量库进行检索,也可表示采用多种召回算法进行混合检索。



混合检索


向量检索和关键词检索在检索领域各有其优势。向量检索优势:复杂语义的文本查找,相近语义理解,多语言理解,多模态理解,容错性。传统关键词搜索优势:精确匹配,少量字符的匹配,倾向低频词汇的匹配。混合检索结合了向量检索和关键词检索的优势,通过多个检索系统的组合,实现了多个检索技术之间的互补。


1.倒排召回:倒排索引是一种经典的关键词匹配方式,主要应用于基于传统文本搜索的场景,如使用 BM25等方法。倒排召回速度快,适合处理精确匹配场景。它基于词项的出现频率和文档倒排索引进行匹配,在面对具体的术语或关键词查询时效果尤为显著。

2.向量召回:向量召回基于语义嵌入,通过将文档和查询转换为向量表示,并在向量空间中计算它们的相似度来进行检索。向量召回特别适合处理模糊、语义相关性较强的问题,能够在概念上找到更具相关性的文档,即使这些文档没有包含查询中的具体关键词。



4. 重排序和过滤


重排序在RAG过程中起着至关重要的作用。在简单的RAG方法中,可能会检索到大量上下文,但并非所有上下文都与问题相关。重新排序可以对文档进行重新排序和过滤,将相关文档放在最前面,从而提高RAG的效率。


(1)RRF多检索融合


RRFRanked Retrieval Fusion)是一种将多个检索系统的排名结果进行融合的方法,它能够综合不同检索方法的优点。将关键词检索(BM25等)和向量检索(基于嵌入的检索)结合在一起,可以提升检索的效果。RRF通常按照检索结果的排名进行分数计算,最终得出一个融合后的排名。


下面通过一个具体的检索结果例子展示关键词检索(BM25)和向量检索的结果如何结合RRF排序来得到最终的排序结果。


假设我们有以下五个文档D1~D5,并且进行两个不同的检索:


文档ID


关键词检索BM25)排名


向量检索(基于嵌入的语义相似度)排名


D1


3


1


D2


1


4


D3


5


2


D4


2


3


D5


4


5


根据RRF公式分别计算D1~D5文档得分,


 

其中,k 为常数,通常选择k = 60rank_i(d) 表示第 i种检索方法中文档d 的排名。


文档D10.03226


文档D20.03202


文档D40.03200


文档D30.03151


文档D50.03101


根据RRF分数排序,最终的文档排名为:


1.D1(分数:0.03226


2.D2(分数:0.03202


3.D4(分数:0.03200


4.D3(分数:0.03151


5.D5(分数:0.03101


(2)语义检索:相似相关



- EmbeddingBi-Encoder)双编码器


结构:Bi-Encoder使用两个独立的编码器来处理查询(query)和文档(document),分别生成它们的嵌入表示(embeddings)。


Embedding模型根据查询(query)和文档(document)给出相似度得分,但是这个得分描述的更多的是相似性。Embedding本质上是一个双编码器,两个文本在模型内部没有任何信息交互。只在最后计算两个向量的余弦相似度时才进行唯一一次交互。


- RerankCross-Encoder)交叉编码器


结构:Cross-Encoder将查询和文档拼接在一起,作为一个整体输入到一个单一的编码器中。


Rerank本质是一个Cross-Encoder的模型。Cross-Encoder能让两个文本片段一开始就在BERT模型各层中通过self-attention进行交互。


采用两阶段检索结合可以兼顾效果和效率:


第一个阶段的目标是尽可能多的召回相似的文本片段,这个阶段的文本得分排序不是特别靠谱,所以候选的 topK可以设置大一些,比如topK=10


第二个阶段的目标是对 10个粗排的候选文本片段进行重新排序,用cross-encoder计算10个候选文本和query的相关度得分。


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

产品:大模型应用平台+智能体定制开发+落地咨询服务

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

联系我们

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

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询