LangChain核心模块 Retrieval——文本嵌入模型、Vector stores

Text embedding models

  • 文本嵌入模型

检索的另一个关键部分是为文档创建嵌入。

Embeddings 类是设计用于与文本嵌入模型交互的类。

Embeddings创建一段文本的矢量表示,这样我们就可以在向量空间中思考文本,并执行语义搜索之类的操作,在向量空间中查找最相似的文本片段。

LangChain中的Embeddings基类提供了两种方法:

  • 用于嵌入文档,采用多个文本作为输入
  • 用于嵌入查询,采用单个文本作为输入

将它们作为两种单独方法的原因是,某些嵌入提供程序对文档(要搜索的)与查询(搜索查询本身)有不同的嵌入方法。

from langchain_openai import OpenAIEmbeddings

embeddings_model = OpenAIEmbeddings()
  1. embed_documents

    嵌入文本列表

    embeddings = embeddings_model.embed_documents(
        [
            "Hi there!",
            "Oh, hello!",
            "What's your name?",
            "My friends call me World",
            "Hello World!"
        ]
    )
    len(embeddings), len(embeddings[0])
    
  2. embed_query

    嵌入单个查询,嵌入一段文本是为了与其他嵌入的文本进行比较。

    embedded_query = embeddings_model.embed_query("What was the name mentioned in the conversation?")
    embedded_query[:5]
    

CacheBackedEmbeddings

embeddings可以被存储或临时缓存以避免需要重新计算它们。

缓存embeddings可以使用 CacheBackedEmbeddings 来完成。支持缓存的嵌入器是嵌入器的包装器,它将嵌入缓存在键值存储中。对文本进行哈希处理,并将哈希值用作缓存中的密钥。

初始化 CacheBackedEmbeddings 的主要支持方式是 from_bytes_store。它需要以下参数:

  • underlying_embedder(底层嵌入器):用于嵌入的嵌入器。
  • document_embedding_cache(文档嵌入缓存):任何用于缓存文档嵌入的 ByteStore
  • batch_size:(optional, defaults to None)要更新嵌入的文档数量。
  • namespace:(optional, defaults to "") 用于文档缓存的命名空间,该命名空间用于避免与其他缓存发生冲突。例如,将其设置为所使用的嵌入模型的名称。

请务必设置命名空间参数,以避免使用不同嵌入模型嵌入的相同文本发生冲突。

from langchain.embeddings import CacheBackedEmbeddings
Using with a Vector Store

首先,让我们看一个使用本地文件系统存储嵌入并使用 FAISS 矢量存储进行检索的示例。

%pip install --upgrade --quiet  langchain-openai faiss-cpu
from langchain.storage import LocalFileStore
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter

underlying_embeddings = OpenAIEmbeddings()

store = LocalFileStore("./cache/")

cached_embedder = CacheBackedEmbeddings.from_bytes_store(
    underlying_embeddings, store, namespace=underlying_embeddings.model
)

嵌入之前缓存为空:

list(store.yield_keys())
[]

加载文档,将其分割成块,嵌入每个块并将其加载到向量存储中。

raw_documents = TextLoader("../../state_of_the_union.txt").load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
documents = text_splitter.split_documents(raw_documents)

创建向量存储:

%%time
db = FAISS.from_documents(documents, cached_embedder)
CPU times: user 218 ms, sys: 29.7 ms, total: 248 ms
Wall time: 1.02 s

如果我们尝试再次创建向量存储,它会快得多,因为它不需要重新计算任何嵌入。

%%time
db2 = FAISS.from_documents(documents, cached_embedder)
CPU times: user 15.7 ms, sys: 2.22 ms, total: 18 ms
Wall time: 17.2 ms

以下是创建的一些嵌入:

list(store.yield_keys())[:5]
['text-embedding-ada-00217a6727d-8916-54eb-b196-ec9c9d6ca472',
 'text-embedding-ada-0025fc0d904-bd80-52da-95c9-441015bfb438',
 'text-embedding-ada-002e4ad20ef-dfaa-5916-9459-f90c6d8e8159',
 'text-embedding-ada-002ed199159-c1cd-5597-9757-f80498e8f17b',
 'text-embedding-ada-0021297d37a-2bc1-5e19-bf13-6c950f075062']
Swapping the ByteStore
  • 交换字节存储

为了使用不同的 ByteStore,只需在创建 CacheBackedEmbeddings 时使用它即可。下面,我们创建一个等效的缓存嵌入对象,但使用非持久性InMemoryByteStore代替:

from langchain.embeddings import CacheBackedEmbeddings
from langchain.storage import InMemoryByteStore

store = InMemoryByteStore()

cached_embedder = CacheBackedEmbeddings.from_bytes_store(
    underlying_embeddings, store, namespace=underlying_embeddings.model
)

Vector stores

  • 矢量仓库

存储和搜索非结构化数据的最常见方法之一是将其嵌入,并存储生成的嵌入向量,然后在查询时嵌入非结构化查询并检索与嵌入查询“最相似”的嵌入向量。

矢量存储负责存储嵌入数据并执行矢量搜索。

在这里插入图片描述

使用向量存储的一个关键部分是创建要放入其中的向量,这通常是通过嵌入创建的。

Asynchronous operations

  • 异步操作

矢量存储通常作为需要一些 I/O 操作的单独服务运行,因此它们可能会被异步调用。这样会带来性能优势,因为不会浪费时间等待外部服务的响应。如果您使用异步框架(例如 FastAPI),这一点也可能很重要。

LangChain支持向量存储的异步操作。所有方法都可以使用其异步对应方法来调用,前缀 a 表示异步。

Qdrant 是一个向量存储,它支持所有异步操作,因此将在下例中使用它。

pip install qdrant-client
from langchain_community.vectorstores import Qdrant
  1. 异步创建向量存储

    db = await Qdrant.afrom_documents(documents, embeddings, "http://localhost:6333")
    
  2. 相似性搜索

    query = "What did the president say about Ketanji Brown Jackson"
    docs = await db.asimilarity_search(query)
    print(docs[0].page_content)
    
  3. 通过vector进行相似性搜索

    embedding_vector = embeddings.embed_query(query)
    docs = await db.asimilarity_search_by_vector(embedding_vector)
    

Maximum marginal relevance search (MMR)

  • 最大边际相关性搜索

最大边际相关性优化了所选文档之间查询的相似性和多样性。异步 API 也支持它。

query = "What did the president say about Ketanji Brown Jackson"
found_docs = await qdrant.amax_marginal_relevance_search(query, k=2, fetch_k=10)
for i, doc in enumerate(found_docs):
    print(f"{i + 1}.", doc.page_content, "\n")
  • 30
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值