【LangChain框架入门级】10. 文本向量与向量数据库(Embedding / Redis / Pinecone / MMR)

文本向量与向量数据库(Embedding / Redis / Pinecone / MMR)

文档切好之后,要把文字变成计算机能比较「语义相似度」的数字------这就是文本向量(Embedding) ;而存储、检索这些向量的地方,就是向量数据库 。

本篇讲解:向量、维度、向量空间与余弦相似度,OpenAI 嵌入模型的用法,以及 InMemory、Redis、Pinecone 三种向量存储和三种搜索方式。

目录

  1. 什么是文本向量(Embedding)
  2. 向量、维度、向量空间
  3. 余弦相似度
  4. OpenAIEmbeddings 嵌入模型
  5. embed_documents 与 embed_query
  6. 向量存储(Vector stores)概念
  7. InMemory 内存向量存储
  8. Redis 向量存储
  9. Pinecone 向量存储
  10. 相似性搜索 similarity_search
  11. 元数据过滤搜索
  12. MMR 最大边际相关性搜索
  13. 本篇小结

1. 什么是文本向量(Embedding)

文本向量是一种文本表示技术,把文本(单词、句子、文档)映射为高维空间中的实数向量,让计算机能捕捉文本的语义信息。

核心思想:语义相似的文本,在向量空间中距离也相近。

例如「猫」和「狗」都是宠物,向量距离很近;「猫」和「汽车」语义无关,距离很远。

嵌入模型(Embedding model)就是干这个的:输入一段文本,输出一串固定长度的数字。


2. 向量、维度、向量空间

  • 向量 :一串有序数字,例如 [0.12, -0.45, 0.78, ...]。
  • 维度:向量里数字的个数。维度越高,能表达的语义信息越丰富,但计算和存储成本也越高。
  • 向量空间:所有向量所处的数学空间。可以想象成一张地图,每个词、每句话都是地图上的一个点,语义相近的点聚在一起。

例如 OpenAI 的 text-embedding-3-large 输出 3072 维向量,text-embedding-3-small 输出 1536 维。


3. 余弦相似度

衡量两个向量「方向是否一致」最常用的指标是余弦相似度(Cosine Similarity)。

公式:

复制代码
            A · B                Σ(Aᵢ × Bᵢ)
cos(θ) = ─────────── = ─────────────────────────────
          |A| × |B|      √(ΣAᵢ²)  ×  √(ΣBᵢ²)
  • 取值范围:[-1, 1]。
  • 1:方向完全相同(语义高度相似)。
  • 0:方向正交(语义无关)。
  • -1:方向完全相反。

大白话:余弦相似度不关心向量长短,只关心两个向量「指向」是否一致,指向越接近,文本语义越相似。这也是向量库里最常用的距离度量。


4. OpenAIEmbeddings 嵌入模型

bash 复制代码
pip install -U langchain-openai
python 复制代码
from langchain_openai import OpenAIEmbeddings

# 定义嵌入模型
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")

常用参数:

  • model:嵌入模型名称。
  • dimensions:可指定输出维度(部分模型支持缩短向量)。
  • api_key / base_url:与 ChatOpenAI 类似,可接入兼容的嵌入服务。

国产模型同样提供 OpenAI 兼容的嵌入接口,改 base_url 和密钥即可。


5. embed_documents 与 embed_query

两个核心方法:

python 复制代码
# embed_documents:批量把多个文本块转成向量(建库时用)
vector = embeddings.embed_documents(
    [
        "Hi there!",
        "Oh, hello!",
        "What's your name?",
        "My friends call me World",
        "Hello World!",
    ]
)

print(len(vector))       # 5:5 个文本
print(len(vector[0]))    # 3072:每个向量 3072 维
python 复制代码
# embed_query:把单个查询转成向量(检索时用)
single_vector = embeddings.embed_query("What's our Q1 revenue?")
print(len(single_vector))   # 3072

为什么要分两个方法?因为文档和查询在某些模型里的嵌入方式不同,分开接口语义更清晰:建库用 embed_documents,查询用 embed_query。


6. 向量存储(Vector stores)概念

向量存储负责:

  1. 用嵌入模型把文档块转成向量。
  2. 存储向量及对应文档、元数据。
  3. 根据查询向量做相似性搜索,返回最相关的文档。

