掘金 人工智能 11小时前
9_LangChain基于RAG实现文档问答
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

RAG(检索增强生成)技术,如同为AI配备智能“小抄”,使其能够超越预训练知识的限制,查阅外部文档并基于专业信息生成回答。本文深入浅出地解析了RAG的工作原理,包括索引阶段(文档加载、文本分割、向量化存储)和检索生成阶段(问题向量化、相似性检索、信息组合与回答生成)。通过LangChain和Streamlit的实战代码,演示了如何构建一个支持文本文件上传的文档问答助手,并提供了代码解析及进阶优化建议。RAG技术赋能AI在特定领域提供精准、实用的答案,是构建智能应用的重要基石。

✨ RAG技术的核心在于“检索增强生成”,它弥补了大语言模型知识“截止日期”的不足,使其能够访问和利用外部文档中的最新或专业信息,从而实现更精准、更实用的回答。

📚 RAG系统的构建涉及两个关键阶段:一是索引阶段,即预先将文档内容进行加载、分割成小块,并使用嵌入模型将其转换为向量存储于向量数据库,为后续快速检索奠定基础;二是检索与生成阶段,当用户提问时,系统将问题向量化,在数据库中查找最相关的文本块,并结合问题与检索内容,由大语言模型生成最终答案。

🚀 在LangChain和Streamlit的加持下,构建文档问答应用变得高效便捷。通过`RecursiveCharacterTextSplitter`进行文本分割,利用`OpenAIEmbeddings`和`FAISS`创建向量存储,再结合`create_retriever_tool`和`create_react_agent`,可以快速实现一个支持文件上传和智能问答的交互式Web应用。

💡 进阶优化方向包括支持更多文件格式(如PDF、Word)、增强对话记忆能力、实现多文档管理以及采用更高级的检索方法(如混合搜索)来提升整体应用的用户体验和信息检索的准确性。

什么是RAG?

RAG(检索增强生成)是一种让AI更聪明的技术,就像给AI配备了一个智能"小抄"。

想象一下:普通的大语言模型(如ChatGPT)只知道它训练时学到的知识,而且这些知识有"截止日期"。如果你想让AI回答关于你公司内部文档、最新研究报告或个人笔记的问题,普通AI就无能为力了。

这时RAG就派上用场了:它能让AI在回答问题前先"查阅资料",就像学生做开卷考试一样。AI会从你提供的文档中找出相关信息,然后基于这些信息生成答案。

简单来说,RAG = 检索(Retrieval) + 生成(Generation),它让AI变得更加实用,能够利用你提供的专业知识来回答问题。

RAG的工作原理

RAG系统的工作方式就像一个高效的图书馆助手,主要分为两大步骤:

1. 索引阶段(准备知识库)

这个阶段就像是整理一个智能图书馆,通常在系统启动前就完成:

2. 检索和生成阶段(回答问题)

当用户提问时,系统会:

文档问答应用实现流程

让我们用生活化的语言来解释如何构建一个文档问答应用:

    上传文档:用户通过网页上传一个或多个文档(比如PDF、TXT文件等)接收并存储:服务器接收这些文档并暂时保存读取文档:程序打开并读取文档内容切块处理:把文档内容分成小块(就像把一本书分成多个段落)创建向量索引:把每个文本块转换为向量并存入数据库准备回答问题:此时系统已经"学习"了文档内容,准备好回答问题用户提问:用户输入与文档相关的问题智能回答:系统找出相关文本块,让AI生成回答

代码实现

下面我们将使用LangChain和Streamlit构建一个简单的文档问答应用。这个应用允许用户上传文本文件,然后向其提问。

1. 安装必要的库

首先,我们需要安装所需的Python库:

pip install langchain langchain-openai streamlit faiss-cpu

2. 创建Streamlit应用

创建一个名为app.py的文件,并添加以下代码:

