LangChain嵌入模型与向量计算(79)

一、LangChain嵌入模型与向量计算概述

在LangChain框架中,嵌入模型(Embedding Model)与向量计算是构建智能应用的核心基础模块。嵌入模型负责将文本、图像等数据转换为低维稠密的向量表示,而向量计算则基于这些向量实现相似度检索、聚类等关键功能。理解其原理和源码实现,有助于开发者高效地利用LangChain开发各类应用。

1.1 嵌入模型的作用

嵌入模型的核心任务是将高维、离散的数据映射到低维、连续的向量空间中,使得语义相近的数据在向量空间中距离较近,语义差异大的数据距离较远。在LangChain中,文本嵌入是最常见的应用场景,例如将用户输入的问题、文档内容等转换为向量。通过这种方式,计算机能够以数值形式理解和处理文本语义信息,为后续的信息检索、问答系统、文本分类等任务提供基础支持 。

1.2 向量计算的重要性

向量计算基于嵌入模型生成的向量,执行诸如余弦相似度计算、欧几里得距离计算等操作,用于衡量向量之间的相似程度。在实际应用中,向量计算可实现高效的相似文档检索、相似问题匹配等功能。比如在问答系统中,通过计算用户问题向量与知识库中问题向量的相似度,快速找到最相关的答案,大大提升系统的响应效率和准确性。

1.3 LangChain中嵌入模型与向量计算的架构

LangChain对嵌入模型与向量计算的实现采用模块化设计,主要包含嵌入模型接口定义、具体嵌入模型实现类、向量存储接口及多种向量存储实现类、向量计算工具类等组件。这些组件相互协作,为开发者提供统一、灵活的使用方式。开发者可以根据具体需求,选择合适的嵌入模型和向量存储方案,轻松实现数据的嵌入和向量计算操作 。

二、嵌入模型接口定义与设计

在LangChain中,为了实现对不同嵌入模型的统一管理和调用,定义了一套标准的嵌入模型接口。该接口规范了嵌入模型应具备的基本方法,使得各种嵌入模型都能以一致的方式接入LangChain框架。

2.1 嵌入模型接口核心方法

LangChain中嵌入模型接口的核心方法是将输入数据转换为向量。以文本嵌入为例,接口中通常定义了类似embed_documentsembed_query的方法。embed_documents方法用于将多个文本(如文档集合)转换为向量列表,而embed_query方法专门用于将单个查询文本转换为向量 。

from abc import ABC, abstractmethod

class BaseEmbeddings(ABC):
    """嵌入模型基类,定义标准接口"""

    @abstractmethod
    def embed_documents(self, texts: list[str]) -> list[list[float]]:
        """
        将多个文本转换为向量列表
        :param texts: 文本列表
        :return: 每个文本对应的向量列表,每个向量是float类型的列表
        """
        pass

    @abstractmethod
    def embed_query(self, text: str) -> list[float]:
        """
        将单个查询文本转换为向量
        :param text: 单个文本
        :return: 对应的向量,是float类型的列表
        """
        pass
2.2 接口设计的优势

这种接口设计具有显著优势。首先,它实现了不同嵌入模型的解耦,开发者可以根据实际需求,如性能、精度、成本等因素,自由选择不同的嵌入模型实现类,如OpenAIEmbeddings、HuggingFaceEmbeddings等。其次,统一的接口使得代码具有良好的扩展性和可维护性,当需要引入新的嵌入模型时,只需实现该接口,即可无缝集成到LangChain框架中,无需对上层应用代码进行大规模修改。

2.3 接口与具体实现的关系

接口定义了行为规范,而具体的嵌入模型实现类则负责实现这些规范。以OpenAIEmbeddings为例,它继承自BaseEmbeddings,并实现了embed_documentsembed_query方法,通过调用OpenAI的API完成文本到向量的转换 。

import openai
from typing import List

class OpenAIEmbeddings(BaseEmbeddings):
    def __init__(self, openai_api_key: str):
        self.openai_api_key = openai_api_key
        openai.api_key = self.openai_api_key

    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        """
        调用OpenAI API将多个文本转换为向量
        :param texts: 文本列表
        :return: 向量列表
        """
        response = openai.Embedding.create(
            input=texts,
            model="text-embedding-ada-002"
        )
        return [data['embedding'] for data in response['data']]

    def embed_query(self, text: str) -> List[float]:
        """
        调用OpenAI API将单个查询文本转换为向量
        :param text: 单个文本
        :return: 对应的向量
        """
        return self.embed_documents([text])[0]

