首页 > 其他分享 >【RAG 项目实战 07】替换 ConversationalRetrievalChain(单轮问答)

【RAG 项目实战 07】替换 ConversationalRetrievalChain(单轮问答)

时间:2024-11-26 20:13:23浏览次数:6  
标签:rag ConversationalRetrievalChain chain RAG text cl content 07

【RAG 项目实战 07】替换 ConversationalRetrievalChain(单轮问答)


NLP Github 项目:


一、RAG 整体流程

检索式问答的系统流程图:

二、RAG 核心模块

2.1 环境配置

# @Author:青松  
# 公众号:FasterAI  
# Python, version 3.10.14  
# Pytorch, version 2.3.0  
# Chainlit, version 1.1.301

2.2 分割文本块并对每一个块建索引

# 配置文件分割器,每个块1000个token,重复100个
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)

# 将文件分割成文本块
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
)

# 将 Chroma 向量数据库转化为检索器
retriever = vectorstore.as_retriever()

2.3 构建 RAG 链

# RAG_Prompt:根据参考内容回答用户问题
rag_template = "你是一个专门处理问答任务的智能助理。请使用给定的参考内容来回答用户的问题,如果你不知道答案,就说你不知道,不要试图编造答案。" \
			   "\n\n用户问题: {question} \n参考内容: {context} \n答案:"

rag_prompt = PromptTemplate.from_template(rag_template)

# RAG链:根据问题和参考内容生成答案
rag_chain = (
		{"context": retriever | format_docs, "question": RunnablePassthrough()}
		| rag_prompt
		| llm
		| StrOutputParser()
)

2.4 检索生成

rag_chain = cl.user_session.get("rag_chain")

# 使用RAG链处理用户问题
response = rag_chain.invoke(
	message.content,
	config=RunnableConfig(callbacks=[cl.LangchainCallbackHandler()]),
)

# 大模型的回答
await cl.Message(content=response).send()

三、RAG 效果展示

启动程序:

chainlit run rag_app.py -w

系统截图:

  • 问题一:对第一个问题大模型可以根据文档内容生成答案。
  • 问题二:对第一个问题大模型未能结合聊天历史进行RAG。

四、RAG 完整代码

# @Author:青松
# 公众号:FasterAI
# Python, version 3.10.14
# Pytorch, version 2.3.0
# Chainlit, version 1.1.301

import chainlit as cl
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceBgeEmbeddings
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnableConfig, RunnablePassthrough

import llm_util
from common import Constants

# 获取大模型实例
llm = llm_util.get_llm(Constants.MODEL_NAME['QianFan'])

# 获取文本嵌入模型
model_name = "BAAI/bge-small-zh"
# 对模型生成的嵌入进行归一化处理,将它们缩放到具有单位范数(长度为1)的尺度
encode_kwargs = {"normalize_embeddings": True}
embeddings_model = HuggingFaceBgeEmbeddings(
    model_name=model_name, encode_kwargs=encode_kwargs
)


@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()

    # 配置文件分割器,每个块1000个token,重复100个
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)

    # 将文件分割成文本块
    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
    )

    # 将 Chroma 向量数据库转化为检索器
    retriever = vectorstore.as_retriever()
    cl.user_session.set("retriever", retriever)

    # RAG_Prompt:根据参考内容回答用户问题
    rag_template = "你是一个专门处理问答任务的智能助理。请使用给定的参考内容来回答用户的问题,如果你不知道答案,就说你不知道,不要试图编造答案。" \
                   "\n\n用户问题: {question} \n参考内容: {context} \n答案:"

    rag_prompt = PromptTemplate.from_template(rag_template)

    # RAG链:根据问题和参考内容生成答案
    rag_chain = (
            {"context": retriever | format_docs, "question": RunnablePassthrough()}
            | rag_prompt
            | llm
            | StrOutputParser()
    )

    cl.user_session.set("rag_chain", rag_chain)

    # 通知用户文件已处理完成,更新当前窗口的内容
    msg.content = f"Processing `{file.name}` done. You can now ask questions!"
    await msg.update()


@cl.on_message
async def on_message(message: cl.Message):
    """ 监听用户消息事件 """

    rag_chain = cl.user_session.get("rag_chain")

    # 使用RAG链处理用户问题
    response = rag_chain.invoke(
        message.content,
        config=RunnableConfig(callbacks=[cl.LangchainCallbackHandler()]),
    )

    # 大模型的回答
    await cl.Message(content=response).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()