import osimport tempfileimport streamlit as stfrom langchain_openai import OpenAIEmbeddings, ChatOpenAIfrom langchain_community.vectorstores import FAISSfrom langchain_text_splitters import RecursiveCharacterTextSplitterfrom langchain.tools.retriever import create_retriever_toolfrom langchain.agents import AgentExecutor, create_react_agentfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.messages import AIMessage, HumanMessagefrom langchain.callbacks.streamlit import StreamlitCallbackHandler# 设置页面标题st.set_page_config(page_title="文档问答助手", page_icon="📚")st.title("📚 文档问答助手")# 设置OpenAI API密钥os.environ["OPENAI_API_KEY"] = st.sidebar.text_input("OpenAI API Key", type="password")# 初始化会话状态if "retriever" not in st.session_state:    st.session_state.retriever = Noneif "chat_history" not in st.session_state:    st.session_state.chat_history = []# 文件上传区域uploaded_file = st.sidebar.file_uploader("上传文档", type=["txt"])# 处理文件上传if uploaded_file and st.session_state.retriever is None:    with st.spinner("正在处理文档..."):        # 创建临时文件        with tempfile.NamedTemporaryFile(delete=False) as tmp_file:            tmp_file.write(uploaded_file.getvalue())            tmp_file_path = tmp_file.name                # 读取文件内容        with open(tmp_file_path, 'r', encoding='utf-8') as f:            text = f.read()                # 删除临时文件        os.unlink(tmp_file_path)                # 文本分割        text_splitter = RecursiveCharacterTextSplitter(            chunk_size=1000,  # 每块文本的大小            chunk_overlap=100,  # 块之间的重叠部分            separators=["\n\n", "\n", "。", "!", "?", ".", " ", ""],  # 分割符号        )        chunks = text_splitter.split_text(text)                # 创建向量存储        embeddings = OpenAIEmbeddings()        vectorstore = FAISS.from_texts(chunks, embeddings)                # 创建检索器        st.session_state.retriever = vectorstore.as_retriever(            search_type="similarity",  # 相似度搜索            search_kwargs={"k": 3}  # 返回前3个最相关的结果        )                st.sidebar.success(f"文档处理完成!共分割为{len(chunks)}个文本块")# 如果检索器已创建,显示聊天界面if st.session_state.retriever is not None:    # 创建检索工具    retriever_tool = create_retriever_tool(        st.session_state.retriever,        "document_search",        "在文档中搜索信息,用于回答关于文档内容的问题。"    )        # 创建语言模型    llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)        # 创建提示模板    prompt = ChatPromptTemplate.from_messages([        ("system", """你是一个专业的文档助手,可以回答用户关于文档内容的问题。        使用提供的工具来搜索文档并回答问题。        如果你不知道答案,请诚实地说你不知道,不要编造信息。        始终使用中文回答问题。        """),        ("human", "{input}")    ])        # 创建React代理    agent = create_react_agent(llm, [retriever_tool], prompt)    agent_executor = AgentExecutor.from_agent_and_tools(        agent=agent,        tools=[retriever_tool],        verbose=True,        handle_parsing_errors=True    )        # 显示聊天历史    for message in st.session_state.chat_history:        if isinstance(message, HumanMessage):            with st.chat_message("user"):                st.write(message.content)        else:            with st.chat_message("assistant"):                st.write(message.content)        # 获取用户输入    user_input = st.chat_input("请输入您的问题...")        # 处理用户输入    if user_input:        # 显示用户问题        with st.chat_message("user"):            st.write(user_input)                # 添加到聊天历史        st.session_state.chat_history.append(HumanMessage(content=user_input))                # 显示AI思考过程        with st.chat_message("assistant"):            st_callback = StreamlitCallbackHandler(st.container())            response = agent_executor.invoke(                {"input": user_input},                {"callbacks": [st_callback]}            )            answer = response["output"]            st.write(answer)                # 添加到聊天历史        st.session_state.chat_history.append(AIMessage(content=answer))else:    # 如果还没上传文件,显示说明    st.info("👈 请先上传一个文本文件")

3. 运行应用

在命令行中运行以下命令启动应用:

streamlit run app.py

4. 使用应用

    在侧边栏输入你的OpenAI API密钥上传一个文本文件(比如公司手册、研究论文等)等待文件处理完成在聊天框中输入与文档相关的问题观察AI如何回答你的问题

代码解析

让我们来解释上面代码的关键部分:

文档处理流程

# 文本分割text_splitter = RecursiveCharacterTextSplitter(    chunk_size=1000,  # 每块文本的大小    chunk_overlap=100,  # 块之间的重叠部分    separators=["\n\n", "\n", "。", "!", "?", ".", " ", ""],  # 分割符号)chunks = text_splitter.split_text(text)

这段代码将长文本分割成小块,每块约1000个字符,相邻块之间重叠100个字符(避免切割导致的信息丢失)。分割时优先按照段落、句子等自然边界进行。

# 创建向量存储embeddings = OpenAIEmbeddings()vectorstore = FAISS.from_texts(chunks, embeddings)

这里使用OpenAI的嵌入模型将文本块转换为向量,并存储在FAISS向量数据库中。FAISS是一个高效的向量搜索库,专为相似性搜索而设计。

检索工具创建

retriever_tool = create_retriever_tool(    st.session_state.retriever,    "document_search",    "在文档中搜索信息,用于回答关于文档内容的问题。")

这段代码创建了一个检索工具,它可以被代理用来搜索文档。工具名称为"document_search",描述告诉AI这个工具的用途。

React代理创建

agent = create_react_agent(llm, [retriever_tool], prompt)agent_executor = AgentExecutor.from_agent_and_tools(    agent=agent,    tools=[retriever_tool],    verbose=True,    handle_parsing_errors=True)

这里创建了一个React代理,它使用ReAct(Reasoning and Acting)方法,能够在回答问题前先思考应该采取什么行动。verbose=True让我们能看到代理的思考过程,handle_parsing_errors=True使代理能够处理解析错误。

进阶优化建议

    支持更多文件类型:扩展应用以支持PDF、Word、Excel等更多文件格式记忆对话历史:让AI记住之前的对话,能够进行连续对话多文档管理:允许用户上传多个文档并在它们之间切换高级检索方法:实现混合搜索或重排序,提高检索质量自定义模型选择:让用户选择不同的语言模型和嵌入模型

总结

RAG技术让我们能够构建"有记忆"的AI应用,它可以基于特定文档回答问题,而不仅仅依赖于预训练知识。这对于构建企业知识库、个人助手、研究工具等应用非常有价值。

通过LangChain,我们可以轻松实现RAG系统的各个组件:文档加载、文本分割、向量存储、检索和生成。而Streamlit则提供了一个简单的方式来创建交互式Web界面。

希望这个教程能帮助你理解RAG的工作原理,并开始构建自己的文档问答应用!

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

RAG 检索增强生成 LangChain Streamlit AI问答
相关文章