LangChain教程 - 向量存储与检索器
在这个教程中,你将了解 LangChain 的向量存储和检索器抽象。这些抽象旨在支持从(向量)数据库和其他来源检索数据,并将其集成到大语言模型(LLM)的工作流程中。这在基于检索增强生成(RAG)等应用中尤为重要,因为这些应用需要在模型推理过程中提取数据供模型进行推理。通过本教程,你应该已经了解了 LangChain 的向量存储与检索器的基本概念和使用方法。这些工具为构建复杂的基于 LLM 的应用
系列文章索引
LangChain教程 - 系列文章
介绍
在这个教程中,你将了解 LangChain 的向量存储和检索器抽象。这些抽象旨在支持从(向量)数据库和其他来源检索数据,并将其集成到大语言模型(LLM)的工作流程中。这在基于检索增强生成(RAG)等应用中尤为重要,因为这些应用需要在模型推理过程中提取数据供模型进行推理。
概念
本教程将主要关注文本数据的检索,涵盖以下几个核心概念:
- 文档(Documents):表示文本数据的基本单位,通常包含内容和元数据。
- 向量存储(Vector Stores):通过将文本转换为向量存储起来,便于快速相似性搜索。
- 检索器(Retrievers):基于向量存储,执行高效的文本检索。
环境准备
Jupyter Notebook
你可以在 Jupyter Notebook 中运行本教程。如果尚未安装,请参考 Jupyter 安装指南。
安装依赖包
我们将使用以下 Python 包:
langchain
langchain-chroma
langchain-openai
通过以下命令安装:
pip install langchain langchain-chroma langchain-openai
安装后,我们就可以开始搭建 LangChain 环境。
文档(Documents)
LangChain 实现了一个文档抽象,用来表示一段文本及其关联的元数据。每个文档都有两个属性:
page_content
:表示文档的文本内容;metadata
:一个包含文档相关信息的字典,比如文档来源等。
我们可以通过以下代码生成一些示例文档:
from langchain_core.documents import Document
documents = [
Document(
page_content="狗是忠诚和友好的伴侣。",
metadata={"source": "mammal-pets-doc"},
),
Document(
page_content="猫是一种独立的宠物,通常喜欢自己的空间。",
metadata={"source": "mammal-pets-doc"},
),
Document(
page_content="金鱼是新手的理想宠物,照顾起来相对简单。",
metadata={"source": "fish-pets-doc"},
),
Document(
page_content="鹦鹉是聪明的鸟类,能够模仿人类的语言。",
metadata={"source": "bird-pets-doc"},
),
Document(
page_content="兔子是一种社交性很强的动物,喜欢有足够的空间活动。",
metadata={"source": "mammal-pets-doc"},
),
]
这些文档示例为后续的检索实验提供了基础数据集。
向量存储(Vector Stores)
向量存储是一种常见的用于存储和检索非结构化数据(如文本)的方式。它的核心思想是将文本数据转换为数值向量,并使用向量相似性度量来进行查询。
LangChain 提供了多种向量存储的集成接口,可以将文本或文档添加到向量存储中,并通过多种相似性度量方法进行查询。我们这里使用 Chroma 的内存实现来演示向量存储的使用。
首先,我们需要一个嵌入模型来将文本转换为向量。下面的示例使用 OpenAI 的嵌入模型:
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
vectorstore = Chroma.from_documents(
documents,
embedding=OpenAIEmbeddings(),
)
from_documents
方法会将文档添加到向量存储中。你可以使用 similarity_search
方法来基于字符串查询文档。
results = vectorstore.similarity_search("猫")
for doc in results:
print(doc.page_content)
这个查询会返回与 “猫” 最相关的文档。
检索器(Retrievers)
LangChain 提供了检索器(Retriever)接口,用于执行标准化的检索操作。检索器可以集成到复杂的应用中,例如结合检索上下文和问题的 RAG 应用。我们可以使用向量存储的 as_retriever
方法生成一个检索器。
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 1})
然后我们可以通过批量查询来检索多个文档:
results = retriever.batch(["猫", "鲨鱼"])
for res in results:
for doc in res:
print(doc.page_content)
通过这种方式,我们可以根据相似性从向量存储中检索与多个查询相关的文档。
检索增强生成(RAG)应用示例
检索器可以方便地集成到 RAG 应用中,将问题和检索到的上下文结合生成答案。下面是一个简单的 RAG 实现示例:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
llm = ChatOpenAI(model="gpt-4o-mini")
message = """
请根据提供的上下文回答问题。
问题:
{question}
上下文:
{context}
"""
prompt = ChatPromptTemplate.from_messages([("human", message)])
rag_chain = {"context": retriever, "question": RunnablePassthrough()} | prompt | llm
response = rag_chain.invoke("告诉我关于猫的事情")
print(response.content)
这个例子展示了如何使用 LangChain 结合检索器和语言模型完成复杂的生成任务。
完整代码
# 导入必要的包
from langchain_core.documents import Document
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
import os
import getpass
# 设置 OpenAI API Key
os.environ["OPENAI_API_KEY"] = getpass.getpass("输入你的 OpenAI API Key: ")
# 生成示例文档
documents = [
Document(
page_content="狗是忠诚和友好的伴侣。",
metadata={"source": "mammal-pets-doc"},
),
Document(
page_content="猫是一种独立的宠物,通常喜欢自己的空间。",
metadata={"source": "mammal-pets-doc"},
),
Document(
page_content="金鱼是新手的理想宠物,照顾起来相对简单。",
metadata={"source": "fish-pets-doc"},
),
Document(
page_content="鹦鹉是聪明的鸟类,能够模仿人类的语言。",
metadata={"source": "bird-pets-doc"},
),
Document(
page_content="兔子是一种社交性很强的动物,喜欢有足够的空间活动。",
metadata={"source": "mammal-pets-doc"},
),
]
# 初始化向量存储(使用 OpenAI 的嵌入模型)
vectorstore = Chroma.from_documents(
documents,
embedding=OpenAIEmbeddings(),
)
# 执行基于相似性的查询
print("执行基于相似性的查询:")
results = vectorstore.similarity_search("猫")
for i, doc in enumerate(results, 1):
print(f"文档 {i} 内容: {doc.page_content}\n")
# 创建一个检索器并进行批量查询
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 1})
print("执行批量查询:")
batch_results = retriever.batch(["猫", "鲨鱼"])
for i, res in enumerate(batch_results, 1):
for doc in res:
print(f"批量查询 {i} 结果: {doc.page_content}\n")
# 检索增强生成(RAG)示例
llm = ChatOpenAI(model="gpt-4o-mini")
message = """
请根据提供的上下文回答问题。
问题:
{question}
上下文:
{context}
"""
prompt = ChatPromptTemplate.from_messages([("human", message)])
rag_chain = {"context": retriever, "question": RunnablePassthrough()} | prompt | llm
# 执行 RAG 查询
response = rag_chain.invoke("告诉我关于猫的事情")
print(f"RAG 生成结果: {response.content}")
总结
通过本教程,你应该已经了解了 LangChain 的向量存储与检索器的基本概念和使用方法。这些工具为构建复杂的基于 LLM 的应用提供了强大的数据检索能力。你可以进一步结合这些概念开发更加智能的应用。
附1:Chroma存储位置
Chroma.from_documents
是 LangChain 中使用 Chroma 向量数据库的一个方法,它将文档内容转换为嵌入向量并存储在 Chroma 中。具体存储位置取决于 Chroma 的配置。如果没有特别指定,默认情况下数据是存储在内存中,即会在程序运行期间保存在 RAM 中,并在程序结束时丢失。
然而,Chroma 也可以配置为将数据存储到磁盘或其他数据库持久化存储。默认情况下,它有以下几种存储选项:
-
内存存储(In-memory):默认情况下,Chroma 将数据存储在内存中,这非常适合测试或小规模实验。数据不会被持久化,程序结束后数据会丢失。
-
磁盘存储(Persistent Storage on Disk):你可以指定 Chroma 将数据持久化到磁盘中,这样即使程序结束,数据也不会丢失。你可以通过指定
persist_directory
参数来设置存储路径。示例:
vectorstore = Chroma.from_documents( documents, embedding=OpenAIEmbeddings(), persist_directory="./chroma_storage" # 指定存储目录 )
这会将数据保存到当前目录下的
chroma_storage
文件夹中。 -
其他数据库(Custom Storage Options):Chroma 还可以与其他存储后端集成,比如通过 PostgreSQL 等数据库进行存储。此时你需要配置 Chroma 连接到外部数据库。
持久化向量存储的示例
如果你想要将向量数据持久化到磁盘,可以使用 persist_directory
参数,并在完成插入数据后调用 persist()
方法来保存数据:
vectorstore = Chroma.from_documents(
documents,
embedding=OpenAIEmbeddings(),
persist_directory="./chroma_storage" # 指定存储路径
)
# 向量存储后调用 persist() 方法进行持久化
vectorstore.persist()
重新加载持久化数据
如果你已经将数据持久化到磁盘并想在下次程序运行时重新加载这些数据,可以直接通过指定 persist_directory
来加载:
vectorstore = Chroma(
embedding_function=OpenAIEmbeddings(),
persist_directory="./chroma_storage" # 指定持久化路径
)
# 现在可以进行查询
results = vectorstore.similarity_search("猫")
for doc in results:
print(doc.page_content)
这种方式允许你在不同的会话之间保留和使用向量存储的数据。
总结
- 默认情况下,
Chroma.from_documents
将向量数据存储在内存中,不会持久化。 - 你可以通过设置
persist_directory
将数据存储到磁盘,并通过persist()
方法确保数据保存。 - 你还可以配置 Chroma 连接到外部存储后端,如 PostgreSQL,以支持更复杂的存储需求。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)