三、常见嵌入模型实现分析

LangChain支持多种嵌入模型,这些模型各有特点,适用于不同的应用场景。下面对几种常见的嵌入模型实现进行深入分析。

3.1 OpenAIEmbeddings实现

OpenAIEmbeddings是基于OpenAI的嵌入服务实现的嵌入模型类。它通过调用OpenAI提供的API,利用预训练好的模型(如text-embedding-ada-002)将文本转换为高质量的向量表示 。

在实现过程中,OpenAIEmbeddings类在初始化时接收openai_api_key参数,用于进行API认证。embed_documentsembed_query方法内部通过构造API请求参数,向OpenAI的API发送请求,获取嵌入向量。该方式的优点是嵌入质量高,适用于对精度要求较高的场景;缺点是需要付费使用,且依赖外部API,存在网络延迟和API调用限制等问题 。

3.2 HuggingFaceEmbeddings实现

HuggingFaceEmbeddings利用Hugging Face生态中的预训练模型实现文本嵌入。开发者可以根据需求选择不同的模型,如sentence-transformers系列模型。在实现上,HuggingFaceEmbeddings类初始化时接收模型名称、模型路径等参数,用于加载本地或远程的预训练模型 。

from transformers import AutoTokenizer, AutoModel
import torch
import numpy as np
from typing import List

class HuggingFaceEmbeddings(BaseEmbeddings):
    def __init__(self, model_name: str, model_kwargs: dict = {}):
        self.model_name = model_name
        self.tokenizer = AutoTokenizer.from_pretrained(model_name)
        self.model = AutoModel.from_pretrained(model_name, **model_kwargs)
        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self.model.to(self.device)

    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        """
        使用Hugging Face模型将多个文本转换为向量
        :param texts: 文本列表
        :return: 向量列表
        """
        all_embeddings = []
        for text in texts:
            inputs = self.tokenizer(text, return_tensors="pt", truncation=True, padding=True).to(self.device)
            with torch.no_grad():
                outputs = self.model(**inputs)
                embeddings = torch.mean(outputs.last_hidden_state, dim=1).squeeze().cpu().numpy()
                all_embeddings.append(embeddings.tolist())
        return all_embeddings

    def embed_query(self, text: str) -> List[float]:
        """
        使用Hugging Face模型将单个查询文本转换为向量
        :param text: 单个文本
        :return: 对应的向量
        """
        return self.embed_documents([text])[0]

该方式的优势在于开源免费,可选择的模型丰富,且支持本地部署,能够避免外部API调用的限制和费用;不足之处在于部分模型的嵌入效果可能不如商业模型,且模型加载和推理可能占用较多本地资源。

3.3 CohereEmbeddings实现

CohereEmbeddings基于Cohere的嵌入服务,类似于OpenAIEmbeddings,通过调用Cohere的API实现文本嵌入。在初始化时,需要传入Cohere的API密钥和选择的模型名称。embed_documentsembed_query方法同样是构造API请求,获取向量结果 。Cohere的嵌入服务在某些自然语言处理任务中表现出色,提供了一种除OpenAI之外的商业嵌入选择,但同样存在API调用成本和网络依赖问题。

四、向量存储接口与实现

向量存储是LangChain中用于存储和管理嵌入向量的重要模块。它提供了一系列接口和实现类,方便开发者根据实际需求选择合适的存储方式。

4.1 向量存储接口定义

LangChain定义了向量存储的通用接口,主要包含添加向量、根据向量查询相似向量、根据文本查询相似向量等方法。这些接口为不同的向量存储实现提供了统一的操作规范 。

from abc import ABC, abstractmethod
from typing import List, Optional

class VectorStore(ABC):
    """向量存储基类,定义标准接口"""

    @abstractmethod
    def add_embeddings(self, embeddings: List[List[float]], metadatas: Optional[List[dict]] = None) -> List[str]:
        """
        添加向量及相关元数据
        :param embeddings: 向量列表
        :param metadatas: 每个向量对应的元数据列表,可选
        :return: 每个向量的唯一标识列表
        """
        pass

    @abstractmethod
    def similarity_search_by_vector(self, embedding: List[float], k: int = 4) -> List:
        """
        根据向量查询相似向量
        :param embedding: 目标向量
        :param k: 返回的相似向量数量
        :return: 相似向量及其相关元数据列表
        """
        pass

    @abstractmethod
    def similarity_search(self, text: str, k: int = 4) -> List:
        """
        根据文本查询相似向量(先将文本转换为向量再查询)
        :param text: 输入文本
        :param k: 返回的相似向量数量
        :return: 相似向量及其相关元数据列表
        """
        pass

