RAG简要流程概述
检索增强生成(RAG)流程简述
检索增强生成(Retrieval-Augmented Generation, RAG)是一种结合了信息检索和文本生成能力的人工智能技术。它旨在解决大型语言模型(LLM)可能存在的“幻觉”(生成不准确或虚构信息)问题,并通过引入外部知识库来增强模型的回答质量和准确性。简单来说,当用户提出问题时,RAG系统会首先从一个或多个知识源中检索相关信息,然后将这些检索到的信息作为上下文提供给大型语言模型,最后由大型语言模型根据这些信息生成回答。
以下将结合提供的 main.py 代码文件,简要说明RAG的大致流程及其核心组成部分。
1. 文档分片(Document Splitting)
RAG流程的第一步是将原始文档(知识库)分割成更小的、可管理的片段(chunks)。这样做有几个好处:
-
提高检索效率:在大型文档中检索相关信息时,如果直接处理整个文档,效率会很低。分片后,可以更快地定位到与查询相关的部分。
-
适应模型输入限制:大型语言模型通常有输入长度限制(上下文窗口)。将文档分片可以确保每个片段都能适应模型的输入,避免信息截断。
-
聚焦相关性:更小的片段有助于检索系统更精确地找到与用户问题最相关的具体信息,而不是整个文档。
在 main.py 中,split_to_chunks 函数负责这个任务,它简单地通过双换行符 \n\n 来分割文档内容。
代码片段:
def split_to_chunks(doc_file):
with open(doc_file,"r",encoding="utf-8") as file:
content = file.read()
chunk = content.split("\n\n")
return chunk
2. 向量化(Embedding)
为了让计算机理解和比较文本片段的语义,我们需要将这些文本转换成数值向量,这个过程称为“向量化”或“嵌入”(Embedding)。语义相似的文本片段在向量空间中会彼此靠近。
main.py 使用 SentenceTransformer 模型来生成文本嵌入。SentenceTransformer 是一种预训练模型,专门用于将句子或段落映射到密集向量空间中。
代码片段:
from sentence_transformers import SentenceTransformer
embedding_model = SentenceTransformer("shibing624/text2vec-base-chinese")
# 利用embedding模型将片段变成向量
def embedding_chunk(chunk):
embedding = embedding_model.encode(chunk)
return embedding.tolist()
3. 向量数据库存储(Vector Database Storage)
生成文本片段的向量后,这些向量需要被存储在一个专门的数据库中,以便进行高效的相似性搜索。这种数据库被称为向量数据库(Vector Database)。向量数据库能够快速地根据查询向量找到最相似的向量,从而实现语义检索。
main.py 中使用了 chromadb,一个轻量级的开源向量数据库,来存储和管理这些文本片段及其对应的嵌入向量。
代码片段:
import chromadb chromadb_client = chromadb.EphemeralClient() chromadb_collection = chromadb_client.get_or_create_collection(name = "my_collection") # 将embedding后的向量保存进chroma向量库 def save_embeddings(chunks,embeddings): ids = [str(i) for i in range(len(chunks))] chromadb_collection.add( documents = chunks, embeddings = embeddings, ids = ids )
4. 召回(Retrieval)
当用户提出问题时,RAG系统会首先将用户的问题也进行向量化,然后利用这个查询向量在向量数据库中进行相似性搜索,找出与问题最相关的文本片段。这个过程就是“召回”(Retrieval)。召回的目的是从大量的知识库中筛选出可能包含答案的少量相关信息。
main.py 中的 retrieve 函数负责执行召回操作,它会根据用户问题的嵌入向量,从 chromadb_collection 中查询出最相似的 top_k 个文档片段。
代码片段:
# 根据问题对向量进行召回 def retrieve(query,top_k): query_embedding = embedding_chunk(query) results = chromadb_collection.query( query_embeddings = [query_embedding], n_results = top_k ) return results["documents"][0]
5. 重排(Reranking)
召回阶段可能会返回一些相关性不那么高的片段,或者相关片段的排序不够理想。为了进一步提高提供给大型语言模型的上下文质量,RAG流程通常会引入“重排”(Reranking)步骤。重排器(Reranker)会对召回的片段进行二次排序,根据它们与查询的实际语义相关性给出更精确的评分,从而将最相关的片段排在前面。
main.py 中使用了 cross-encoder/mmarco-mMiniLMv2-L12-H384-v1 交叉编码器模型进行重排。交叉编码器能够同时考虑查询和文档片段的语义,给出更准确的相关性分数。
代码片段:
from sentence_transformers import CrossEncoder
cross_encoder = CrossEncoder("cross-encoder/mmarco-mMiniLMv2-L12-H384-v1")
# 对召回后的内容进行重排
def rerank(query,retrieved_chunks,top_k):
pairs = [(query,chunk) for chunk in retrieved_chunks]
scores = cross_encoder.predict(pairs)
chunk_scores = list(zip(retrieved_chunks,scores))
chunk_scores.sort(key = lambda x : x[1] , reverse = True )
return [chunk[0] for chunk in chunk_scores][:top_k]
6. 生成(Generation)
经过召回和重排后,我们得到了与用户问题最相关的几个高质量文本片段。接下来,这些片段将作为上下文(context)输入给大型语言模型(LLM)。大型语言模型会根据用户的问题和这些提供的上下文来生成最终的回答。这个过程就是“生成”(Generation)。
main.py 中使用了 OpenAI 的大型语言模型进行生成。它构建了一个包含用户问题和相关片段的提示(prompt),然后将这个提示发送给LLM以获取回答。
代码片段:
from openai import OpenAI
from dotenv import load_dotenv
import os
load_dotenv()
client = OpenAI(
api_key = os.getenv("OPENAI_API_KEY"),
base_url = os.getenv("OPENAI_BASE_URL")
)
model = os.getenv("OPENAI_MODEL")
# 将问题与重排后的内容递交给大模型
def generate(query,chunks):
prompt = f"""你是一位知识助手,请根据用户的问题和下列片段生成准确回答。
用户问题:{query}
相关片段:{"\n\n".join(chunks)}
请基于以上内容作答。"""
response = client.chat.completions.create(
model = model,
messages=[
{
"role":"user",
"content":prompt
}
]
)
return response.choices[0].message.content
总结
检索增强生成(RAG)通过“文档分片 -> 向量化 -> 向量数据库存储 -> 召回 -> 重排 -> 生成”这一系列步骤,有效地结合了信息检索的精确性和大型语言模型的生成能力。它使得LLM能够基于更准确、更相关的外部知识来回答问题,从而显著提升了回答的质量和可靠性。
更多推荐



所有评论(0)