LangChain 提供统一的 VectorStore 接口,支持 InMemory、Redis、Pinecone、Chroma 等多种实现,接口方法基本一致:

  • add_documents(documents):添加文档。
  • similarity_search(query, k):相似性搜索。
  • max_marginal_relevance_search(...):MMR 搜索。
  • delete(ids / delete_all):删除文档。
  • as_retriever():转成检索器(下一篇讲)。

7. InMemory 内存向量存储

最简单、无需任何外部服务,数据存在内存里,适合学习和小规模原型。

python 复制代码
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings
from langchain_core.vectorstores import InMemoryVectorStore

embeddings = OpenAIEmbeddings(model="text-embedding-3-large")

# 定义文档
document_1 = Document(
    page_content="我今天早上吃了巧克力煎饼和炒鸡蛋。",
    metadata={"source": "tweet"},
)
document_2 = Document(
    page_content="天气预报:明天辽宁将有小雨,气温18-25度。",
    metadata={"source": "news"},
)
document_3 = Document(
    page_content="ChatAnthropic 接口初始化时 model 命名为 anthropic,api_key 从环境变量读取。",
    metadata={"source": "langchain docs"},
)

documents = [document_1, document_2, document_3]

# 初始化内存向量库
vector_store = InMemoryVectorStore(embeddings)

# 添加文档,返回文档 ID 列表
ids = vector_store.add_documents(documents=documents)
print(ids)

删除文档:

python 复制代码
# 全量删除
vector_store.delete(ids=ids)
# 或 result = vector_store.delete(delete_all=True)

8. Redis 向量存储

Redis 是生产中常用的内存数据库,通过 RediSearch / Redis Stack 支持向量检索,性能高、可持久化。

8.1 安装与准备

bash 复制代码
pip install -U langchain-redis

需要一个运行中的 Redis(带向量检索能力的 Redis Stack),连接形如 redis://host:port。

8.2 初始化

python 复制代码
from langchain_openai import OpenAIEmbeddings
from langchain_redis import RedisConfig, RedisVectorStore

embeddings = OpenAIEmbeddings(model="text-embedding-3-large")

redis_url = "redis://192.168.100.238:6379"

config = RedisConfig(
    index_name="qa",            # 索引名,类似「表名」
    redis_url=redis_url,
    metadata_schema=[
        {"name": "category", "type": "tag"},       # tag:用于精确匹配
        {"name": "num", "type": "numeric"},        # numeric:用于数值比较
    ],
)

vector_store = RedisVectorStore(embeddings, config=config)

8.3 添加文档(含元数据)

python 复制代码
from langchain_community.document_loaders import UnstructuredMarkdownLoader
from langchain_text_splitters import CharacterTextSplitter

# 分割文档
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
    encoding_name="cl100k_base", chunk_size=200, chunk_overlap=50
)
data = UnstructuredMarkdownLoader("../Docs/Markdown/脚手架微服务租房平台Q&A.md").load()
documents = text_splitter.split_documents(data)

# 给每个块加元数据
for i, doc in enumerate(documents, start=1):
    doc.metadata["category"] = "QA"
    doc.metadata["num"] = i

ids = vector_store.add_documents(documents=documents)
print(f"共编排了{len(ids)}个文档索引")

删除:

python 复制代码
vector_store.delete(delete_all=True)
vector_store.delete(ids=delete_ids)

9. Pinecone 向量存储

Pinecone 是全托管的生产级向量数据库,负责后端维护、扩展、监控,用户无需自己运维。

9.1 注册与环境变量

  • 官网:https://www.pinecone.io/ (需科学上网),选择个人免费版。
  • 注册后保存 API Key,设置环境变量 PINECONE_API_KEY。
bash 复制代码
pip install -U pinecone langchain-pinecone

9.2 创建索引并初始化

python 复制代码
from langchain_openai import OpenAIEmbeddings
from langchain_pinecone import PineconeVectorStore
from pinecone import Pinecone, ServerlessSpec

pc = Pinecone()
index_name = "qa"

if not pc.has_index(index_name):
    pc.create_index(
        name=index_name,
        dimension=3072,                 # 维度必须和嵌入模型一致
        metric="cosine",                # 度量方式:余弦相似度
        spec=ServerlessSpec(
            cloud="aws",
            region="us-east-1",
        ),
    )

embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
index = pc.Index(index_name)

vector_store = PineconeVectorStore(embedding=embeddings, index=index)

添加、删除文档的方法与 Redis 完全一致(add_documents / delete),控制台可以看到写入的记录。

选型:学习原型用 InMemory;已有 Redis 基础设施用 Redis;想全托管、免运维用 Pinecone。


