引言
在现代的问答应用中,用户期望能够与系统进行自然流畅的对话,这需要应用程序具备某种形式的"记忆"能力,以便可以综合先前的问题和答案到当前的对话中。本文将探讨通过会话增强生成(RAG)技术为应用程序添加对话逻辑的方法,重点讨论如何处理聊天历史记录以及使用链式结构和代理(Agent)实现这一目标。
主要内容
利用链的方式
链是我们在每次执行时都完成检索步骤的简单方法。通过构建链,我们可以确保每次用户输入都会触发检索操作,从而获取相关的上下文信息。
代理的使用
代理允许我们向大语言模型(LLM)赋予自主决策权,使它可以根据需要决定是否执行检索步骤,甚至可以多次检索。这种方法使得应用程序的行为更加灵活和智能。
设置和依赖项
要实现这些功能,我们需要使用一些库和工具,例如OpenAI嵌入和Chroma向量存储。可以使用环境变量设置API密钥,以便使用这些服务。
LangSmith的可选使用
为了更好地调试和管理复杂的链条,LangSmith是一个非常有用的工具。它可以帮助开发者查看链中每一个步骤的详细信息。
代码示例
以下是使用链构建问答应用的示例代码:
import os
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain import hub
from langchain.chains import create_retrieval_chain, create_stuff_documents_chain
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.prompts import ChatPromptTemplate
from langchain_text_splitters import RecursiveCharacterTextSplitter
import bs4
# 使用API代理服务提高访问稳定性
os.environ["OPENAI_API_KEY"] = getpass.getpass()
llm = ChatOpenAI(model="gpt-3.5-turbo")
# 加载并切分文档
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()
# 构建QA链
system_prompt = (
"You are an assistant for question-answering tasks. "
"Use the following pieces of retrieved context to answer "
"the question. If you don't know the answer, say that you "
"don't know. Use three sentences maximum and keep the "
"answer concise."
"\n\n"
"{context}"
)
qa_prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
("human", "{input}"),
]
)
question_answer_chain = create_stuff_documents_chain(llm, qa_prompt)
rag_chain = create_retrieval_chain(retriever, question_answer_chain)
response = rag_chain.invoke({"input": "What is Task Decomposition?"})
print(response["answer"])
常见问题和解决方案
- 网络访问问题:由于某些地区的网络限制,开发者可能需要考虑使用API代理服务来提高访问的稳定性。
- 上下文关联问题:通过维护会话历史,LLM能够更好地理解和关联用户的上下文信息。
总结和进一步学习资源
本文介绍了如何利用RAG和代理来实现复杂的对话问答系统。要进一步探索不同的检索器和策略,请参考LangChain的检索器文档。对于对话记忆功能的详细指南,可以查看LangChain的会话内存模块。
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---