LangChain-v0.2文档翻译:2.3、教程-构建向量存储库和检索器

  1. 介绍
  2. 教程
    2.1. 构建一个简单的 LLM 应用程序
    2.2. 构建一个聊天机器人
    2.3. 构建向量存储库和检索器(点击查看原文

这个教程将帮助您熟悉LangChain的向量存储和检索器抽象概念。这些抽象概念旨在支持从向量数据库和其他来源检索数据,以便与LLM(大型语言模型)工作流程集成。它们对于应用程序来说非常重要,这些应用程序需要获取数据以作为模型推理的一部分进行推理,就像检索增强生成(RAG)的情况一样(请参阅我们这里关于RAG的教程)。

概念

本指南重点介绍文本数据的检索。我们将涵盖以下概念:

  • 文档;
  • 向量存储;
  • 检索器。

安装

Jupyter Notebook

这些和其他教程可能最方便在Jupyter笔记本中运行。请参阅此处了解如何安装。

安装

本教程需要安装langchainlangchain-chromalangchain-openai包:

  • pip
pip install langchain langchain-chroma langchain-openai
  • conda
conda install langchain langchain-chroma langchain-openai -c conda-forge

更多详细信息,请参见我们的安装指南。

LangSmith

使用LangChain构建的许多应用程序将包含多个步骤,涉及LLM调用的多次调用。
随着这些应用程序变得越来越复杂,能够检查链或代理内部的确切情况变得至关重要。
最好的方法是使用LangSmith
在上述链接注册后,请确保设置您的环境变量以开始记录跟踪:

export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY="..."

或者,如果在笔记本中,您可以使用以下方式设置它们:

import getpass
import os

os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = getpass.getpass()

文档

LangChain实现了一个文档抽象,旨在表示一个文本单元和相关的元数据。它有两个属性:

  • page_content: 表示内容的字符串;
  • metadata: 包含任意元数据的字典。

metadata属性可以捕获有关文档来源、其与其他文档的关系以及其他信息。请注意,单个Document对象通常表示一个更大文档的一部分。

让我们生成一些示例文档:

from langchain_core.documents import Document

documents = [
    Document(
        page_content="狗是伟大的伴侣,以其忠诚和友好而闻名。",
        metadata={"source": "哺乳动物宠物文档"},
    ),
    Document(
        page_content="猫是独立的宠物,通常喜欢自己的空间。",
        metadata={"source": "哺乳动物宠物文档"},
    ),
    Document(
        page_content="金鱼是初学者的流行宠物,需要相对简单的护理。",
        metadata={"source": "鱼类宠物文档"},
    ),
    Document(
        page_content="鹦鹉是聪明的鸟类,能够模仿人类的语言。",
        metadata={"source": "鸟类宠物文档"},
    ),
    Document(
        page_content="兔子是社交动物,需要足够的空间跳跃。",
        metadata={"source": "哺乳动物宠物文档"},
    ),
]

这里我们生成了五个文档,包含元数据指示三个不同的“来源”。

向量存储

向量搜索是存储和搜索非结构化数据(例如非结构化文本)的常见方式。其理念是存储与文本相关联的数值向量。给定一个查询,我们可以将其嵌入为相同维度的向量,并使用向量相似性度量来识别存储中的相关数据。

LangChain VectorStore对象包含添加文本和Document对象到存储中,以及使用各种相似度指标查询它们的方法。它们通常使用 embedding模型进行初始化,这些模型决定了如何将文本数据转换为数值向量。

LangChain 包含一套与不同向量存储技术的集成。一些向量存储由提供商托管(例如,各种云提供商),需要特定的凭据才能使用;一些(例如Postgres)在可以本地运行或通过第三方运行的单独基础设施中运行;其他可以在内存中运行以进行轻量级工作负载。这里我们将演示使用Chroma的LangChain VectorStores的使用,它包括一个内存中的实现。

要实例化一个向量存储,我们通常需要提供一个嵌入模型来指定如何将文本转换为数值向量。这里我们将使用OpenAI嵌入。

from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

vectorstore = Chroma.from_documents(
    documents,
    embedding=OpenAIEmbeddings(),
)

这里调用.from_documents将文档添加到向量存储中。VectorStore实现了添加文档的方法,也可以在对象实例化后调用。大多数实现将允许您连接到现有的向量存储–例如,通过提供客户端、索引名称或其他信息。有关更多详细信息,请参见特定集成的文档。

一旦我们实例化了一个包含文档的VectorStore,我们就可以查询它。VectorStore包括查询方法:

  • 同步和异步;
  • 通过字符串查询和向量查询;
  • 返回或不返回相似度分数;
  • 通过相似性和最大边际相关性(在检索结果中平衡与查询的相似性与多样性)。

这些方法通常在其输出中包括一个Document对象列表。

示例

根据与字符串查询的相似性返回文档:

vectorstore.similarity_search("cat")

[Document(page_content=‘猫是独立的宠物,通常喜欢自己的空间。’, metadata={‘source’:
‘哺乳动物宠物文档’}), Document(page_content=‘狗是伟大的伴侣,以其忠诚和友好而闻名。’,
metadata={‘source’: ‘哺乳动物宠物文档’}),
Document(page_content=‘兔子是社交动物,需要足够的空间跳跃。’, metadata={‘source’:
‘哺乳动物宠物文档’}), Document(page_content=‘鹦鹉是聪明的鸟类,能够模仿人类的语言。’,
metadata={‘source’: ‘鸟类宠物文档’})]

异步查询:

await vectorstore.asimilarity_search("cat")

[Document(page_content=‘猫是独立的宠物,通常喜欢自己的空间。’, metadata={‘source’:
‘哺乳动物宠物文档’}), Document(page_content=‘狗是伟大的伴侣,以其忠诚和友好而闻名。’,
metadata={‘source’: ‘哺乳动物宠物文档’}),
Document(page_content=‘兔子是社交动物,需要足够的空间跳跃。’, metadata={‘source’:
‘哺乳动物宠物文档’}), Document(page_content=‘鹦鹉是聪明的鸟类,能够模仿人类的语言。’,
metadata={‘source’: ‘鸟类宠物文档’})]

返回分数:

# 注意,提供商实现的分数不同;Chroma在这里
# 返回一个距离度量,应该与相似性成反比变化。
vectorstore.similarity_search_with_score("cat")

[(Document(page_content=‘猫是独立的宠物,通常喜欢自己的空间。’, metadata={‘source’:
‘哺乳动物宠物文档’}),
0.3751849830150604), (Document(page_content=‘狗是伟大的伴侣,以其忠诚和友好而闻名。’, metadata={‘source’: ‘哺乳动物宠物文档’}),
0.48316916823387146), (Document(page_content=‘兔子是社交动物,需要足够的空间跳跃。’, metadata={‘source’: ‘哺乳动物宠物文档’}),
0.49601367115974426), (Document(page_content=‘鹦鹉是聪明的鸟类,能够模仿人类的语言。’, metadata={‘source’: ‘鸟类宠物文档’}),
0.4972994923591614)]

根据与嵌入查询的相似性返回文档:

embedding = OpenAIEmbeddings().embed_query("cat")

vectorstore.similarity_search_by_vector(embedding)

[Document(page_content=‘猫是独立的宠物,通常喜欢自己的空间。’, metadata={‘source’:
‘哺乳动物宠物文档’}), Document(page_content=‘狗是伟大的伴侣,以其忠诚和友好而闻名。’,
metadata={‘source’: ‘哺乳动物宠物文档’}),
Document(page_content=‘兔子是社交动物,需要足够的空间跳跃。’, metadata={‘source’:
‘哺乳动物宠物文档’}), Document(page_content=‘鹦鹉是聪明的鸟类,能够模仿人类的语言。’,
metadata={‘source’: ‘鸟类宠物文档’})]

了解更多:

  • API参考
  • 如何指南
  • 特定集成文档

检索器

LangChain VectorStore对象没有Runnable子类,因此不能立即集成到LangChain表达式语言链中。

LangChain Retrievers是 Runnable,因此它们实现了一组标准方法(例如,同步和异步的invokebatch操作),并设计为被合并到LCEL链中。

我们可以自己创建一个简单的版本,而不需要从Retriever继承。如果我们选择我们希望使用的方法来检索文档,我们可以轻松地创建一个可运行的。下面我们将围绕similarity_search方法构建一个:

from typing import List

from langchain_core.documents import Document
from langchain_core.runnables import RunnableLambda

retriever = RunnableLambda(vectorstore.similarity_search).bind(k=1)  # 选择顶部结果

retriever.batch(["cat", "shark"])

[[Document(page_content=‘猫是独立的宠物,通常喜欢自己的空间。’, metadata={‘source’:
‘哺乳动物宠物文档’})], [Document(page_content=‘金鱼是初学者的流行宠物,需要相对简单的护理。’,
metadata={‘source’: ‘鱼类宠物文档’})]]

Vectorstores 实现了一种as_retriever生成 Retriever 的方法,具体来说就是VectorStoreRetriever。这些检索器包括特定的search_typesearch_kwargs属性,这些属性确定调用底层向量存储的哪些方法,以及如何参数化它们。例如,我们可以使用以下方式复制上述内容:

retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 1},
)

