首先讲在前面,介绍一些背景
RAG(Retrieval-Augmented Generation,检索增强生成)
是一种结合了信息检索与语言生成模型的技术,通过从外部知识库中检索相关信息,并将其作为提示输入给大型语言模型(LLMs),以增强模型处理知识密集型任务的能力。以下是RAG的具体操作过程解析:
1.数据准备阶段
• 数据提取:使用相应的数据加载器从各种数据源(如PDF、Word、CSV、HTML等)中提取文本数据。例如,可以使用TextLoader
加载txt文本。
• 文本分割:将提取的文本分割成适当大小的块,以确保每个块的内容具有一定的语义完整性。常用的分割方法包括字符级分割、递归方式分割等。
• 向量化(embedding):使用嵌入模型(如HuggingFaceBgeEmbeddings
)将分割后的文本块转换为向量表示。• 数据入库:将向量化后的文本块存储到向量数据库(如Chroma
、weaviate
、FAISS
等)中,以便后续的高效检索。
2.检索阶段
• 用户提问:用户提出问题,系统需要从知识库中检索与该问题相关的信息。
• 向量化查询:使用相同的嵌入模型将用户的问题转换为向量表示。
• 相似度计算与检索:计算问题向量与知识库中文档块向量之间的相似度,选择相似度最高的前K个文档块作为当前问题的增强上下文信息。3.生成阶段
• 构造Prompt:将用户的问题和检索到的相关文档合并为一个新的提示(Prompt),可以使用ChatPromptTemplate
等工具来构造。• LLM生成答案:将构造好的提示输入到大型语言模型(如ChatZhipuAI
),模型会基于提供的信息生成最终的回答。
4.高级RAG
• 数据预处理:在数据索引阶段进行更精细的数据清洗、设计文档结构和添加元数据等,以提升文本的一致性、准确性和检索效率。
• 检索前处理:在检索前可以进行一些额外的处理,如查询扩展、语义解析等,以提高检索的准确性。
• 检索后处理:在检索后可以对结果进行排序、去重、融合等操作,以优化检索结果的质量。
• 生成优化:将检索与微调、强化学习等技术融合,进一步提升生成结果的质量和相关性。
5.模块化RAG
• 功能模块化:将RAG系统分解为多个功能模块,如查询搜索引擎、融合多个回答等,每个模块负责特定的任务。
• 模块编排:根据具体的应用场景和需求,对各个模块进行灵活的设计和编排,形成多种RAG模式。通过上述过程,RAG技术能够有效地结合外部知识库和大型语言模型的优势,生成更准确、更符合用户需求的回答。
向量化后的向量长度
• 固定长度:嵌入模型通常会将文本转换为固定长度的向量。例如,常见的嵌入模型如text-embedding-ada-002
会生成固定长度的向量(如1024维或768维),无论输入文本的长度如何。
• 与文章无关:因此,不同文章的向量化后的向量长度是相同的,都是由嵌入模型的输出维度决定的。
向量数据库的存储
• 存储向量:向量化后的文本向量会被存储在向量数据库中。向量数据库专门用于存储和检索高维向量数据,如FAISS、Milvus等。
• 索引结构:向量数据库通常会建立索引结构(如KD树、球树、LSH等),以便快速检索相似向量。
检索和相似度计算
• 用户提问向量化:当用户提出问题时,使用相同的嵌入模型将问题文本转换为向量表示。
• 相似度计算:计算用户问题向量与向量数据库中存储的向量之间的相似度。常用的相似度计算方法包括:
• 余弦相似度:衡量两个向量之间的夹角余弦值,值越大表示越相似。
• 欧氏距离:衡量两个向量之间的直线距离,值越小表示越相似。
• 检索相关向量:根据相似度计算结果,选择相似度最高的前K个向量对应的文本块作为检索结果。
• 返回对应信息:通过检索到的文本块,找到与用户问题相关的信息,并将其作为上下文提供给语言模型进行生成。
示例代码
以下是一个简单的示例代码,展示如何使用嵌入模型和向量数据库进行检索:
from openai import OpenAI
import numpy as np
from numpy.linalg import norm
# 初始化OpenAI客户端
client = OpenAI()
# 获取嵌入向量
def get_embedding(text, model="text-embedding-ada-002"):
response = client.embeddings.create(input=text, model=model)
return response.data[0].embedding
# 计算余弦相似度
def cosine_similarity(a, b):
return np.dot(a, b) / (norm(a) * norm(b))
# 示例文档
documents = [
"联合国就苏丹达尔富尔地区大规模暴力事件发出警告",
"土耳其、芬兰、瑞典与北约代表将继续就瑞典“入约”问题进行谈判",
"日本岐阜市陆上自卫队射击场内发生枪击事件 3人受伤",
"国家游泳中心(水立方):恢复游泳、嬉水乐园等水上项目运营",
"我国首次在空间站开展舱外辐射生物学暴露实验",
]
# 获取文档的嵌入向量
doc_embeddings = [get_embedding(doc) for doc in documents]
# 用户提问
query = "国际争端"
query_embedding = get_embedding(query)
# 计算相似度
similarities = [cosine_similarity(query_embedding, doc_embedding) for doc_embedding in doc_embeddings]
# 输出最相似的文档
most_similar_index = np.argmax(similarities)
print(f"最相似的文档: {documents[most_similar_index]}")
输出结果
最相似的文档: 土耳其、芬兰、瑞典与北约代表将继续就瑞典“入约”问题进行谈判
通过上述过程,可以有效地根据用户提出的问题找到相关的向量和对应的信息。