4.2 Chroma向量存储实现

Chroma是一种基于Python的轻量级向量存储库,在LangChain中得到广泛应用。Chroma类实现了VectorStore接口,它在内部维护一个向量数据库,用于存储向量和对应的元数据 。

在添加向量时,Chroma将向量和元数据存储到数据库中,并为每个向量生成唯一标识。在查询相似向量时,Chroma利用向量数据库的索引和查询功能,基于余弦相似度等算法,快速检索出与目标向量相似的向量。Chroma的优点是使用简单、性能较好,适合小型应用和快速原型开发;但在大规模数据存储和分布式场景下,可能存在一定的局限性。

4.3 FAISS向量存储实现

FAISS(Facebook AI Similarity Search)是一个高效的向量相似性搜索库。LangChain中的FAISS类同样实现了VectorStore接口,它基于FAISS库强大的向量索引和搜索功能,能够快速处理大规模向量数据 。

import faiss
import numpy as np
from typing import List, Optional

class FAISS(VectorStore):
    def __init__(self, embeddings: List[List[float]], metadatas: Optional[List[dict]] = None):
        self.embeddings = np.array(embeddings).astype('float32')
        self.d = self.embeddings.shape[1]
        self.index = faiss.IndexFlatL2(self.d)
        self.index.add(self.embeddings)
        self.metadatas = metadatas or []

    def add_embeddings(self, embeddings: List[List[float]], metadatas: Optional[List[dict]] = None) -> List[str]:
        """
        添加向量及元数据到FAISS索引
        :param embeddings: 向量列表
        :param metadatas: 元数据列表
        :return: 向量唯一标识列表(这里简单用索引表示)
        """
        new_embeddings = np.array(embeddings).astype('float32')
        self.index.add(new_embeddings)
        if metadatas:
            self.metadatas.extend(metadatas)
        return [str(i) for i in range(len(self.embeddings), len(self.embeddings) + len(embeddings))]

    def similarity_search_by_vector(self, embedding: List[float], k: int = 4) -> List:
        """
        根据向量在FAISS索引中查询相似向量
        :param embedding: 目标向量
        :param k: 返回数量
        :return: 相似向量及其元数据列表
        """
        query = np.array([embedding]).astype('float32')
        distances, indices = self.index.search(query, k)
        results = []
        for i in range(k):
            result_index = indices[0][i]
            result = {
                "embedding": self.embeddings[result_index].tolist(),
                "metadata": self.metadatas[result_index] if self.metadatas else {}
            }
            results.append(result)
        return results

    def similarity_search(self, text: str, k: int = 4) -> List:
        """
        先将文本转换为向量,再在FAISS索引中查询相似向量
        :param text: 输入文本
        :param k: 返回数量
        :return: 相似向量及其元数据列表
        """
        # 假设这里有嵌入模型将text转换为向量
        embedding = [1.0] * self.d  # 示例向量,实际需替换
        return self.similarity_search_by_vector(embedding, k)

在初始化时,FAISS类根据传入的向量数据构建FAISS索引结构,如FlatL2索引。在查询时,利用FAISS的高效搜索算法,快速返回与目标向量最相似的k个向量及其元数据。FAISS在处理大规模高维向量数据时表现优异,常用于生产环境中的大规模向量存储和检索场景。

五、向量计算核心算法实现

向量计算是基于嵌入向量进行相似度衡量等操作的关键环节。LangChain中实现了多种常用的向量计算算法,下面对余弦相似度计算和欧几里得距离计算进行深入分析。

5.1 余弦相似度计算

余弦相似度通过计算两个向量之间夹角的余弦值来衡量它们的相似程度,取值范围在[-1, 1]之间,值越接近1表示向量越相似。在LangChain中,余弦相似度计算的实现通常如下:

import numpy as np

