基于 LangChain + 通义千问 + bge-large 中文 Embedding 搭建一个RAG问答示例
文章目录
- LangChain介绍
- RAG简介
- embedding模型权重下载代码
- 核心代码实现
- 代码解析
- 1. 环境配置与依赖
- 2. 模型设置
- 3. 数据处理流程
- 4. 提示模板设计
- 5. 链(Chain)的编排
- 使用方法
最近我尝试使用LangChain框架结合阿里云的通义千问模型构建了一个简单的RAG(检索增强生成)应用,在这里记录一下实现过程和关键代码解析。
LangChain介绍
LangChain 是一个用于构建基于大型语言模型(LLM)应用程序的流行开源框架。它提供模块化组件和工具链,简化了将 LLM 集成到实际应用中的流程,支持开发问答系统、聊天机器人、自动化代理等场景。其它流行的框架还有LlamaIndex,它可以和LangChain进行结合开发。
LangChain详细文档:https://python.langchain.com/docs/introduction/
RAG简介
RAG是一种将检索与生成相结合的AI应用架构,通过先检索相关知识再生成回答的方式,既能利用大模型的生成能力,又能保证回答的准确性和时效性。主要流程包括:
- 加载并处理文档数据
- 将文档向量化并存储
- 根据用户问题检索相关文档片段
- 结合检索到的信息生成回答
embedding模型权重下载代码
运行下面的代码即可将embedding模型的权重下载到本地,以供调用。
from modelscope import snapshot_downloadmodel_dir = snapshot_download(model_id='BAAI/bge-large-zh-v1.5',cache_dir=r'E:\project\agent_learn\RAG_LangChain\model_dir'
)
这里简单介绍下该embedding模型,BAAI/bge-large-zh-v1.5 是由北京智源人工智能研究院(BAAI)开发的中文文本嵌入模型,属于 BGE(BAAI General Embedding)系列模型之一。该模型专注于生成高质量的中文文本向量表示,适用于检索、聚类、语义匹配等自然语言处理任务。这个模型在中文语料库上的效果十分好,如果大家的主要业务是在英文文档领域,可以尝试国外的英文embedding模型,这里就不再详细介绍。
核心代码实现
下面是完整的实现代码:
from operator import itemgetter
from pathlib import Pathfrom langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough, RunnableParallel
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
from langchain_chroma import Chroma
import os
from dotenv import load_dotenv# 加载环境变量
load_dotenv() # 加载 .env 文件
api_key = os.getenv("QWEN_API_KEY")# 1. 设置模型
# 使用通义千问模型,通过兼容OpenAI的接口调用
llm = ChatOpenAI(model="qwen-max-latest", api_key=api_key, base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)# 使用本地的BGE中文嵌入模型
embedding_model = HuggingFaceEmbeddings(model_name=r"E:\project\agent_learn\RAG_LangChain\model_dir\BAAI\bge-large-zh-v1___5"
)# 2. 设置数据处理(加载、分块、存储、检索)
file_dir = Path('my_knowledge')
# 滑动窗口分块,块大小500字符,重叠100字符
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)
# 使用Chroma作为向量数据库
vector_store = Chroma(embedding_function=embedding_model, persist_directory="./chroma_db")
# 创建检索器,每次检索5个最相关的片段
retriever = vector_store.as_retriever(search_kwargs={"k": 5})# 定义提示模板
prompt_template = PromptTemplate.from_template("""
请根据以下提供的上下文信息来回答问题。
如果上下文信息不足以回答问题,请直接说“根据提供的信息无法回答”。
如果回答时使用了上下文中的信息。在回答后输出使用了哪些上下文。
上下文信息:
{context}
-------------
问题:{question} """)# 3. 编排"链"
chain = ({ "question": RunnablePassthrough()}| RunnablePassthrough.assign(context=itemgetter("question") | retriever)| prompt_template| llm| StrOutputParser()
)if __name__ == '__main__':# 4. 初始化知识库(首次运行时取消注释)docs = DirectoryLoader(str(file_dir), loader_cls=TextLoader, loader_kwargs={"encoding": "utf-8"}).load() # 加载文档docs = text_splitter.split_documents(docs) # 切分文档vector_store.add_documents(docs) # 存储文档# 测试问题print(chain.invoke("韩立是谁"))
代码解析
1. 环境配置与依赖
代码中使用了python-dotenv
库来加载环境变量,将敏感的API密钥存储在.env
文件中,避免硬编码。需要安装的主要依赖包括:
- langchain及其相关组件
- HuggingFace相关库
- Chroma向量数据库
- 通义千问API访问密钥
2. 模型设置
这里有两个关键模型:
- 大语言模型LLM:使用通义千问的
qwen-max-latest
模型,通过兼容OpenAI的接口进行调用 - 嵌入(embedding)模型:使用本地部署的BGE中文嵌入模型,适合处理中文文本
3. 数据处理流程
- 文档加载:从
my_knowledge
目录加载文本文件 - 文档分块:使用
RecursiveCharacterTextSplitter
进行分块,采用滑动窗口策略,保留上下文关联 - 向量存储:使用Chroma作为向量数据库,存储文档向量
- 检索设置:配置检索器,每次返回最相关的5个文档片段
4. 提示模板设计
提示模板中特别强调了:
- 必须基于提供的上下文回答
- 信息不足时的处理方式
- 需要注明使用了哪些上下文
这种设计有助于提高回答的可追溯性和可靠性。
5. 链(Chain)的编排
LangChain的链机制将整个流程串联起来:
- 接收用户问题
- 根据问题检索相关上下文
- 将问题和上下文传入提示模板
- 调用大模型生成回答
- 解析输出结果
使用方法
- 准备
.env
文件,添加QWEN_API_KEY="你的通义千问API密钥"
- 在
my_knowledge
目录下放置相关文档 - 首次运行后,可以把 初始化知识库 注释掉,运行一次即可。
- 后续运行可直接调用
chain.invoke("你的问题")
获取回答
这个简单的RAG应用可以根据自己的需求进行扩展,比如添加更复杂的文档加载器、优化分块策略或增强提示工程等。