langchain学习总结-Embedding 学习总结

0 阅读4分钟

OpenAI Embedding 学习总结

一、什么是 Embedding(嵌入)?

Embedding 是将文本转换为数值向量的技术,它能够:

  • 将文本映射到高维向量空间
  • 保留文本的语义信息
  • 使相似的文本在向量空间中距离更近

应用场景

  • 语义搜索
  • 文档相似度计算
  • 推荐系统
  • 文档聚类
  • 问答系统

二、LangChain 中的 Embedding

1. 基础嵌入模型

LangChain 提供了多种嵌入模型的统一接口,常用模型包括:

  • OpenAI Embeddings: text-embedding-3-small, text-embedding-3-large
  • 千帆 Embeddings: Embedding-V1
  • 其他本地模型

核心方法

方法说明
embed_query(text)将单个查询文本转换为向量
embed_documents(texts)将多个文档文本批量转换为向量

三、示例代码与输出

示例 1:基础嵌入模型使用

import dotenv
import numpy as np
from langchain_community.embeddings import QianfanEmbeddingsEndpoint
from numpy.linalg import norm

dotenv.load_dotenv()

# 计算两个向量的余弦相似度
def cosine_similarity(vec1, vec2):
    dot_product = np.dot(vec1, vec2)
    norm_vec1 = norm(vec1)
    norm_vec2 = norm(vec2)
    return dot_product / (norm_vec1 * norm_vec2)

# 创建文本嵌入模型
embeddings = QianfanEmbeddingsEndpoint(model="Embedding-V1")

# 嵌入单个查询
query_vector = embeddings.embed_query("你好,我是一名学生")
print("查询向量维度:", len(query_vector))

# 批量嵌入文档
documents_vectors = embeddings.embed_documents([
    "你好,我是一名学生",
    "你好,我是一名老师",
    "你好,我是一名学生",  # 重复文本
])

print("文档向量数量:", len(documents_vectors))

# 计算相似度
sim1 = cosine_similarity(documents_vectors[0], documents_vectors[1])
sim2 = cosine_similarity(documents_vectors[0], documents_vectors[2])

print("向量1和向量2的相似度:", sim1)
print("向量1和向量3的相似度:", sim2)
预期输出:
查询向量维度: 1024
文档向量数量: 3
向量1和向量2的相似度: 0.9567
向量1和向量3的相似度: 1.0000

输出分析:

  • 向量维度为 1024(千帆 Embedding-V1 模型)
  • 相同文本的向量相似度为 1.0(完全相同)
  • 相似文本的向量相似度接近 1.0(语义相近)

四、CacheBackedEmbeddings(缓存嵌入)

是什么?

CacheBackedEmbeddings 是 LangChain 提供的带缓存功能的嵌入包装器,它能够:

  • 缓存已计算过的文本向量,避免重复调用 API
  • 节省时间和成本
  • 支持多种存储后端(本地文件、Redis 等)

有什么用?

优势说明
节省成本避免对相同文本重复调用付费 API
提升速度从缓存读取比调用 API 快得多
离线可用缓存后的文本可离线使用
一致性相同文本始终得到相同的向量

核心参数

CacheBackedEmbeddings.from_bytes_store(
    underlying_embeddings,    # 底层嵌入模型
    document_store,           # 存储后端
    namespace,                # 命名空间(区分不同缓存)
    query_embedding_cache=True # 是否缓存查询向量
)

五、示例代码与输出(带缓存)

示例 2:使用 CacheBackedEmbeddings

import dotenv
import numpy as np
from langchain_community.embeddings import QianfanEmbeddingsEndpoint
from langchain_classic.embeddings import CacheBackedEmbeddings
from langchain_classic.storage import LocalFileStore
from numpy.linalg import norm

dotenv.load_dotenv()

def cosine_similarity(vec1, vec2):
    dot_product = np.dot(vec1, vec2)
    norm_vec1 = norm(vec1)
    norm_vec2 = norm(vec2)
    return dot_product / (norm_vec1 * norm_vec2)

# 创建基础嵌入模型
embeddings = QianfanEmbeddingsEndpoint(model="Embedding-V1")

# 创建带缓存的嵌入模型
embeddings_with_cache = CacheBackedEmbeddings.from_bytes_store(
    embeddings,                      # 基础嵌入模型
    LocalFileStore("./cache/"),      # 本地文件存储
    namespace=embeddings.model,      # 使用模型名作为命名空间
    query_embedding_cache=True,      # 缓存查询向量
)

# 第一次调用 - 会请求 API 并缓存
query_vector = embeddings_with_cache.embed_query("你好,我是一名学生")
print("查询向量维度:", len(query_vector))

# 第二次调用相同文本 - 从缓存读取,不请求 API
query_vector_cached = embeddings_with_cache.embed_query("你好,我是一名学生")

# 批量嵌入(部分重复,会使用缓存)
documents_vectors = embeddings_with_cache.embed_documents([
    "你好,我是一名学生",  # 已缓存
    "你好,我是一名老师",  # 新文本
    "你好,我是一名学生",  # 已缓存
])

print("文档向量数量:", len(documents_vectors))

# 计算相似度
sim1 = cosine_similarity(documents_vectors[0], documents_vectors[1])
sim2 = cosine_similarity(documents_vectors[0], documents_vectors[2])

print("向量1和向量2的相似度:", sim1)
print("向量1和向量3的相似度:", sim2)
预期输出:
查询向量维度: 1024
文档向量数量: 3
向量1和向量2的相似度: 0.9567
向量1和向量3的相似度: 1.0000
缓存目录结构:
./cache/
└── Embedding-V1/
    ├── <hash1>  # "你好,我是一名学生" 的缓存
    └── <hash2>  # "你好,我是一名老师" 的缓存

六、余弦相似度原理

公式

cosine_similarity(A, B) = (A · B) / (||A|| × ||B||)

说明

  • A · B: 两个向量的点积
  • ||A||: 向量 A 的长度(模)
  • 取值范围: [-1, 1]
    • 1.0: 完全相同方向
    • 0.0: 正交(无关)
    • -1.0: 完全相反方向

在文本嵌入中的应用

  • 值越接近 1,文本语义越相似
  • 值越接近 0,文本语义越不相关

七、最佳实践

  1. 生产环境务必使用缓存:可节省 50%+ 的 API 调用
  2. 选择合适的存储后端
    • 本地开发:LocalFileStore
    • 生产环境:Redis 或数据库
  3. 命名空间管理:使用模型名或项目名作为 namespace
  4. 批量处理:优先使用 embed_documents 而非多次调用 embed_query