def cosine_similarity(vec1: list[float], vec2: list[float]) -> float:
    """
    计算两个向量的余弦相似度
    :param vec1: 向量1
    :param vec2: 向量2
    :return: 余弦相似度值
    """
    vec1 = np.array(vec1)
    vec2 = np.array(vec2)
    numerator = np.dot(vec1, vec2)
    denominator = np.linalg.norm(vec1) * np.linalg.norm(vec2)
    return numerator / denominator if denominator != 0 else 0

在实际应用中,如在向量存储的相似性查询中,会对目标向量和存储的多个向量依次计算余弦相似度,然后根据相似度值进行排序,返回最相似的向量。余弦相似度计算的优势在于不受向量长度的影响,更关注向量的方向,适合用于文本语义相似性的衡量。

5.2 欧几里得距离计算

欧几里得距离是计算两个向量在空间中的直线距离,距离越近表示向量越相似。在LangChain中的实现方式如下:

import numpy as np

def euclidean_distance(vec1: list[float], vec2: list[float]) -> float:
    """
    计算两个向量的欧几里得距离
    :param vec1: 向量1
    :param vec2: 向量2
    :return: 欧几里得距离值
    """
    vec1 = np.array(vec1)
    vec2 = np.array(vec2)
    return np.linalg.norm(vec1 - vec2)

在向量检索场景中,通过计算目标向量与所有存储向量的欧几里得距离,按照距离从小到大排序,选取距离最小的若干个向量作为相似向量返回。欧几里得距离计算简单直观,但对向量的尺度比较敏感,在使用时可能需要进行归一化等预处理操作。

六、嵌入模型与向量存储的集成流程

在LangChain中,嵌入模型与向量存储的集成是实现高效信息检索和处理的关键步骤。下面详细分析其集成流程。

6.1 初始化嵌入模型

首先,根据具体需求选择合适的嵌入模型并进行初始化。例如,若选择OpenAIEmbeddings,需要传入OpenAI的API密钥:

from langchain.embeddings import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(openai_api_key="your_api_key")

若选择HuggingFaceEmbeddings,则需指定模型名称:

from langchain.embeddings import HuggingFaceEmbeddings

embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")

6.2 准备数据并生成向量

接着,准备需要处理的数据,如文本数据。然后利用初始化好的嵌入模型,通过embed_documents方法将数据转换

六、嵌入模型与向量存储的集成流程(续)

6.2 准备数据并生成向量(续)

接着,准备需要处理的数据,如文本数据。然后利用初始化好的嵌入模型,通过embed_documents方法将数据转换为向量。假设我们有一个包含多篇文档的列表 texts

texts = [
    "这是第一篇文档的内容",
    "第二篇文档描述了不同的信息",
    "第三篇文档探讨相关主题"
]
embeddings = OpenAIEmbeddings(openai_api_key="your_api_key")
vector_list = embeddings.embed_documents(texts)

在这个过程中,嵌入模型会根据其内部的算法和参数,将每篇文档映射到对应的向量表示。不同的嵌入模型在生成向量的维度、精度和计算效率上可能有所差异,开发者需要根据实际需求和资源情况进行选择 。

6.3 初始化向量存储

生成向量后,需要选择合适的向量存储方式并进行初始化。以Chroma为例,创建一个新的Chroma向量存储实例:

from langchain.vectorstores import Chroma

vector_store = Chroma.from_embeddings(
    embedding=embeddings,
    texts=texts
)

上述代码中,from_embeddings 方法会自动调用嵌入模型将 texts 转换为向量,并将向量和原始文本(可用于后续检索展示等)存储到Chroma中。如果使用FAISS,初始化过程类似:

from langchain.vectorstores import FAISS

vector_store = FAISS.from_texts(
    texts=texts,
    embedding=embeddings
)

FAISS会根据传入的文本和嵌入模型生成向量,并构建内部的向量索引结构,为后续的高效检索做准备。不同的向量存储在数据存储格式、索引构建方式和检索性能上存在差异,选择时需要综合考虑数据规模、查询频率、存储资源等因素 。

6.4 数据添加与索引构建

在向量存储初始化后,数据会被添加到存储中,并构建相应的索引。以Chroma为例,其内部会维护一个向量数据库,将传入的向量和相关元数据(如原始文本)进行存储,并为每个向量生成唯一标识。同时,Chroma会根据数据特点构建合适的索引,以便快速进行相似性查询 。
对于FAISS,在 from_texts 方法内部,会先将文本转换为向量,然后使用FAISS库的函数构建向量索引,如常见的FlatL2索引。FAISS的索引构建过程会根据数据的维度、数量等进行优化,以确保在大规模数据下仍能实现高效的相似向量检索 。

