Project Icon

local-rag-example

结合Langchain和Streamlit技术构建本地化聊天式PDF应用

优化描述,以如何在本地机器上快速建立和运行ChatPDF为核心,突出其隐私保护和成本效益的特点。进一步细化技术栈的用途,即Langchain、Ollama和Streamlit如何具体提升操作效率和用户界面体验。

local-rag-example

构建自己的ChatPDF并在本地运行

依赖项:

  • langchain
  • streamlit
  • streamlit-chat
  • pypdf
  • chromadb
  • fastembed
pip install langchain streamlit streamlit_chat chromadb pypdf fastembed

博客文章:https://blog.duy-huynh.com/build-your-own-rag-and-run-them-locally/

如何构建自己的RAG并在本地运行:Langchain + Ollama + Streamlit教程

随着大型语言模型(LLM)的兴起及其令人印象深刻的能力,许多有趣的应用程序建立在像OpenAI和Anthropic这样的巨型LLM供应商的基础上。这些应用程序背后的神话是RAG框架,以下文章对其进行了详细解释:

为了熟悉RAG,我建议通读这些文章。然而,这篇帖子将跳过基础知识,直接指导你如何构建可以在本地笔记本电脑上运行的RAG应用程序,不用担心数据隐私和令牌成本。

我们将构建一个类似ChatPDF但更简单的应用程序,用户可以上传PDF文档并通过一个简单的用户界面进行提问。我们的技术栈非常简单,包括Langchain,Ollama和Streamlit。

  • LLM服务器:这个应用程序最关键的组件是LLM服务器。感谢Ollama,我们有一个可以在本地甚至笔记本电脑上设置的强大LLM服务器。虽然llama.cpp也是一个选择,但我发现Ollama用Go语言编写,更容易设置和运行。

  • RAG:毫无疑问,LLM领域的两大主流库是LangchainLLamIndex。对于这个项目,我会使用Langchain,因为我从我的专业经验中熟悉它。任何RAG框架的重要组件是向量存储。我们将在这里使用Chroma,因为它与Langchain集成良好。

  • 聊天UI:用户界面也是一个重要组件。尽管有许多可用的技术,但我更喜欢使用Streamlit,一个Python库,让人心安。

好的,让我们开始设置。


设置Ollama

如上所述,设置和运行Ollama非常简单。首先,访问ollama.ai并下载适用于您的操作系统的应用程序。

接下来,打开终端,执行以下命令以拉取最新的Mistral-7B。虽然有许多其他的LLM模型可用,但我选择Mistral-7B因为它体积小和质量具有竞争力。

ollama pull mistral

构建RAG流水线

我们进程的第二步是构建RAG流水线。鉴于我们的应用程序简单,我们主要需要两个方法:ingestask

ingest方法接受文件路径并将其加载到向量存储中,分两步完成:首先,它将文档分割成较小的块,以适应LLM的令牌限制;其次,它使用Qdrant FastEmbeddings对这些块进行向量化,并将它们存储到Chroma中。

ask方法处理用户查询。用户可以提出问题,然后RetrievalQAChain使用向量相似性搜索技术检索相关上下文(文档块)。

有了用户的问题和检索到的上下文,我们可以组成一个提示并向LLM服务器请求预测。

from langchain_community.vectorstores import Chroma
from langchain_community.chat_models import ChatOllama
from langchain_community.embeddings import FastEmbedEmbeddings
from langchain.schema.output_parser import StrOutputParser
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.schema.runnable import RunnablePassthrough
from langchain.prompts import PromptTemplate
from langchain.vectorstores.utils import filter_complex_metadata

class ChatPDF:
    vector_store = None
    retriever = None
    chain = None

    def __init__(self):
        self.model = ChatOllama(model="mistral")
        self.text_splitter = RecursiveCharacterTextSplitter(chunk_size=1024, chunk_overlap=100)
        self.prompt = PromptTemplate.from_template(
            """
            <s> [INST] 你是一个回答问答任务的助手。使用以下检索到的上下文片段来回答问题。
            如果你不知道答案,只需说你不知道。用三句话最多,并保持答案简洁。 [/INST] </s> 
            [INST] 问题:{question} 
            上下文:{context} 
            答案: [/INST]
            """
        )

    def ingest(self, pdf_file_path: str):
        docs = PyPDFLoader(file_path=pdf_file_path).load()
        chunks = self.text_splitter.split_documents(docs)
        chunks = filter_complex_metadata(chunks)

        vector_store = Chroma.from_documents(documents=chunks, embedding=FastEmbedEmbeddings())
        self.retriever = vector_store.as_retriever(
            search_type="similarity_score_threshold",
            search_kwargs={
                "k": 3,
                "score_threshold": 0.5,
            },
        )

        self.chain = ({"context": self.retriever, "question": RunnablePassthrough()}
                      | self.prompt
                      | self.model
                      | StrOutputParser())

    def ask(self, query: str):
        if not self.chain:
            return "请首先添加一个PDF文档。"

        return self.chain.invoke(query)

    def clear(self):
        self.vector_store = None
        self.retriever = None
        self.chain = None

