在此示例中,我们将了解如何在 RAG 应用程序中使用新的 MongoDBCache 和 MongoDBChatMessageHistory。
步骤1: 安装所需库
- datasets: 用于访问Hugging Face Hub上可用数据集的Python库
- langchain: LangChain的Python工具包
- langchain-mongodb: 在LangChain中使用MongoDB作为向量存储、语义缓存、聊天历史存储等的Python包
- langchain-openai: 在LangChain中使用OpenAI模型的Python包
- pymongo: MongoDB的Python工具包
- pandas: 用于数据分析、探索和操作的Python库
! pip install -qU datasets langchain langchain-mongodb langchain-openai pymongo pandas
步骤2: 设置先决条件
import getpass
# 导入getpass模块用于安全输入密码
MONGODB_URI = getpass.getpass("输入你的MongoDB连接字符串:")
# 安全地输入MongoDB连接字符串
OPENAI_API_KEY = getpass.getpass("输入你的OpenAI API密钥:")
# 安全地输入OpenAI API密钥
# 可选 -- 如果你想启用Langsmith -- 对调试很有帮助
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = getpass.getpass()
# 设置Langsmith环境变量
步骤3: 下载数据集
我们将使用MongoDB的embedded_movies数据集
import pandas as pd
from datasets import load_dataset
# 导入pandas和datasets库
# 确保你的开发环境中有HF_TOKEN:
# 访问令牌可以在Hugging Face平台上创建或复制 (https://huggingface.co/docs/hub/en/security-tokens)
# 从Hugging Face加载MongoDB的embedded_movies数据集
# https://huggingface.co/datasets/MongoDB/airbnb_embeddings
data = load_dataset("MongoDB/embedded_movies")
# 加载数据集
df = pd.DataFrame(data["train"])
# 将数据集转换为pandas DataFrame
步骤4: 数据分析
确保数据集长度符合预期,删除空值等。
# 预览数据内容
df.head(1)
# 只保留fullplot字段不为空的记录
df = df[df["fullplot"].notna()]
# 将嵌入字段重命名为"embedding" -- LangChain要求
df.rename(columns={"plot_embedding": "embedding"}, inplace=True)
步骤5: 使用MongoDB作为向量存储创建简单的RAG链
from langchain_mongodb import MongoDBAtlasVectorSearch
from pymongo import MongoClient
# 初始化MongoDB Python客户端
client = MongoClient(MONGODB_URI, appname="devrel.content.python")
DB_NAME = "langchain_chatbot"
COLLECTION_NAME = "data"
ATLAS_VECTOR_SEARCH_INDEX_NAME = "vector_index"
collection = client[DB_NAME][COLLECTION_NAME]
# 删除集合中任何现有记录
collection.delete_many({})
# 数据导入
records = df.to_dict("records")
collection.insert_many(records)
print("数据导入MongoDB完成")
from langchain_openai import OpenAIEmbeddings
# 使用text-embedding-ada-002,因为这是用于创建电影数据集中的嵌入的模型
embeddings = OpenAIEmbeddings(
openai_api_key=OPENAI_API_KEY, model="text-embedding-ada-002"
)
# 创建向量存储
vector_store = MongoDBAtlasVectorSearch.from_connection_string(
connection_string=MONGODB_URI,
namespace=DB_NAME + "." + COLLECTION_NAME,
embedding=embeddings,
index_name=ATLAS_VECTOR_SEARCH_INDEX_NAME,
text_key="fullplot",
)
# 在RAG链中使用MongoDB向量存储作为检索器
retriever = vector_store.as_retriever(search_type="similarity", search_kwargs={"k": 5})
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
# 使用检索器生成上下文,并传递用户问题
retrieve = {
"context": retriever | (lambda docs: "\n\n".join([d.page_content for d in docs])),
"question": RunnablePassthrough(),
}
template = """仅根据以下上下文回答问题: \
{context}
问题: {question}
"""
# 定义聊天提示
prompt = ChatPromptTemplate.from_template(template)
# 定义用于聊天完成的模型
model = ChatOpenAI(temperature=0, openai_api_key=OPENAI_API_KEY)
# 将输出解析为字符串
parse_output = StrOutputParser()
# 简单的RAG链
naive_rag_chain = retrieve | prompt | model | parse_output
naive_rag_chain.invoke("当伤心时看什么电影最好?")
步骤6: 创建带有聊天历史的RAG链
from langchain_core.prompts import MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_mongodb.chat_message_histories import MongoDBChatMessageHistory
def get_session_history(session_id: str) -> MongoDBChatMessageHistory:
return MongoDBChatMessageHistory(
MONGODB_URI, session_id, database_name=DB_NAME, collection_name="history"
)
# 给定一个后续问题和历史记录,创建一个独立的问题
standalone_system_prompt = """
给定聊天历史和后续问题,将后续问题重新表述为一个独立的问题。\
不要回答问题,只需在需要时重新表述,否则按原样返回。\
只返回最终的独立问题。\
"""
standalone_question_prompt = ChatPromptTemplate.from_messages(
[
("system", standalone_system_prompt),
MessagesPlaceholder(variable_name="history"),
("human", "{question}"),
]
)
question_chain = standalone_question_prompt | model | parse_output
# 通过将question_chain的输出(即独立问题)传递给检索器来生成上下文
retriever_chain = RunnablePassthrough.assign(
context=question_chain
| retriever
| (lambda docs: "\n\n".join([d.page_content for d in docs]))
)
# 创建一个包含上下文、历史记录和后续问题的提示
rag_system_prompt = """仅根据以下上下文回答问题: \
{context}
"""
rag_prompt = ChatPromptTemplate.from_messages(
[
("system", rag_system_prompt),
MessagesPlaceholder(variable_name="history"),
("human", "{question}"),
]
)
# RAG链
rag_chain = retriever_chain | rag_prompt | model | parse_output
# 带有历史记录的RAG链
with_message_history = RunnableWithMessageHistory(
rag_chain,
get_session_history,
input_messages_key="question",
history_messages_key="history",
)
with_message_history.invoke(
{"question": "当伤心时看什么电影最好?"},
{"configurable": {"session_id": "1"}},
)
with_message_history.invoke(
{
"question": "嗯...我不想看那个。你能推荐其他的吗?"
},
{"configurable": {"session_id": "1"}},
)
with_message_history.invoke(
{"question": "有更轻松一点的吗?"},
{"configurable": {"session_id": "1"}},
)
步骤7: 使用语义缓存获得更快的响应
注意: 语义缓存只缓存LLM的输入。在检索链中使用时,请记住检索到的文档可能在运行之间发生变化,导致语义相似的查询出现缓存未命中。
from langchain_core.globals import set_llm_cache
from langchain_mongodb.cache import MongoDBAtlasSemanticCache
set_llm_cache(
MongoDBAtlasSemanticCache(
connection_string=MONGODB_URI,
embedding=embeddings,
collection_name="semantic_cache",
database_name=DB_NAME,
index_name=ATLAS_VECTOR_SEARCH_INDEX_NAME,
wait_until_ready=True, # 可选,等待缓存准备就绪后再使用
)
)
%%time
naive_rag_chain.invoke("当伤心时看什么电影最好?")
%%time
naive_rag_chain.invoke("当伤心时看什么电影最好?")
%%time
naive_rag_chain.invoke("伤心的时候我应该看什么电影?")
总结
本文介绍了如何在RAG(检索增强生成)应用中使用MongoDB的新功能MongoDBCache和MongoDBChatMessageHistory。文章详细说明了安装必要库、设置先决条件、下载并分析数据集、创建简单的RAG链、添加聊天历史功能,以及使用语义缓存来加速响应等步骤。这些技术可以显著提高RAG应用的性能和用户体验。
扩展知识
-
RAG (检索增强生成) 是一种结合了检索系统和生成模型的技术,可以提高大语言模型回答问题的准确性和相关性。
-
语义缓存是一种高级缓存技术,它不仅基于精确匹配来缓存结果,还可以识别语义相似的查询,从而提高缓存命中率。
-
MongoDB Atlas Vector Search 是一个强大的工具,可以高效地执行向量相似性搜索,这在实现RAG系统时非常有用。
-
LangChain 是一个用于开发以语言模型为中心的应用程序的框架,它提供了许多工具和抽象,使得构建复杂的AI应用变得更加简单。
-
在实际应用中,合理使用缓存和历史记录可以显著提高系统的响应速度和用户体验,同时也可以减少API调用成本。