引言
在现代问答应用中,提供连续的对话体验是至关重要的。这需要应用程序具备某种“记忆”功能,以便能够记住之前的提问和回答,并将其纳入当前的思考之中。本文将深入探讨如何在问答应用中实现这种功能,尤其着眼于会话型RAG(Retrieval-Augmented Generation)的方法。
主要内容
1. 什么是会话型RAG?
会话型RAG结合了检索增强生成(RAG)技术和对话记忆逻辑,能够根据上下文进行智能问答。它主要分为两种方法:
- 链式方法(Chains):每次执行查询时,始终进行检索步骤。
- 代理方法(Agents):让大语言模型(LLM)自主决定是否以及如何执行检索步骤。
2. 配置环境和依赖项
在本教程中,我们将使用OpenAI嵌入和Chroma向量存储。请确保安装以下Python包:
%%capture --no-stderr
%pip install --upgrade --quiet langchain langchain-community langchainhub langchain-chroma bs4
我们还需要设置OPENAI_API_KEY环境变量,可以直接输入或从.env文件加载。
3. 构建链式RAG
链式方法依赖聊天历史和检索器来生成答案。我们首先需要构建一个检索器,从外部知识源中获取信息。以下是使用OpenAI嵌入构建检索器的代码示例:
import bs4
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_chroma import Chroma
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 使用API代理服务提高访问稳定性
loader = WebBaseLoader(web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",))
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever()
4. 增强聊天历史逻辑
为了在会话中灵活理解上下文,我们需要更新提示并添加一个子链以将最新的问题与聊天历史结合。通过创建一个“历史感知”检索器,我们可以在检索步骤中加入对话背景。
5. 构建智能代理
代理方法通过利用LLM的推理能力来做出查询执行的决策。这种方法的优点在于允许代理在服务查询时执行多个检索步骤。
from langchain.tools.retriever import create_retriever_tool
from langgraph.prebuilt import create_react_agent
tool = create_retriever_tool(retriever, "blog_post_retriever", "检索博文内容")
agent_executor = create_react_agent(llm, [tool])
代码示例
下面是一个完整的代码示例,展示了如何将上述所有步骤整合在一起:
import bs4
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain.tools.retriever import create_retriever_tool
from langchain_chroma import Chroma
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.prebuilt import create_react_agent
# 初始化必要组件
memory = SqliteSaver.from_conn_string(":memory:")
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 构建检索器
loader = WebBaseLoader(web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",))
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever()
# 构建检索工具和代理
tool = create_retriever_tool(retriever, "blog_post_retriever", "检索博文内容")
agent_executor = create_react_agent(llm, [tool], checkpointer=memory)
常见问题和解决方案
-
检索不准确: 确保检索器配置正确,并选择合适的向量存储技术。
-
代理行为不可预测: 在设置代理时,可以通过调节模型配置参数来控制其输出的稳定性。
总结和进一步学习资源
会话型RAG提供了在问答应用中结合历史对话的强大功能。在实际应用中,开发者常常需要根据具体场景调整检索策略。
若想深入了解,可以查看以下资源:
参考资料
- Weng, L. (2023). LLM Powered Autonomous Agents.
- LangChain官方文档.
- OpenAI API参考手册.
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---