使用 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 扮演着关键角色:

  1. 向量存储:存储由嵌入模型生成的文档向量
  2. 相似度搜索:根据用户查询向量快速检索最相关的文档片段
  3. 元数据管理:存储与向量关联的元数据,如文档来源、时间戳等
  4. 高效检索:通过索引和优化算法提供快速的向量相似度搜索

创建 Vectorize 索引

在使用 Vectorize 之前,需要先创建一个索引。索引是 Vectorize 中存储向量的基本单位。

索引配置参数

创建索引时需要指定两个关键参数:

  1. 维度(Dimensions):向量的维度大小,必须与所使用的嵌入模型输出维度一致
  2. 距离度量(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 变量名,例如 VECTORIZEMY_INDEXPROD_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 (免费)

最佳实践

  1. 选择合适的维度:维度大小应与使用的嵌入模型输出一致,较小的维度搜索更快,较大的维度更准确。

  2. 合理使用元数据:为向量添加有用的元数据,如文档 URL、标题、语言等,便于后续检索和过滤。

  3. 批量操作:尽可能使用批量插入/更新操作,提高效率。

  4. 异步处理:考虑到插入操作的异步特性,在需要立即查询刚插入的向量时,应适当等待。

  5. 命名空间使用:使用命名空间来隔离不同类型的向量,如按客户、产品类别等划分。

  6. 元数据索引规划:提前规划需要过滤的元数据字段,并创建相应的索引。

通过合理使用这些功能和遵循最佳实践,你可以构建一个高效、可扩展的 RAG 系统,充分利用 Cloudflare Vectorize 提供的全球分布式向量数据库能力。

文章导航

独立页面

这是书籍中的独立页面。

书籍首页