6.5 相似性查询与结果处理

完成数据存储和索引构建后,就可以进行相似性查询。假设用户输入一个查询文本,首先使用嵌入模型的 embed_query 方法将其转换为向量:

query_text = "查询相关内容"
query_vector = embeddings.embed_query(query_text)

然后,利用向量存储的 similarity_search_by_vectorsimilarity_search 方法进行查询。以Chroma为例:

results = vector_store.similarity_search_by_vector(
    embedding=query_vector,
    k=2
)

上述代码会在Chroma存储中查找与 query_vector 最相似的2个向量,并返回对应的原始文本和相关元数据。FAISS的查询过程类似,但其内部会利用构建好的高效索引,通过余弦相似度或欧几里得距离等计算方式,快速找到最相似的向量 。
在得到查询结果后,开发者可以根据具体应用需求进行处理,如将最相似的文档内容作为答案返回给用户,或者进一步对结果进行筛选、排序和整合等操作。

七、嵌入模型与向量计算的性能优化

在实际应用中,嵌入模型与向量计算的性能对系统整体表现有着重要影响。以下从多个方面分析性能优化的策略和源码实现原理。

7.1 批量处理优化

在嵌入模型生成向量时,通过批量处理可以减少API调用次数或模型推理次数,从而提升效率。以OpenAIEmbeddings为例,embed_documents 方法本身就支持传入多个文本进行批量转换:

class OpenAIEmbeddings(BaseEmbeddings):
    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        response = openai.Embedding.create(
            input=texts,
            model="text-embedding-ada-002"
        )
        return [data['embedding'] for data in response['data']]

上述代码中,将整个文本列表 texts 作为 input 参数一次性传入OpenAI API,相比逐个文本调用API,大大减少了网络请求开销和等待时间。在向量存储的添加操作中,同样可以利用批量处理,如Chroma的 add_embeddings 方法可以一次性添加多个向量和元数据,减少存储操作的次数 。

7.2 索引优化

向量存储的索引结构对查询性能起着关键作用。以FAISS为例,它提供了多种索引类型,如FlatL2、HNSW等。在LangChain的FAISS实现中,根据数据特点选择合适的索引类型可以显著提升查询效率。例如,在处理大规模高维向量数据时,HNSW索引通常比FlatL2索引具有更好的查询性能 。

import faiss
from langchain.vectorstores import FAISS

# 使用HNSW索引
index = faiss.HNSW(d=64, m=16)  # 假设向量维度为64
vector_store = FAISS(embeddings=vector_list, index=index)

上述代码中,通过创建HNSW索引实例并传入FAISS向量存储的初始化方法,使得FAISS在存储和查询向量时使用HNSW索引结构。HNSW索引通过层次化的图结构,能够在大规模数据中快速定位相似向量,减少查询时间复杂度 。

7.3 缓存机制

引入缓存机制可以避免重复计算。在嵌入模型的使用过程中,如果相同文本经常需要转换为向量,可以缓存已经计算过的结果。例如,自定义一个简单的缓存装饰器:

from functools import wraps
from typing import Dict, List

text_embedding_cache: Dict[str, List[float]] = {}

def cache_embeddings(func):
    @wraps(func)
    def wrapper(self, text: str):
        if text in text_embedding_cache:
            return text_embedding_cache[text]
        result = func(self, text)
        text_embedding_cache[text] = result
        return result
    return wrapper

class CachedOpenAIEmbeddings(OpenAIEmbeddings):
    @cache_embeddings
    def embed_query(self, text: str) -> List[float]:
        return super().embed_query(text)

上述代码中,通过 cache_embeddings 装饰器为 embed_query 方法添加了缓存功能。当再次调用 embed_query 处理相同文本时,直接从缓存中获取结果,避免了重复的API调用和计算,提升了响应速度 。在向量存储的查询环节,也可以对频繁查询的结果进行缓存,减少重复检索的开销 。

7.4 硬件加速

利用GPU等硬件资源可以加速嵌入模型的计算和向量计算过程。对于基于深度学习的嵌入模型,如HuggingFaceEmbeddings,在有GPU支持的环境下,可以将模型和数据移动到GPU上进行计算:

