langchain+通义千问,实现简单地RAG应用
本文介绍了一个简单的RAG应用实现方案,使用LangChain框架、DashScope嵌入模型和Chroma数据库。首先准备PDF/Markdown文档,通过PyMuPDFLoader/UnstructuredMarkdownLoader加载文本,使用RecursiveCharacterTextSplitter分块处理。由于嵌入模型限制,采用分批入库方式。最后演示了文档检索功能,输入问题可返回3个
·
说在前面
大模型应用,尤其是RAG技术十分火热,通过实现一个简单的RAG应用,可以帮助我们更好的理解这门技术,也能更好的理解使用过程中可能得一些局限性,目前实现了一个最基础的版本:
读取本地文件,入库,然后检索。
技术选型
开发框架:langchain
嵌入模型:text-embedding-v4
数据库chroma
准备
申请百炼大模型的api-key,新用户一般都会赠送一些的,足够日常测试用了
准备几个需要向量化的文档,比如markdown,pdf,不要是扫描件,需要可复制的那种。
代码
说几个注意的点:
TONGYI_API_KEY是要定义在.env文件中的embedding模型,langchain对阿里社区支持还是不错的,如果选择其他不支持的模型,需要自己实现一些关键的方法- 源文件的路径和持久化的路径需要按照实际修改
- 之所以定义
batch_size并使用for循环进行入库,是因为嵌入模型最多支持10行
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyMuPDFLoader
from langchain_community.document_loaders import UnstructuredMarkdownLoader
import os
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
def main():
# 获取folder_path下所有文件路径,储存在file_paths里
file_paths = []
folder_path = '../../data_base/knowledge_db'
for root, dirs, files in os.walk(folder_path):
for file in files:
file_path = os.path.join(root, file)
file_paths.append(file_path)
print(file_paths[:3])
# 遍历文件路径并把实例化的loader存放在loaders里
loaders = []
texts = []
os.environ["DASHSCOPE_API_KEY"] = os.environ["TONGYI_API_KEY"]
embedding = DashScopeEmbeddings(
model="text-embedding-v4"
)
for file_path in file_paths:
file_type = file_path.split('.')[-1]
if file_type == 'pdf':
loaders.append(PyMuPDFLoader(file_path))
elif file_type == 'md':
loaders.append(UnstructuredMarkdownLoader(file_path))
for loader in loaders: texts.extend(loader.load())
text = texts[1]
print(f"每一个元素的类型:{type(text)}.", #<class 'langchain_core.documents.base.Document'>
f"该文档的描述性数据:{text.metadata}", # {'source': '../../data_base/knowledge_db\\prompt_engineering\\3. 迭代优化 Iterative.md'}
f"查看该文档的内容:\n{text.page_content[0:]}",
sep="\n------\n")
# 切分文档,每个块大小为 500 个字符,重叠部分为 50 个字符。
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=50)
split_docs = text_splitter.split_documents(texts)
# 定义持久化路径
persist_directory = '../../data_base/vector_db/chroma'
from langchain_community.vectorstores import Chroma
# 分批处理文档
batch_size = 10
for i in range(0, len(split_docs), batch_size):
batch_docs = split_docs[i:i+batch_size]
if i == 0:
# 第一批文档创建数据库
vectordb = Chroma.from_documents(
documents=batch_docs,
embedding=embedding,
persist_directory=persist_directory
)
else:
# 后续批次添加到数据库
vectordb.add_documents(batch_docs)
if __name__ == "__main__":
main()
测试
from langchain_community.embeddings import DashScopeEmbeddings
from dotenv import find_dotenv, load_dotenv
from langchain_chroma import Chroma
import os
_ = load_dotenv(find_dotenv())
# 1. 设置你的API Key(环境变量方式更安全)
os.environ["DASHSCOPE_API_KEY"] = os.environ["TONGYI_API_KEY"]
def main():
embedding = DashScopeEmbeddings(
model="text-embedding-v4"
)
# 向量数据库持久化路径
persist_directory = '../../data_base/vector_db/chroma'
# 加载数据库
vectordb = Chroma(
persist_directory=persist_directory,
embedding_function=embedding
)
question="提供几个设计 Prompt 的技巧"
sim_docs = vectordb.similarity_search(question,k=3)
print(f"检索到的内容数:{len(sim_docs)}")
if __name__ == "__main__":
main()
通过打印的内容,可以发现已经将三个最相关的片段检索出来了。
说到最后
以上。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)