使用 Cloudflare Vectorize 构建向量数据库
Cloudflare Vectorize 是构建 RAG 系统的核心组件,它提供了全球分布的向量数据库服务,能够在边缘网络上实现高效的向量存储和检索。本章将详细介绍 Vectorize 的核心概念和功能特性,包括索引创建、向量操作、元数据索引等关键操作。我们将深入探讨如何在 RAG 系统中有效利用 Vectorize 的各种功能,从基础的向量插入和查询,到高级的元数据过滤和命名空间管理。通过本章的学习,您将掌握使用 Vectorize 构建高性能向量数据库的完整流程。
什么是 Cloudflare Vectorize
Cloudflare Vectorize 是 Cloudflare 提供的全球分布式向量数据库服务,专为 AI 应用程序设计。它允许你在 Cloudflare 的全球网络上存储和查询向量嵌入,为语义搜索、推荐系统、分类和异常检测等任务提供支持。
Vectorize 与 Cloudflare Workers 深度集成,使得构建和部署全栈 AI 应用变得简单高效。它支持与多种机器学习模型配合使用,包括 Cloudflare Workers AI、OpenAI、Cohere 等平台提供的模型。
Vectorize 在 RAG 系统中的作用
在 RAG(检索增强生成)系统中,Vectorize 扮演着关键角色:
- 向量存储:存储由嵌入模型生成的文档向量
- 相似度搜索:根据用户查询向量快速检索最相关的文档片段
- 元数据管理:存储与向量关联的元数据,如文档来源、时间戳等
- 高效检索:通过索引和优化算法提供快速的向量相似度搜索
创建 Vectorize 索引
在使用 Vectorize 之前,需要先创建一个索引。索引是 Vectorize 中存储向量的基本单位。
索引配置参数
创建索引时需要指定两个关键参数:
- 维度(Dimensions):向量的维度大小,必须与所使用的嵌入模型输出维度一致
- 距离度量(Distance Metric):用于计算向量相似度的度量方式
距离度量类型
Vectorize 支持三种距离度量方式:
- cosine(余弦相似度):测量向量间夹角的余弦值,范围为 [-1, 1],1 表示完全相同
- euclidean(欧氏距离):测量向量间的直线距离,0 表示完全相同
- dot-product(点积):负点积,负值越大或正值越小表示越相似
对于文本相似度搜索,通常推荐使用余弦相似度。
创建索引命令
使用 Wrangler CLI 创建索引:
npx wrangler vectorize create your-index-name --dimensions=NUM_DIMENSIONS --metric=SELECTED_METRIC
例如,如果你使用千问的 text-embedding-v4 模型(输出 1024 维向量):
npx wrangler vectorize create website-vectors --dimensions=1024 --metric=cosine
索引命名规范
良好的索引命名应具备以下特点:
- 使用小写字母和数字组合,长度不超过 32 个字符
- 以字母开头,使用连字符(-)代替空格
- 描述性强,如 “production-doc-search” 或 “dev-recommendation-engine”
绑定 Vectorize 到 Worker
创建索引后,需要将其绑定到 Cloudflare Worker 以在代码中使用。
在 wrangler.toml
文件中添加以下配置:
[[vectorize]]
binding = "VECTORIZE" # 在 Worker 中通过 env.VECTORIZE 访问
index_name = "website-vectors"
绑定名称必须是有效的 JavaScript 变量名,例如 VECTORIZE
、MY_INDEX
或 PROD_SEARCH_INDEX
。
在 Worker 代码中,可以通过 env.VECTORIZE
访问 Vectorize API:
export interface Env {
VECTORIZE: Vectorize;
}
向量操作详解
插入向量
使用 insert()
方法向索引中插入向量:
let vectorsToInsert = [
{
id: "doc-1-chunk-1",
values: [0.12, 0.45, 0.67, 0.89, /* ... 更多维度 ... */],
metadata: {
url: "/blog/post-1",
title: "文章标题",
chunkIndex: 0
}
},
{
id: "doc-1-chunk-2",
values: [0.23, 0.56, 0.34, 0.78, /* ... 更多维度 ... */],
metadata: {
url: "/blog/post-1",
title: "文章标题",
chunkIndex: 1
}
}
];
let inserted = await env.VECTORIZE.insert(vectorsToInsert);
需要注意的是,Vectorize 的插入操作是异步的,会返回一个变更标识符。插入的向量通常需要几秒钟才能在查询中可见。
如果尝试插入具有相同 ID 的向量,只有新 ID 的向量会被插入。
更新向量
使用 upsert()
方法插入或更新向量:
let vectorsToUpsert = [
{
id: "doc-1-chunk-1",
values: [0.15, 0.48, 0.70, 0.92, /* ... 更多维度 ... */],
metadata: {
url: "/blog/post-1",
title: "文章标题",
chunkIndex: 0,
updated: new Date().toISOString()
}
}
];
let upserted = await env.VECTORIZE.upsert(vectorsToUpsert);
Upsert 操作会插入索引中不存在的向量,覆盖已存在的同名向量。需要注意的是,upsert 不会合并或组合现有向量的值或元数据,而是完全替换。
查询向量
使用 query()
方法根据向量进行相似度搜索:
// 查询向量维度必须与索引维度匹配
let queryVector = [0.14, 0.46, 0.68, 0.90, /* ... 更多维度 ... */];
let matches = await env.VECTORIZE.query(queryVector);
可以通过配置选项控制查询结果:
let matches = await env.VECTORIZE.query(queryVector, {
topK: 5, // 返回最相似的 5 个结果
returnValues: true, // 返回向量值
returnMetadata: "all" // 返回所有元数据
});
查询结果示例:
{
"count": 5,
"matches": [
{
"score": 0.999909486,
"id": "doc-1-chunk-1",
"values": [0.15, 0.48, 0.70, 0.92, /* ... 更多维度 ... */],
"metadata": {
"url": "/blog/post-1",
"title": "文章标题",
"chunkIndex": 0,
"updated": "2025-07-31T10:00:00Z"
}
}
// ... 其他匹配项
]
}
根据 ID 查询向量
使用 queryById()
方法根据已存在的向量 ID 进行相似度搜索:
let matches = await env.VECTORIZE.queryById("some-vector-id");
获取向量信息
使用 getByIds()
方法根据 ID 获取向量:
let ids = ["doc-1-chunk-1", "doc-1-chunk-2"];
const vectors = await env.VECTORIZE.getByIds(ids);
删除向量
使用 deleteByIds()
方法删除指定 ID 的向量:
let idsToDelete = ["doc-1-chunk-1", "doc-1-chunk-2"];
const deleted = await env.VECTORIZE.deleteByIds(idsToDelete);
元数据索引
Vectorize 允许为向量添加元数据,并通过创建元数据索引来实现过滤查询。
创建元数据索引
npx wrangler vectorize create-metadata-index website-vectors --property-name=url --type=string
支持的元数据类型包括:
string
:字符串类型number
:数字类型boolean
:布尔类型
使用元数据过滤
在查询时可以使用元数据过滤:
let matches = await env.VECTORIZE.query(queryVector, {
topK: 5,
filter: {
url: { $eq: "/blog/post-1" }
},
returnMetadata: "all"
});
支持的过滤操作符:
$eq
:等于$ne
:不等于$in
:在指定数组中$nin
:不在指定数组中$lt
:小于$lte
:小于等于$gt
:大于$gte
:大于等于
Vectorize 限制和最佳实践
重要限制
根据 Cloudflare 官方文档,Vectorize 有以下重要限制:
特性 | 限制 |
---|---|
每个账户索引数量 | 50,000 (付费) / 100 (免费) |
向量最大维度 | 1536 维 |
向量精度 | 32 位浮点数 |
向量 ID 最大长度 | 64 字节 |
每个向量元数据 | 10KiB |
带值或元数据的最大返回结果 | 20 |
不带值和元数据的最大返回结果 | 100 |
每批次最大 upsert 数量 | 1000 (Workers) / 5000 (HTTP API) |
索引名称最大长度 | 64 字节 |
每个索引最大向量数 | 5,000,000 |
每个索引最大命名空间数 | 50,000 (付费) / 1000 (免费) |
最佳实践
选择合适的维度:维度大小应与使用的嵌入模型输出一致,较小的维度搜索更快,较大的维度更准确。
合理使用元数据:为向量添加有用的元数据,如文档 URL、标题、语言等,便于后续检索和过滤。
批量操作:尽可能使用批量插入/更新操作,提高效率。
异步处理:考虑到插入操作的异步特性,在需要立即查询刚插入的向量时,应适当等待。
命名空间使用:使用命名空间来隔离不同类型的向量,如按客户、产品类别等划分。
元数据索引规划:提前规划需要过滤的元数据字段,并创建相应的索引。
通过合理使用这些功能和遵循最佳实践,你可以构建一个高效、可扩展的 RAG 系统,充分利用 Cloudflare Vectorize 提供的全球分布式向量数据库能力。