传入查询,返回最相似的 k 个文档:

python 复制代码
results = vector_store.similarity_search(
    query="数据库表怎么设计的?",
    k=2,
)

for res in results:
    print(f"* {res.page_content[:100]}")
    print(f"* {res.metadata}")

想要带相似度分数,用 similarity_search_with_score:

python 复制代码
results = vector_store.similarity_search_with_score(
    query="数据库表怎么设计的?",
    k=2,
)
for doc, score in results:
    print(score, doc.page_content[:50])

11. 元数据过滤搜索

只在满足条件的文档里搜索,用 filter 参数。

Redis 中用字段条件:

python 复制代码
from langchain_redis import Tag, Num

category_is_qa = Tag("category") == "qa"
num_is_under_50 = Num("num") < 50
filter_condition = category_is_qa & num_is_under_50

results = vector_store.similarity_search(
    query="数据库表怎么设计的?",
    k=2,
    filter=filter_condition,
)

Pinecone 中直接传字典:

python 复制代码
results = vector_store.similarity_search(
    query="数据库表怎么设计的?",
    k=2,
    filter={"category": "QA"},
)

大白话:元数据过滤就像 SQL 里的 WHERE 条件,先筛范围、再做语义匹配。


12. MMR 最大边际相关性搜索

普通相似性搜索可能返回内容高度重复的几个块。MMR(最大边际相关性) 在「相关性」和「多样性」之间做平衡,避免结果同质化(原理见第 7 篇示例选择器)。

python 复制代码
mmr_results = vector_store.max_marginal_relevance_search(
    query="数据库表怎么设计的?",
    k=2,
    fetch_k=10,
    filter=filter_condition,
)

for doc in mmr_results:
    print(f"Content: {doc.page_content[:100]}...")
    print(f"Metadata: {doc.metadata}")

关键参数 fetch_k:MMR 是两阶段过程------

  1. 初步获取 :先按纯相似度从全库取最相似的 fetch_k 个候选(广撒网)。
  2. 重排筛选 :在这 fetch_k 个候选里,用 MMR 挑出既相关、彼此又不太相似的 k 个作为最终结果。

目的:保证相关性的前提下提升结果多样性。


13. 本篇小结

  1. 文本向量把文本映射成高维数字向量,语义相近则向量相近;维度是向量长度,向量空间是向量所处的「语义地图」。
  2. 余弦相似度衡量向量方向一致性,取值 -1,1,是最常用的相似度度量。
  3. OpenAIEmbeddings:embed_documents 批量建库、embed_query 单条查询。
  4. 三种向量库:InMemoryVectorStore(学习)、RedisVectorStore(自建、高性能)、PineconeVectorStore(全托管)。
  5. 统一方法:add_documents / similarity_search / delete。
  6. 三种搜索:
    • 相似性搜索(similarity_search,带分数用 with_score)。
    • 元数据过滤(filter,相当于 WHERE)。
    • MMR(max_marginal_relevance_search,fetch_k 先广撒网、再选 k 个多样化结果)。

下一篇是本系列收官篇------检索器(Retrievers)与 RAG 完整落地,把「检索 → 拼接提示 → 模型生成」整条链跑通。

相关推荐
benchmark_cc1 小时前
本地已有一年历史 K 线,第二天更新别只拉“昨天一天”
python·数据分析·pandas·量化交易·股票数据·quantdash
Omics Pro1 小时前
研究证实AI虚拟细胞可用于药物靶点发现
数据库·人工智能·算法·机器学习·自然语言处理
好奇的菜鸟1 小时前
GORM 入门(二):从 database/sql 平滑过渡到 GORM
数据库·sql
甜到心里的蛋糕1 小时前
云主机部署图片/视频管理系统的实践经验
python·音视频
小园子的小菜1 小时前
FastAPI 全方位入门实战:高性能 Python Web 框架开发指南
python·pycharm·fastapi
长春的KAKA2 小时前
GitLab 项目页面报 500 错误的完整修复记录:PostgreSQL 数据库损坏、统计表缺失及数据库迁移
数据库·postgresql·gitlab
Helix2502 小时前
Python爬虫零基础实战:3步抓取网页数据并导出Excel
爬虫·python·beautifulsoup·excel·python教程·requests·网页数据
平生幻2 小时前
unbuntu虚拟机确认python安装位置
开发语言·python
这个DBA有点耶2 小时前
关系数据库管理系统选型指南:四步决策框架与主流产品技术路线对比
数据库·sql·程序人生·mysql·database·dba