学习总结
通过这段代码,我实现了一个结合文档检索与聊天对话的智能聊天机器人(Chatbot)。其主要特点是能够根据用户输入的问题,从事先加载的文档中检索相关信息,并且能够与用户进行多轮对话。我的目标是通过引入大模型(LLM)和文档检索技术,提升聊天机器人的回答准确性和互动能力。
在构建过程中,我利用了langchain
框架的多个功能模块:
- 文档加载与处理:通过
PyPDFLoader
、Docx2txtLoader
、TextLoader
等模块加载文档(如PDF、DOCX、TXT等),并进行文本分割处理,确保大文档可以被有效检索。 - 向量化与检索:通过
OpenAIEmbeddings
生成文档的向量表示,并使用Qdrant
创建向量数据库,实现基于文本内容的检索功能。 - 对话记忆:引入
ConversationSummaryMemory
,使得聊天机器人能够记住上下文信息,处理多轮对话中的历史记录,从而使得回答更具连贯性和智能化。 - LLM与Retrieval链:结合
ChatOpenAI
作为语言模型,配合文档检索,利用ConversationalRetrievalChain
实现对用户输入问题的响应。
通过这些技术的结合,我的目标是创建一个智能的、能够从特定文档库中获取信息并与用户自然对话的系统,进而为用户提供有用的知识和答案。
思考题:简化代码中的Memory部分
在代码中,我使用了ConversationSummaryMemory
来进行多轮对话的记忆。根据第11讲的内容,ConversationChain
实际上是对Memory
和LLMChain
的封装,它能简化记忆管理和模型交互的步骤。为了简化代码,可以考虑使用ConversationChain
来替代ConversationSummaryMemory
和LLMChain
的组合。
ConversationChain
可以自动管理记忆,且它已经集成了LLM
和Memory
,因此不需要手动创建ConversationSummaryMemory
对象。简化后的代码可以如下:
from langchain.chains import ConversationChain
class ChatbotWithRetrieval:
def __init__(self, dir):
base_dir = dir
documents = []
for file in os.listdir(base_dir):
file_path = os.path.join(base_dir, file)
if file.endswith('.pdf'):
loader = PyPDFLoader(file_path)
documents.extend(loader.load())
elif file.endswith('.docx') or file.endswith('.doc'):
loader = Docx2txtLoader(file_path)
documents.extend(loader.load())
elif file.endswith('.txt'):
loader = TextLoader(file_path)
documents.extend(loader.load())
# 文本分割
text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=0)
all_splits = text_splitter.split_documents(documents)
# 向量数据库
self.vectorstore = Qdrant.from_documents(
documents=all_splits,
embedding=OpenAIEmbeddings(),
location=":memory:",
collection_name="my_documents",
)
# 初始化LLM
self.llm = ChatOpenAI()
# 使用ConversationChain直接结合Memory和LLM
retriever = self.vectorstore.as_retriever()
self.qa = ConversationChain.from_llm(
self.llm,
memory_key="chat_history",
retriever=retriever
)
def chat_loop(self):
print("Chatbot 已启动! 输入'exit'来退出程序。")
while True:
user_input = input("你: ")
if user_input.lower() == 'exit':
print("再见!")
break
# 调用ConversationChain进行对话
response = self.qa({"input": user_input})
print(f"Chatbot: {response['output']}")
在这个简化版的实现中,ConversationChain.from_llm
自动创建了一个包含Memory
的链,并处理了对话历史和检索功能的集成。这样一来,代码更加简洁,避免了手动管理Memory
对象的步骤。
思考题:增加数据库查询能力
在现有的聊天机器人中增加数据库查询能力,可以参考第17讲的内容。通过调用数据库查询功能,我们可以让聊天机器人根据用户提供的查询条件,查询鲜花的库存或销售情况。假设我们有一个数据库,包含关于鲜花的表(如:flowers_inventory
),并且我们能够通过SQL查询来获取相关信息。
为了将这一功能集成到聊天机器人中,我们可以在现有的ChatbotWithRetrieval
类中增加一个查询数据库的功能模块。以下是一个简单的集成方法:
- 数据库连接:通过Python的数据库库(如
sqlite3
、pymysql
等)连接到数据库。 - 查询功能:添加一个查询功能,查询特定鲜花的库存、销售等信息。
- 与聊天机器人结合:在用户的输入中,判断是否涉及数据库查询任务,如果是,则调用数据库查询模块。
示例代码如下:
import sqlite3
class ChatbotWithRetrieval:
def __init__(self, dir):
# 省略其他初始化代码
# 数据库连接
self.db_conn = sqlite3.connect('flower_inventory.db') # 连接数据库
self.db_cursor = self.db_conn.cursor()
# 初始化LLM和Retrieval Chain等
def query_inventory(self, flower_name):
# 查询数据库,返回鲜花库存情况
query = "SELECT stock, sales FROM flowers_inventory WHERE name = ?"
self.db_cursor.execute(query, (flower_name,))
result = self.db_cursor.fetchone()
if result:
return f"{flower_name}的库存为{result[0]},销售情况为{result[1]}。"
else:
return f"未找到{flower_name}的信息。"
def chat_loop(self):
print("Chatbot 已启动! 输入'exit'来退出程序。")
while True:
user_input = input("你: ")
if user_input.lower() == 'exit':
print("再见!")
break
# 判断是否涉及查询数据库
if '库存' in user_input or '销售' in user_input:
flower_name = user_input.split(' ')[0] # 假设用户输入的是类似 "玫瑰 库存情况" 的格式
response = self.query_inventory(flower_name)
else:
# 调用Retrieval Chain进行文档检索
response = self.qa({"input": user_input})["output"]
print(f"Chatbot: {response}")
在这个扩展中,我增加了一个query_inventory
方法来查询数据库,返回鲜花的库存和销售情况。然后,在chat_loop
中,判断用户输入是否包含“库存”或“销售”,如果是,就调用query_inventory
方法进行查询。如果不是查询请求,则继续执行文档检索功能。
通过这种方式,聊天机器人不仅能够处理文档中的信息,还能结合数据库的查询,增强了其业务能力。