该提示源自Langchain hub:Langchain RAG Prompt for Mistral。该提示已被测试并下载了数千次,作为了解LLM提示技术的可靠资源。

你可以在这里了解更多关于LLM提示技术的内容。

实现的更多细节:

ingest:我们使用PyPDFLoader加载用户上传的PDF文件。Langchain提供的RecursiveCharacterSplitter将PDF分割成较小的块。重要的是,使用Langchain的filter_complex_metadata函数过滤掉ChromaDB不支持的复杂元数据。

对于向量存储,我们使用Chroma,并与Qdrant FastEmbed作为我们的嵌入模型结合使用。这种轻量级模型然后被转换为具有0.5评分阈值和k=3的检索器,这意味着它返回评分最高的3个块。最后,我们使用LECL构建一个简单的对话链。

ask:该方法只需将用户的问题传递到我们预定义的链中,然后返回结果。

clear:当上传新的PDF文件时,该方法用于清除之前的聊天会话和存储。

草拟一个简单的UI

为了实现简单的用户界面(UI),我们将使用Streamlit,一个为快速原型设计AI/ML应用程序而设计的UI框架。

import os
import tempfile
import streamlit as st
from streamlit_chat import message
from rag import ChatPDF

st.set_page_config(page_title="ChatPDF")

def display_messages():
    st.subheader("聊天")
    for i, (msg, is_user) in enumerate(st.session_state["messages"]):
        message(msg, is_user=is_user, key=str(i))
    st.session_state["thinking_spinner"] = st.empty()

def process_input():
    if st.session_state["user_input"] and len(st.session_state["user_input"].strip()) > 0:
        user_text = st.session_state["user_input"].strip()
        with st.session_state["thinking_spinner"], st.spinner(f"思考中"):
            agent_text = st.session_state["assistant"].ask(user_text)

        st.session_state["messages"].append((user_text, True))
        st.session_state["messages"].append((agent_text, False))

def read_and_save_file():
    st.session_state["assistant"].clear()
    st.session_state["messages"] = []
    st.session_state["user_input"] = ""

    for file in st.session_state["file_uploader"]:
        with tempfile.NamedTemporaryFile(delete=False) as tf:
            tf.write(file.getbuffer())
            file_path = tf.name

        with st.session_state["ingestion_spinner"], st.spinner(f"提取 {file.name}"):
            st.session_state["assistant"].ingest(file_path)
        os.remove(file_path)

def page():
    if len(st.session_state) == 0:
        st.session_state["messages"] = []
        st.session_state["assistant"] = ChatPDF()

    st.header("ChatPDF")

    st.subheader("上传文档")
    st.file_uploader(
        "上传文档",
        type=["pdf"],
        key="file_uploader",
        on_change=read_and_save_file,
        label_visibility="collapsed",
        accept_multiple_files=True,
    )

    st.session_state["ingestion_spinner"] = st.empty()

    display_messages()
    st.text_input("信息", key="user_input", on_change=process_input)

if __name__ == "__main__":
    page()

运行此代码使用命令streamlit run app.py,看看它的外观。

好了,就是这样!我们现在有了一个在你的笔记本电脑上完全运行的ChatPDF应用程序。由于这篇帖子主要集中在提供一个如何构建自己RAG应用程序的概述,有几个方面需要微调。你可以考虑以下建议来增强你的应用程序并进一步发展你的技能:

  • 为对话链添加记忆:目前,它不记得对话流程。添加临时记忆将帮助你的助手了解上下文。

  • 允许多文件上传:一次聊天一个文档是可以的。但想象一下,如果我们可以聊天多个文档——你可以把整本书籍放进去。那会非常酷!

  • 使用其他LLM模型:虽然Mistral是有效的,但有许多其他替代方案。你可能会找到一个更适合你需求的模型,比如LlamaCode对于开发者。然而,记住模型的选择取决于你的硬件,特别是你有多少RAM💵。

  • 增强RAG流水线:在RAG内部有很大的实验空间。你可能需要更改检索度量标准、嵌入模型……或者添加像重新排序器这样的层来提高结果。

完整源代码:https://github.com/vndee/local-rag-example

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号