Skip to content

Cloudflare Serverless RAG 部署完整指南

本文梳理了在 Cloudflare 全家桶(Workers + Pages + D1 + Vectorize + Workers AI)上构建无服务器 RAG 知识检索系统的完整架构,以及实际部署过程中遇到的问题与正确操作流程,适合作为可复用的工程参考。

一、整体架构概览

用户提问 + 图片上传


Cloudflare Pages (静态前端)
        │  /api/* 服务绑定

Cloudflare Workers (panjiayuan-backend)

        ├─ /api/get-verdict  ──► [1] Vectorize 向量检索
        │                         [2] D1 SQL 精准点查
        │                         [3] 返回结构化 JSON

        ├─ /api/analyze-bracelet ──► [RAG Context 注入]
        │                             DeepSeek 流式深度报告

        └─ /api/sync-rag  ──► D1 全量读取
                               Workers AI Embedding
                               Vectorize 批量 upsert

双轨并发设计:前端在点击分析时同时发起两个请求:

  • GET /api/get-verdict:毫秒级返回卡片 JSON(走 Vectorize → D1)
  • GET /api/analyze-bracelet:流式返回深度 Markdown 报告(RAG 上下文注入大模型)

二、关键组件说明

组件角色费用
Cloudflare Pages静态前端托管 + API 路由代理免费
Cloudflare Workers边缘 API 网关(panjiayuan-backend)免费额度内
Cloudflare D1关系型 SQL 百科知识库免费
Cloudflare Vectorize1024 维语义向量索引免费额度内
Cloudflare Workers AI文本嵌入 (bge-large-en-v1.5)免费额度内

三、部署完整步骤

步骤 1:创建 D1 数据库与 Vectorize 索引

bash
# 创建 D1 数据库
npx wrangler d1 create panjiayuan-db
# 记录输出的 database_id

# 创建 1024 维向量索引(必须与 Workers AI 模型维度对齐)
npx wrangler vectorize create panjiayuan-vector-index \
  --dimensions=1024 \
  --metric=cosine

步骤 2:编写 wrangler.toml(关键!)

必须在 Worker 代码目录下创建 wrangler.toml,否则每次 deploy 会清除控制台配置的绑定关系:

toml
name = "panjiayuan-backend"
main = "worker.js"
compatibility_date = "2026-06-16"

# Workers AI 绑定(文本向量化)
[ai]
binding = "AI"

# D1 SQL 数据库绑定
[[d1_databases]]
binding = "DB"
database_name = "panjiayuan-db"
database_id = "你的-database-id-uuid"

# Vectorize 向量索引绑定
[[vectorize]]
binding = "VECTOR_INDEX"
index_name = "panjiayuan-vector-index"

步骤 3:部署 Worker

bash
# 必须加 --keep-vars,避免清除控制台配置的 API Key 等环境变量
npx wrangler deploy --keep-vars

步骤 4:初始化数据库表结构与种子数据

bash
# 将 schema.sql 里的建表与初始数据注入远端 D1
npx wrangler d1 execute panjiayuan-db \
  --remote \
  --file=./schema.sql

步骤 5:触发向量冷启动同步

D1 数据注入后,Vectorize 索引仍为空,需要执行一键同步将所有百科条目向量化并写入:

bash
curl -X POST https://your-domain.com/api/sync-rag
# 成功响应:{"success":true,"message":"Sync D1 to Vectorize database successfully!","recordsSynced":7}

四、踩坑记录与修复方案

坑 1:无 wrangler.toml 直接 deploy 会清除云端绑定

问题:执行 npx wrangler deploy worker.js --name panjiayuan-backend 后,D1 / Vectorize / AI 绑定从控制台消失。

原因:wrangler 在没有 wrangler.toml 时以"本地零配置"为基准,会将远端已有的资源绑定清空覆盖。

解决:在 Worker 目录下创建 wrangler.toml,显式声明全部绑定关系,并在 deploy 时加 --keep-vars


坑 2:向量模型 @cf/baai/bge-large-zh-v1.5 已下线

问题:调用 Workers AI 时返回 5007: No such model @cf/baai/bge-large-zh-v1.5 or task

原因:截至 2026-06-16,Cloudflare Workers AI 已不再提供该中文模型。

正确替代模型(1024 维,中英文均可用):

模型 ID维度说明
@cf/baai/bge-large-en-v1.51024推荐,英文优先兼容中文词汇
@cf/qwen/qwen3-embedding-0.6b1024阿里千问,中文效果更优
@cf/baai/bge-base-en-v1.5768轻量,需调整 Vectorize 维度

解决:将代码中的模型名称统一替换为 @cf/baai/bge-large-en-v1.5,Vectorize 索引维度保持 1024 不变。


坑 3:Pages "服务绑定" 指向的是独立 Worker,不是 Pages 函数目录

问题:在 Pages 项目 Settings → Bindings 页面配置了 D1/Vectorize/AI,但 API 请求实际由 panjiayuan-backend Worker 处理,Pages 层的绑定对其无效。

原因:Cloudflare Pages 的 API 路由通过"服务绑定"代理到了一个独立的 Workers 服务,两者的绑定是分开配置的。

解决:在 Workers 控制台(而非 Pages 控制台)为 panjiayuan-backend 分别绑定 D1、Vectorize、AI,或者通过 wrangler.toml 在代码层显式声明(推荐后者,更可追踪)。


坑 4:sync-rag 接口因 FormData 解析顺序问题报错

问题/api/sync-rag 返回 Parsing a Body as FormData requires a Content-Type header

原因:Worker 代码在路由判断前统一执行了 await request.formData(),而 sync-rag 请求没有携带 FormData body。

解决:在 Worker 中将 isSyncRoute 的处理逻辑提前到 request.formData() 之前,让同步路由直接返回,不触碰 FormData 解析。

五、RAG 核心代码片段

D1 百科表结构(schema.sql)

sql
CREATE TABLE IF NOT EXISTS panjiayuan_wiki (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    category TEXT NOT NULL,     -- 文玩类别
    title TEXT NOT NULL,        -- 百科词条标题
    description TEXT NOT NULL,  -- 特征与骗局识别描述
    price_range TEXT NOT NULL,  -- 地摊合理拿货价区间
    phrases TEXT NOT NULL,      -- 砍价金句 JSON 字符串
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

Worker 向量检索与 D1 点查(queryRAGContext)

javascript
async function queryRAGContext(vlmResult, userVoiceText, env) {
    if (!env.VECTOR_INDEX || !env.AI || !env.DB) return null;

    const queryText = `分析材质与提问:${vlmResult} ${userVoiceText}`;
    
    // 1. 将查询文本向量化
    const embeddingRes = await env.AI.run('@cf/baai/bge-large-en-v1.5', {
        text: [queryText]
    });

    // 2. 语义检索 Vectorize,取最相似 Top 1
    const vectorMatches = await env.VECTOR_INDEX.query(
        embeddingRes.data[0],
        { topK: 2, returnMetadata: true }
    );

    const bestMatch = vectorMatches.matches[0];
    if (!bestMatch || bestMatch.score < 0.6) return null;

    // 3. 精准点查 D1,还原结构化百科
    const sqlId = bestMatch.metadata.sqlId;
    return await env.DB.prepare(
        "SELECT * FROM panjiayuan_wiki WHERE id = ?"
    ).bind(sqlId).first();
}

一键冷启动同步路由(/api/sync-rag)

javascript
// 读取 D1 所有百科,向量化后批量 upsert 到 Vectorize
const { results } = await env.DB.prepare("SELECT * FROM panjiayuan_wiki").all();
const upsertVectors = [];
for (const row of results) {
    const vectorText = `品类:${row.category}。防坑描述:${row.description}。拿货价:${row.price_range}`;
    const embeddingRes = await env.AI.run('@cf/baai/bge-large-en-v1.5', { text: [vectorText] });
    upsertVectors.push({
        id: `wiki_${row.id}`,
        values: embeddingRes.data[0],
        metadata: { type: "wiki", category: row.category, sqlId: row.id }
    });
}
await env.VECTOR_INDEX.upsert(upsertVectors);

六、快速重建检查清单

每次修改 Worker 代码后,按以下顺序操作:

  1. npx wrangler deploy --keep-vars(确保 wrangler.toml 在当前目录)
  2. 如 D1 数据有变更:npx wrangler d1 execute panjiayuan-db --remote --file=./schema.sql
  3. 如百科数据变更,重新同步向量:curl -X POST https://your-domain.com/api/sync-rag
  4. 验证:curl -X POST https://your-domain.com/api/get-verdict 查看 source 字段是否包含 CF_RAG_WIKI_ID_