如何在聊天应用中添加对话历史记录:打造智能问答体验
引言
在许多问答应用中,我们希望允许用户进行来回对话,也就是说,应用程序需要某种“记忆”功能,以存储过去的问题和答案,并将其逻辑地整合到当前的思考中。在这篇文章中,我们将介绍如何为聊天应用添加对话历史逻辑,以实现更智能的互动体验。本指南以简化版的Conversational RAG教程为基础,主要探讨两种实现方法:链和代理。
主要内容
1. 基础设置
首先,我们需要设置环境和依赖库。在本次演示中,我们将使用OpenAI的嵌入以及Chroma向量存储。以下是需要安装的包:
%%capture --no-stderr
%pip install --upgrade --quiet langchain langchain-community langchain-chroma bs4
此外,需要设置环境变量OPENAI_API_KEY,可以直接设置或通过.env文件加载:
import getpass
import os
if not os.environ.get("OPENAI_API_KEY"):
os.environ["OPENAI_API_KEY"] = getpass.getpass()
2. 使用链管理历史查询
在Conversational RAG应用中,向检索器发出的查询应该考虑对话的上下文。LangChain提供了create_history_aware_retriever构造器来简化这一过程。
实现步骤:
- 选择LLM和检索器:我们可以使用各种聊天模型(如OpenAI、Anthropic等)和检索器(如Chroma)。
- 构造检索器:如下代码示例中,我们使用
WebBaseLoader和Chroma创建向量存储及检索器。
import bs4
from langchain_chroma import Chroma
from langchain_community.document_loaders import WebBaseLoader
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
loader = WebBaseLoader(
web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),
bs_kwargs=dict(
parse_only=bs4.SoupStrainer(
class_=("post-content", "post-title", "post-header")
)
),
)
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() # 使用API代理服务提高访问稳定性
3. 使用代理动态管理检索步骤
代理允许我们利用LLM的推理能力在执行过程中做决策,提供更高级的灵活性。
实施细节:
- 创建检索工具:将我们的检索器转化为LangChain工具。
- 构建代理:使用LangGraph构建代理,可以高层接口构建,也可以调整底层API来更改代理逻辑。
from langgraph.prebuilt import create_react_agent
agent_executor = create_react_agent(llm, tools)
代码示例
以下是一个完整的示例,展示如何将上述逻辑结合在一起:
import bs4
from langchain_chroma import Chroma
from langchain_community.document_loaders import WebBaseLoader
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.tools.retriever import create_retriever_tool
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/",),
bs_kwargs=dict(
parse_only=bs4.SoupStrainer(
class_=("post-content", "post-title", "post-header")
)
),
)
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",
"搜索并返回自主代理博客文章的摘录。",
)
tools = [tool]
agent_executor = create_react_agent(llm, tools, checkpointer=memory)
常见问题和解决方案
- 网络访问限制:某些地区的网络访问可能受到限制,推荐使用API代理服务确保访问的稳定性。
- 复杂性管理:随着对话复杂性增加,可考虑使用LangSmith进行链条或代理的调试和追踪。
总结和进一步学习资源
通过本文的学习,我们了解了如何在聊天应用中添加对话历史记录,从而提高问答的智能性。以下是一些进一步学习的资源:
参考资料
- Weng, L. (2023). LLM Powered Autonomous Agents. Retrieved from lilianweng.github.io/posts/2023-…
- LangChain API 文档
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力! ---END---