【RAG 项目实战 06】使用 LangChain 结合 Chainlit 实现文档问答
【RAG 项目实战 06】使用 LangChain 结合 Chainlit 实现文档问答
NLP Github 项目:
-
NLP 项目实践:fasterai/nlp-project-practice
介绍:该仓库围绕着 NLP 任务模型的设计、训练、优化、部署和应用,分享大模型算法工程师的日常工作和实战经验
-
AI 藏经阁:https://gitee.com/fasterai/ai-e-book
介绍:该仓库主要分享了数百本 AI 领域电子书
-
AI 算法面经:fasterai/nlp-interview-handbook#面经
介绍:该仓库一网打尽互联网大厂NLP算法面经,算法求职必备神器
-
NLP 剑指Offer:https://gitee.com/fasterai/nlp-interview-handbook
介绍:该仓库汇总了 NLP 算法工程师高频面题
[!NOTE] 问题汇总
- 如何添加rag-demo能力
- 如何将rag-demo的单轮问答转化为多轮问答
- 如何改造rag-demo的提示词:将 StringPrompt 转化为 ChatPrompt
- 如何拼接和组合不同的Prompt
- 如何修改Hub中的Prompt
一、文档问答流程
检索式问答的功能示意图:
检索式问答的系统流程图:
二、文档问答系统的核心模块
2.1 环境配置
# @Author:青松
# 公众号:FasterAI
# Python, version 3.10.14
# Pytorch, version 2.3.0
# Chainlit, version 1.1.301
2.2 文档分块
使用文档分割器 RecursiveCharacterTextSplitter
将用户上传的文件分割文本块
# 配置文件分割器,每个块1000个token,重复100个
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
files = None
# 等待用户上传文件
while files is None:
files = await cl.AskFileMessage(
content="Please upload a text file to begin!",
accept=["text/plain"],
max_size_mb=20,
timeout=180,
).send()
file = files[0]
# 发送处理文件的消息
msg = cl.Message(content=f"Processing `{file.name}`...", disable_feedback=True)
await msg.send()
with open(file.path, "r", encoding="utf-8") as f:
text = f.read()
# 将文件分割成文本块
texts = text_splitter.split_text(text)
2.3 建立索引
# 将文件分割成文本块
texts = text_splitter.split_text(text)
# 为每个文本块添加元数据信息
metadatas = [{"source": f"{i}-pl"} for i in range(len(texts))]
# 使用异步方式创建 Chroma 向量数据库
vectorstore = await cl.make_async(Chroma.from_texts)(
texts, embeddings_model, metadatas=metadatas
)
2.4 创建RAG链
# 创建会话历史记录
message_history = ChatMessageHistory()
# 使用 ConversationBufferMemory 记忆组件存储历史记录
memory = ConversationBufferMemory(
memory_key="chat_history",
output_key="answer",
chat_memory=message_history,
return_messages=True,
)
# todo:即将弃用,使用 create_history_aware_retriever 结合 create_retrieval_chain 替换
# 使用 Chroma vector store 创建一个检索链
chain = ConversationalRetrievalChain.from_llm(
llm,
chain_type="stuff",
retriever=vectorstore.as_retriever(),
memory=memory,
return_source_documents=True,
)
cl.user_session.set("chain", chain)
2.5 检索生成
@cl.on_message
async def on_message(message: cl.Message):
""" 监听用户消息事件 """
chain = cl.user_session.get("chain") # type: ConversationalRetrievalChain
cb = cl.AsyncLangchainCallbackHandler()
# todo 即将弃用,需要替换
res = await chain.acall(message.content, callbacks=[cb])
# 大模型检索生成的答案
answer = res["answer"]
await cl.Message(content=answer).send()
三、效果展示
启动程序:
chainlit run rag_app.py -w
系统截图:
四、完整代码
# @Author:青松
# 公众号:FasterAI
# Python, version 3.10.14
# Pytorch, version 2.3.0
# Chainlit, version 1.1.301
import chainlit as cl
from langchain.chains import ConversationalRetrievalChain
from langchain.memory import ChatMessageHistory, ConversationBufferMemory
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceBgeEmbeddings
import llm_util
from common import Constants
# 获取大模型实例
llm = llm_util.get_llm(Constants.MODEL_NAME['QianFan'])
# 获取文本嵌入模型
model_name = "BAAI/bge-small-zh-v1.5"
encode_kwargs = {"normalize_embeddings": True}
embeddings_model = HuggingFaceBgeEmbeddings(
model_name=model_name, encode_kwargs=encode_kwargs
)
# 配置文件分割器,每个块1000个token,重复100个
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
@cl.on_chat_start
async def on_chat_start():
""" 监听会话开始事件 """
await send_welcome_msg()
files = None
# 等待用户上传文件
while files is None:
files = await cl.AskFileMessage(
content="Please upload a text file to begin!",
accept=["text/plain"],
max_size_mb=20,
timeout=180,
).send()
file = files[0]
# 发送处理文件的消息
msg = cl.Message(content=f"Processing `{file.name}`...", disable_feedback=True)
await msg.send()
with open(file.path, "r", encoding="utf-8") as f:
text = f.read()
# 将文件分割成文本块
texts = text_splitter.split_text(text)
# 为每个文本块添加元数据信息
metadatas = [{"source": f"{i}-pl"} for i in range(len(texts))]
# 使用异步方式创建 Chroma 向量数据库
vectorstore = await cl.make_async(Chroma.from_texts)(
texts, embeddings_model, metadatas=metadatas
)
# 创建会话历史记录
message_history = ChatMessageHistory()
# 使用 ConversationBufferMemory 记忆组件存储历史记录
memory = ConversationBufferMemory(
memory_key="chat_history",
output_key="answer",
chat_memory=message_history,
return_messages=True,
)
# todo:即将弃用,使用 create_history_aware_retriever 结合 create_retrieval_chain 替换
# 使用 Chroma vector store 创建一个检索链
chain = ConversationalRetrievalChain.from_llm(
llm,
chain_type="stuff",
retriever=vectorstore.as_retriever(),
memory=memory,
return_source_documents=True,
)
# 通知用户文件已处理完成,更新当前窗口的内容
msg.content = f"Processing `{file.name}` done. You can now ask questions!"
await msg.update()
cl.user_session.set("chain", chain)
@cl.on_message
async def on_message(message: cl.Message):
""" 监听用户消息事件 """
chain = cl.user_session.get("chain") # type: ConversationalRetrievalChain
cb = cl.AsyncLangchainCallbackHandler()
# todo 即将弃用
res = await chain.acall(message.content, callbacks=[cb])
# 大模型的回答
answer = res["answer"]
await cl.Message(content=answer).send()
async def send_welcome_msg():
image = cl.Image(url="https://qingsong-1257401904.cos.ap-nanjing.myqcloud.com/wecaht.png")
# 发送一个图片
await cl.Message(
content="**青松** 邀你关注 **FasterAI**, 让每个人的 AI 学习之路走的更容易些!立刻扫码开启 AI 学习、面试快车道 **(^_^)** ",
elements=[image],
).send()
@cl.password_auth_callback
def auth_callback(username: str, password: str):
""" 持久化客户端聊天历史代码,不需要请删除 """
if (username, password) == ("admin", "admin"):
return cl.User(
identifier="admin", metadata={"role": "admin", "provider": "credentials"}
)
else:
return None
【动手学 RAG】系列文章:
- 【RAG 项目实战 01】在 LangChain 中集成 Chainlit
- 【RAG 项目实战 02】Chainlit 持久化对话历史
- 【RAG 项目实战 03】优雅的管理环境变量
- 【RAG 项目实战 04】添加多轮对话能力
- 【RAG 项目实战 05】重构:封装代码
- 【RAG 项目实战 06】使用 LangChain 结合 Chainlit 实现文档问答
- 【RAG 项目实战 07】替换 ConversationalRetrievalChain(单轮问答)
- 【RAG 项目实战 08】为 RAG 添加历史对话能力
- More...
【动手部署大模型】系列文章:
- 【模型部署】vLLM 部署 Qwen2-VL 踩坑记 01 - 环境安装
- 【模型部署】vLLM 部署 Qwen2-VL 踩坑记 02 - 推理加速
- 【模型部署】vLLM 部署 Qwen2-VL 踩坑记 03 - 多图支持和输入格式问题
- More...
本文由mdnice多平台发布
标签:
自然语言处理
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