Langchain入门:向量存储和检索器
LangChain 实现了一个 文档 抽象,旨在表示一个文本单元及其相关元数据。metadata 属性可以捕获有关文档来源、与其他文档的关系以及其他信息。请注意,单个 Document 对象通常表示一个较大文档的一部分。在这里,我们生成了五个文档,包含指示三个不同“来源”的元数据。
文档
LangChain 实现了一个 文档 抽象,旨在表示一个文本单元及其相关元数据。它有两个属性:
- page_content:一个表示内容的字符串;
- metadata:一个包含任意元数据的字典。
metadata 属性可以捕获有关文档来源、与其他文档的关系以及其他信息。请注意,单个 Document 对象通常表示一个较大文档的一部分。
from langchain_core.documents import Document
documents = [
Document(
page_content="Dogs are great companions, known for their loyalty and friendliness.",
metadata={"source": "mammal-pets-doc"},
),
Document(
page_content="Cats are independent pets that often enjoy their own space.",
metadata={"source": "mammal-pets-doc"},
),
Document(
page_content="Goldfish are popular pets for beginners, requiring relatively simple care.",
metadata={"source": "fish-pets-doc"},
),
Document(
page_content="Parrots are intelligent birds capable of mimicking human speech.",
metadata={"source": "bird-pets-doc"},
),
Document(
page_content="Rabbits are social animals that need plenty of space to hop around.",
metadata={"source": "mammal-pets-doc"},
),
]
在这里,我们生成了五个文档,包含指示三个不同“来源”的元数据。
向量存储
LangChain 向量存储 对象包含用于将文本和 文档 对象添加到存储中以及使用各种相似性度量进行查询的方法。它们通常使用 嵌入 模型进行初始化,这决定了文本数据如何转换为数值向量。
LangChain 包含与不同向量存储技术的 集成 套件。一些向量存储由提供商(例如各种云提供商)托管,并需要特定的凭据才能使用;一些(如 Postgres)在可以本地运行或通过第三方运行的独立基础设施中运行;其他可以在内存中运行以处理轻量级工作负载。这里我们将演示使用 Chroma 的 LangChain 向量存储,它包括一个内存实现。
要实例化一个向量存储,我们通常需要提供一个 嵌入 模型,以指定文本应如何转换为数值向量。这里我们将使用 OpenAI 嵌入。
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
vectorstore = Chroma.from_documents(
documents,
embedding=OpenAIEmbeddings(
openai_api_base="https://api.siliconflow.cn/v1/",
openai_api_key=os.environ["siliconFlow"],
model="Qwen/Qwen3-Embedding-4B")
)
在这里调用 .from_documents 将把文档添加到向量存储中。向量存储 实现了可以在对象实例化后调用的添加文档的方法。
一旦我们实例化了一个包含文档的 向量存储,我们就可以对其进行查询。向量存储 包含用于查询的方法:
- 同步和异步;
- 通过字符串查询和通过向量;
- 有和没有返回相似性分数;
- 通过相似性和 最大边际相关性(以平衡查询的相似性与检索结果的多样性)。
这些方法的输出通常会包含 文档 对象的列表。
示例
根据与字符串查询的相似性返回文档:
vectorstore.similarity_search("cats")

异步查询:
await vectorstore.asimilarity_search("cats")

返回分数:
vectorstore.similarity_search_with_score("cats")

根据与嵌入查询的相似性返回文档:
embedding = OpenAIEmbeddings(
openai_api_base="https://api.siliconflow.cn/v1/",
openai_api_key=os.environ["siliconFlow"],
model="Qwen/Qwen3-Embedding-4B").embed_query("cat") # 获取"cat"的向量表示
vectorstore.similarity_search_by_vector(embedding)

检索器
LangChain VectorStore 对象不继承 Runnable,因此无法立即集成到 LangChain 表达式 chains 中。
LangChain 检索器 是 Runnables,因此它们实现了一组标准方法(例如,同步和异步的 invoke 和 batch 操作),并设计为可以纳入 LCEL 链中。
我们可以自己创建一个简单版本,而无需继承 Retriever。如果我们选择希望用于检索文档的方法,我们可以轻松创建一个可运行的对象。下面我们将围绕 similarity_search 方法构建一个:
from langchain_core.runnables import RunnableLambda
retriever = RunnableLambda(vectorstore.similarity_search).bind(k=1)
retriever.batch(["cat", "shark"])
- RunnableLambda:将普通函数包装成 Runnable 对象
- vectorstore.similarity_search:向量存储的相似度搜索方法
- 作用:把 similarity_search 函数转换为可以在 LCEL 链中使用的组件
- bind():为函数绑定固定参数
- k=1:设置返回结果的数量为 1 个
- retriever.batch([“cat”, “shark”]) 的作用是批量处理多个查询,同时对 “cat” 和 “shark” 两个查询词进行相似度搜索。

向量存储实现了一个 as_retriever 方法,该方法将生成一个检索器,特别是一个 VectorStoreRetriever。这些检索器包括特定的 search_type 和 search_kwargs 属性,用于识别调用底层向量存储的方法,以及如何对其进行参数化。例如,我们可以用以下方式复制上述内容:
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 1}
)
retriever.batch(["cat", "shark"])

检索器可以轻松地纳入更复杂的应用程序,例如检索增强生成(RAG)应用程序,这些应用程序将给定问题与检索到的上下文结合成 LLM 的提示。下面我们展示一个最小示例。
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
openai_api_base = "https://api.siliconflow.cn/v1/",
openai_api_key = os.environ['siliconflow'],
model_name = "Qwen/Qwen3-8B", # 模型名称
)
注意: LangChain 自动将包含 Runnable 对象的字典转换为 RunnableParallel 对象。
字典中的每个 Runnable 会并行执行,输入会同时传递给所有组件。
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
message = """
Answer this question using the provided context only.
{question}
Context:
{context}
"""
prompt = ChatPromptTemplate.from_messages(["human", message])
rag_chain = {"context": retriever, "question":RunnablePassthrough()} | prompt | llm
response = rag_chain.invoke("tell me about cats")
print(response.content)

这里用Qwen的4B模型效果很差,建议用8B
更多推荐

所有评论(0)