import torch
from transformers import AutoTokenizer, AutoModel
from langchain.embeddings import HuggingFaceEmbeddings

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model_name = "sentence-transformers/all-MiniLM-L6-v2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name).to(device)

class GPUHuggingFaceEmbeddings(HuggingFaceEmbeddings):
    def __init__(self):
        super().__init__(model_name=model_name)
        self.model.to(device)

    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        all_embeddings = []
        for text in texts:
            inputs = tokenizer(text, return_tensors="pt", truncation=True, padding=True).to(device)
            with torch.no_grad():
                outputs = self.model(**inputs)
                embeddings = torch.mean(outputs.last_hidden_state, dim=1).squeeze().cpu().numpy()
                all_embeddings.append(embeddings.tolist())
        return all_embeddings

上述代码中,通过 torch.device 判断是否有可用的GPU,并将模型和输入数据移动到GPU上进行计算。由于GPU具有强大的并行计算能力,能够大幅提升嵌入模型的推理速度,尤其在处理大规模文本数据时效果显著 。在向量计算中,一些支持GPU加速的库,如CuPy(CUDA版本的NumPy),也可以用于加速余弦相似度、欧几里得距离等计算 。

八、嵌入模型与向量计算的应用场景

LangChain中嵌入模型与向量计算的组合在多种场景下有着广泛应用,下面详细分析不同场景下的实现方式和优势。

8.1 问答系统

在问答系统中,嵌入模型与向量计算是实现高效检索答案的核心技术。首先,将知识库中的问题和答案转换为向量并存储到向量存储中。例如,使用OpenAIEmbeddings和Chroma构建问答系统的向量存储:

from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma

# 假设questions和answers是对应的问题和答案列表
questions = ["问题1", "问题2"]
answers = ["答案1", "答案2"]

embeddings = OpenAIEmbeddings(openai_api_key="your_api_key")
vector_store = Chroma.from_texts(
    texts=questions,
    embedding=embeddings,
    metadatas=[{"answer": answer} for answer in answers]
)

当用户提出问题时,将问题转换为向量并在向量存储中进行相似性查询:

user_question = "用户提问"
question_vector = embeddings.embed_query(user_question)
results = vector_store.similarity_search_by_vector(
    embedding=question_vector,
    k=1
)
if results:
    answer = results[0].metadata["answer"]
    print(answer)

通过这种方式,问答系统能够快速从知识库中找到与用户问题最相似的问题,并返回对应的答案,提升了问答的准确性和效率 。

8.2 文档检索

在处理大量文档时,嵌入模型与向量计算可以实现高效的文档检索功能。将文档内容转换为向量并存储到向量存储中,如使用HuggingFaceEmbeddings和FAISS:

from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS

# 假设documents是文档内容列表
documents = ["文档1内容", "文档2内容"]
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
vector_store = FAISS.from_texts(
    texts=documents,
    embedding=embeddings
)

当用户输入检索关键词时,将关键词转换为向量并查询相似文档:

search_keyword = "检索关键词"
keyword_vector = embeddings.embed_query(search_keyword)
results = vector_store.similarity_search_by_vector(
    embedding=keyword_vector,
    k=3
)
for result in results:
    print(result.page_content)  # 假设page_content存储文档内容

这种基于向量的文档检索方式能够理解关键词的语义,返回语义相关的文档,相比传统的关键词匹配检索方式,具有更高的准确性和召回率 。

8.3 推荐系统

在推荐系统中,嵌入模型与向量计算可以用于计算用户兴趣和物品之间的相似度。例如,将用户的历史行为数据(如浏览记录、购买记录等)转换为用户兴趣向量,将物品信息转换为物品向量。然后使用向量存储和计算找到与用户兴趣最相似的物品进行推荐 。
假设使用OpenAIEmbeddings将用户行为和物品描述转换为向量,使用Chroma进行存储和查询:

# 用户行为数据和物品描述
user_behaviors = ["用户行为1", "用户行为2"]
item_descriptions = ["物品1描述", "物品2描述"]

embeddings = OpenAIEmbeddings(openai_api_key="your_api_key")
user_vector_store = Chroma.from_texts(
    texts=user_behaviors,
    embedding=embeddings,
    metadatas=[{"user_id": 1}, {"user_id": 2}]
)
item_vector_store = Chroma.from_texts(
    texts=item_descriptions,
    embedding=embeddings,
    metadatas=[{"item_id": 1}, {"item_id": 2}]
)