retriever.batch(["cat", "shark"])

[[Document(page_content=‘猫是独立的宠物,通常喜欢自己的空间。’, metadata={‘source’:
‘哺乳动物宠物文档’})], [Document(page_content=‘金鱼是初学者的流行宠物,需要相对简单的护理。’,
metadata={‘source’: ‘鱼类宠物文档’})]]

VectorStoreRetriever支持"similarity"(默认)、"mmr"(最大边际相关性,如上所述)和"similarity_score_threshold"的搜索类型。我们可以使用后者通过相似性分数来阈值检索器输出的文档。

检索器可以轻松地被合并到更复杂的应用程序中,例如检索增强生成(RAG)应用程序,这些应用程序将给定的问题与检索到的上下文结合起来,作为一个LLM的提示。下面我们展示了一个最小示例,基于OpenAI。

  • OpenAI
pip install -qU langchain-openai
import getpass
import os

os.environ["OPENAI_API_KEY"] = getpass.getpass()

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo-0125")
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

message = """
使用提供的上下文仅回答这个问题。

{question}

上下文:
{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)

猫是独立的宠物,通常喜欢自己的空间。

了解更多:

检索策略可以丰富而复杂。例如:

  • 我们可以从查询中推断出硬规则和过滤器(例如,“使用2020年后发布的文档”);
  • 我们可以返回以某种方式与检索上下文相关联的文档(例如,通过某种文档分类法);
  • 我们可以为每个上下文单元生成多个嵌入;
  • 我们可以集成来自多个检索器的结果;
  • 我们可以为文档分配权重,例如,给最近的文档更高的权重。

如何指南中的检索器部分涵盖了这些和其他内置检索策略。

扩展BaseRetriever类以实现自定义检索器也是直接的。请参阅我们这里的如何指南。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值