使用 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 限制和最佳实践
计费说明
Vectorize 的计费基于以下两个指标:
- 查询向量维度数:所有查询操作涉及的向量维度总数。例如,索引中有 10,000 个 384 维向量,进行 100 次查询,则总查询维度为
(10000 + 100) * 384 = 3,878,400
,价格约 $0.05/每 1 亿查询维度。 - 存储向量维度数:索引中存储的所有向量维度总数。例如,索引中有 1,000 个 1536 维向量,则总存储维度为
1000 * 1536 = 1,536,000
,价格约 $0.01/每 1 百万存储维度。
Cloudflare 不对 CPU、内存、索引数量或“活跃索引小时”计费。只有实际查询时才会产生查询维度费用,未查询则不计费。详见 Vectorize 计费文档。对于个人开发者,几千个向量的存储和查询通常在免费额度内。对于生产环境,建议定期监控使用情况,避免超出免费额度。
以下是关于 Vectorize 计费的要点:
- Vectorize 始终有免费额度,适合原型和实验。
- 超出免费额度后,按实际查询和存储维度计费。
- 不对数据传输/出口计费。
- 通过 HTTP API、Wrangler CLI 或 Workers API 查询均计入用量。
- 空索引(无向量)不计入存储费用。
最佳实践
在使用 Cloudflare Vectorize 时,遵循以下最佳实践可以帮助你更高效地构建和管理向量数据库:
选择合适的维度:维度大小应与使用的嵌入模型输出一致,较小的维度搜索更快,较大的维度更准确。
合理使用元数据:为向量添加有用的元数据,如文档 URL、标题、语言等,便于后续检索和过滤。
批量操作:尽可能使用批量插入/更新操作,提高效率。
异步处理:考虑到插入操作的异步特性,在需要立即查询刚插入的向量时,应适当等待。
命名空间使用:使用命名空间来隔离不同类型的向量,如按客户、产品类别等划分。
元数据索引规划:提前规划需要过滤的元数据字段,并创建相应的索引。
通过合理使用这些功能和遵循最佳实践,你可以构建一个高效、可扩展的 RAG 系统,充分利用 Cloudflare Vectorize 提供的全球分布式向量数据库能力。
小结
通过本节的介绍,您已经了解了如何使用 Cloudflare Vectorize 构建 RAG 系统的向量数据库。我们详细讲解了索引创建、向量操作、元数据索引等关键功能,并提供了最佳实践建议。接下来,您可以将这些知识应用到实际项目中,构建高性能的向量存储和检索系统,为智能问答和内容发现提供强大支持。