# 为用户1推荐物品
user_1_vector = user_vector_store.similarity_search("用户行为1", k=1)[0].embedding
recommended_items = item_vector_store.similarity_search_by_vector(
    embedding=user_1_vector,
    k=1
)
for item in recommended_items:
    print(f"推荐物品ID: {item.metadata['item_id']}")

通过这种方式,推荐系统能够基于用户的语义兴趣进行个性化推荐,提升用户体验和推荐效果 。

九、嵌入模型与向量计算的安全性与隐私保护

在实际应用中,嵌入模型与向量计算涉及的数据可能包含敏感信息,因此安全性和隐私保护至关重要。以下从数据传输、存储和计算等环节分析相关的保护措施和原理。

9.1 数据传输安全

在嵌入模型调用API或向量存储进行数据交互时,数据传输过程需要进行加密保护。以OpenAIEmbeddings调用OpenAI API为例,使用HTTPS协议进行通信,确保数据在传输过程中不被窃取或篡改 。在LangChain的代码实现中,OpenAI的Python SDK会自动处理HTTPS连接:

import openai
from langchain.embeddings import OpenAIEmbeddings

openai.api_key = "your_api_key"
embeddings = OpenAIEmbeddings()

在上述代码背后,OpenAI SDK在发送请求时会建立安全的HTTPS连接,对请求数据进行加密传输。对于自定义的向量存储数据传输,也可以使用SSL/TLS等加密协议,保证数据在网络传输过程中的安全性 。

9.2 数据存储安全

向量存储中的数据需要进行安全存储。对于敏感数据,可以采用加密存储的方式。以Chroma为例,可以通过在存储数据前对向量和元数据进行加密处理,然后在查询时进行解密。例如,使用Python的加密库 cryptography 对数据进行加密:

from cryptography.fernet import Fernet
from langchain.vectorstores import Chroma

# 生成加密密钥
key = Fernet.generate_key()
cipher_suite = Fernet(key)

# 假设texts是要存储的文本,先加密再存储
texts = ["敏感文本1", "敏感文本2"]
encrypted_texts = [cipher_suite.encrypt(text.encode()) for text in texts]

embeddings = OpenAIEmbeddings(openai_api_key="your_api_key")
vector_store = Chroma.from_texts(
    texts=encrypted_texts,
    embedding=embeddings
)

# 查询时解密
query_text = "敏感查询"
encrypted_query = cipher_suite.encrypt(query_text.encode())
query_vector = embeddings.embed_query(encrypted_query.decode())
results = vector_store.similarity_search_by_vector(
    embedding=query_vector,
    k=1
)
if results:
    decrypted_result = cipher_suite.decrypt(results[0].page_content).decode()
    print(decrypted_result)

上述代码中,通过 cryptography 库对文本数据进行加密和解密,确保数据在向量存储中以密文形式存在,即使存储被攻击,攻击者也无法直接获取敏感信息 。

9.3 计算过程隐私保护

在嵌入模型计算和向量计算过程中,也需要考虑隐私保护。例如,在使用基于深度学习的嵌入模型时,模型训练和推理过程可能会泄露用户数据。为了保护隐私,可以采用联邦学习、差分隐私等技术 。
以差分隐私为例,在嵌入模型生成向量时,可以在计算结果中添加一定的噪声,以保护原始数据的隐私。在LangChain中,可以自定义嵌入模型类并添加差分隐私机制:

import numpy as np
from langchain.embeddings import BaseEmbeddings

class DifferentialPrivacyEmbeddings(BaseEmbeddings):
    def __init__(self, base_embeddings: BaseEmbeddings, epsilon: float = 1.0):
        self.base_embeddings = base_embeddings
        self.epsilon = epsilon

    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        original_embeddings = self.base_embeddings.embed_documents(texts)
        noisy_embeddings = []
        for embedding in original_embeddings:
            noise = np.random.laplace(0, 1 / self.epsilon, len(embedding))
            noisy_embedding = [e + n for e, n in zip(embedding, noise)]
            noisy_embeddings.append(noisy_embedding)
        return noisy_embeddings

    def embed_query(self, text: str) -> List[float]:
        original_embedding = self.base_embeddings.embed_query(text)
        noise = np.random.laplace(0, 1 / self.epsilon, len(original_embedding))
        return [e + n for e, n in zip(original
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Android 小码蜂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值