def format_docs(docs):
    """ 拼接检索到的文本块 """
    return "\n\n".join(doc.page_content for doc in docs)

【动手学 RAG】系列文章:


【动手部署大模型】系列文章:

本文由mdnice多平台发布

标签:rag,ConversationalRetrievalChain,chain,RAG,text,cl,content,07
From: https://www.cnblogs.com/fasterai/p/18570876

相关文章

  • 03-07、SpringCloud第七章,升级篇,服务注册与发现Eureka、Zookeeper和Consule
    SpringCloud第七章,升级篇,服务注册与发现Eureka、Zookeeper和Consule一、基础概念1、服务治理传统的远程RPC远程调用框架中,管理每个服务与服务之间的依赖关系比较复杂。所以需要使用服务治理,用于管理服务与服务之间的依赖关系,可以实现服务调用、负载均衡、容错等。实现服......
  • HyDE 如何改进了传统的 RAG 方法?
    HyDE的方法就是让AI先自己猜一个答案,然后用这个猜测去寻找相关的真实信息,最后结合起来,给出一个更准确、更有参考依据的回答。一、什么是RAG?RAG(Retrieval-AugmentedGeneration)是指"检索增强生成"。这是一种让AI模型在回答问题时,不仅依赖自身的知识,还从一个数据库(比如文档库、知......
  • AttributeError: module ‘backend_interagg‘ has no attribute ‘FigureCanvas‘.
    plt.figure(figsize=(12,6))File"D:\anaconda\Lib\site-packages\matplotlib\pyplot.py",line1027,infiguremanager=new_figure_manager(^^^^^^^^^^^^^^^^^^^File"D:\anaconda\Lib\site-packages\matplotlib\pyplot.py",line549......
  • HCIA-07 OSPF基础
    目录1-OSPF协议概述1.1LAS1.2LSDB1.3SPF计算1.4路由表生成1.5OSPF简介1.6OSPF在园区网络中的应用1.7OSPF基础术语:区域、Router、度量值1.8OSPF五种协议报文类型1.9OSPF三大表项:邻居表、LSDB表、OSPF表2-OSPF工作原理2.1OSPF邻接关系建立过程2.2OSPF网络类......
  • 部署local-path-storage
    环境:os:Centos7k8s:1个master2个nodes以下操作都是在master节点上完成1.下载配置文件cd/softwgethttps://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.30/deploy/local-path-storage.yaml 2.修改镜像文件local-path-storage.yaml因为无法访问国外的......
  • Cesium教程07_entity进阶
    基于Cesium和Vue的卫星轨道可视化本文介绍了如何使用Cesium和Vue构建一个动态卫星轨道可视化应用。该示例模拟了一个卫星围绕地球轨道运动的场景,并实现了实时的轨迹渲染、卫星扫描范围展示以及摄像头跟随功能。目录项目背景功能展示代码实现模板部分脚本部分样......
  • 707. 设计链表
    题目这题卡哥的讲解视频特别好,涵盖了很多细节。自己跟着卡哥代码敲了一遍。单链表:classMyLinkedList{public:structLinkedNode{intval;LinkedNode*next;LinkedNode(intval):val(val),next(nullptr){}};MyLinkedList()......
  • 请描述一下cookies、sessionStorage和localStorage的区别?
    在前端开发中,cookies、sessionStorage和localStorage都是用于在浏览器中存储数据的机制,但它们之间存在显著的区别:1.数据的生命周期:Cookies:Cookie的生命周期可以通过expires或max-age属性设置。如果没有设置过期时间,Cookie会在浏览器会话结束时(关闭浏览器)被删除,这......
  • 2024-2025-1 20241307《计算机基础与程序设计》第九周学习总结
    作业信息这个作业属于哪个课程(2024-2025-1-计算机基础与程序设计)这个作业要求在哪里(2024-2025-1计算机基础与程序设计第九周作业)这个作业的目标作业正文(2024-2025-1学号20241307《计算机基础与程序设计》第九周学习总结)教材学习内容总结《计算机科学概......
  • RAG应用
    为了使计算机能够理解和处理非结构化数据(如文本,图片,视频),通常使用嵌入模型(Embedding)将非结构化数据编码为向量[6]。可以理解为,向量就是非结构化数据的压缩。因此,在对非结构化数据进行相似性搜索、最近邻搜索(NNS,NearestNeighborSearch)时,可以使用向量的近似度来表征非结构化......