news 2026/1/20 9:26:38

0成本搭建!20分钟用 Workers AI + Vectorize 搞定 RAG(附全套源码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
0成本搭建!20分钟用 Workers AI + Vectorize 搞定 RAG(附全套源码)

引言

想给公司做个智能客服,查了一圈 RAG 教程,要么讲理论云里雾里,要么让你先租个 GPU、搭环境,看着就头大。说实话,我刚开始研究这块的时候也一样,光是配置 LangChain 和向量数据库就折腾了两天,还没跑起来。
后来发现 Cloudflare 推出了一整套 AI 工具,Workers AI + Vectorize + D1,全托管的,免费额度还挺大方。我试着用它们搭了个笔记问答应用,从零到能用真的不到 20 分钟,代码也就百来行。
这篇文章会手把手带你走一遍完整流程:

  • 先讲清楚RAG 到底是什么(不扔术语,用大白话)
  • 实战搭建一个能跑的知识库问答应用(有完整代码)
  • 优化技巧让检索更准确、成本更低
  • 部署上线真正用起来
    你只需要懂点 JavaScript,有个 Cloudflare 账号(免费),跟着操作就能做出来。

RAG 是个啥?5 分钟看懂工作原理

用考试来理解 RAG

先说个直观的比喻。你考试的时候,闭卷考试只能靠脑子里记的东西答题,万一忘了就瞎编。开卷考试就不一样了,不确定的时候翻书查资料,答案准确多了。
RAG(检索增强生成)就是给 AI 开卷考试的权限。
传统 LLM 就像闭卷考试,只能基于训练时见过的数据回答。问题是:

  • 训练数据有时效性,不知道最新动态
  • 没见过你公司的内部文档
  • 记不住所有细节,容易瞎编(行话叫"幻觉")
    RAG 的做法是:先从你准备好的知识库里找相关资料,然后把资料给 AI,让它基于这些内容回答。这样答案既靠谱又能结合最新信息。

RAG 的三个核心步骤

<StatsGrid stats={[
{ value: “第1步”, label: “文档转向量存储”, description: “将知识转成数字表示” },
{ value: “第2步”, label: “检索相似内容”, description: “找到语义最相关的片段” },
{ value: “第3步”, label: “LLM生成答案”, description: “基于检索结果回答” }
]} columns={3} />

整个流程其实就三步:

第一步:把知识变成向量存起来
你有一堆文档对吧?RAG 会把每段文字转成一串数字(专业术语叫"向量"或"Embedding"),这串数字代表了文字的语义。
打个比方,"猫很可爱"和"小猫萌萌的"虽然用词不同,但意思接近,转成向量后这两串数字也会很接近。这些向量会存到 Vectorize 这样的向量数据库里。

第二步:用户提问时,找出最相关的知识片段
用户问"怎么训练猫咪"的时候,系统会先把这个问题也转成向量,然后在数据库里找"距离最近"的那几段内容——也就是语义最相关的知识。
这个过程叫"相似度搜索",速度很快,几毫秒就能从几万条数据里找出最匹配的 3-5 条。

第三步:把检索到的内容喂给 LLM 生成答案
找到相关内容后,组装成一个 Prompt 发给 AI:

以下是相关资料: [检索到的内容1] [检索到的内容2] ... 用户问题:怎么训练猫咪? 请基于上述资料回答。

AI 看到这些"参考资料",就能给出准确且有依据的答案了。

为什么选 Cloudflare 全家桶?

市面上做 RAG 的方案挺多,LangChain、LlamaIndex 啥的都行,但要自己配环境、挑向量数据库、管 GPU 资源,折腾起来挺累的。

Cloudflare 这套方案的优势是:

Workers AI- 内置十几个开源模型(Llama 3、Claude 等),调 API 就能用,不用租 GPU。免费层每天有固定的 Neurons 额度(计量单位),个人项目够用了。

Vectorize- 托管的向量数据库,不用自己搭 Milvus、Pinecone 那些。创建索引、插入向量、相似度搜索,几行代码搞定。

D1- Cloudflare 的 SQLite 数据库,存原始文本用。向量数据库只存向量,具体文字内容还是要从这里取。

全托管- 这是最爽的地方。不用操心服务器、扩容、备份这些破事,专心写代码就行。而且 Cloudflare 的边缘网络,全球访问都快。

2025 年 Cloudflare 还推出了 AutoRAG,进一步简化了流程——上传文档到 R2,后面的切分、向量化、检索、生成全自动。不过这篇文章咱们还是手动搭一遍,这样能学到底层原理。
说了这么多理论,接下来动手做一个。

动手实战 - 搭建你的第一个 RAG 应用

咱们做个笔记问答应用:用户可以添加笔记,然后提问,系统从所有笔记里找相关内容回答。

项目初始化和环境准备

先装 Wrangler(Cloudflare 的 CLI 工具):

npminstall-g wrangler wrangler login# 登录你的 Cloudflare 账号

创建项目:

npmcreate cloudflare@latest rag-notes-app# 选择 "Hello World" worker# 选择 TypeScriptcdrag-notes-app

装个路由库 Hono(比原生 Workers API 好用):

npminstallhono

创建 D1 数据库和 Vectorize 索引:

# 创建 D1 数据库存原始笔记wrangler d1 create notes-db# 创建 Vectorize 索引(768 维,配合 bge-base-en-v1.5 模型)wrangler vectorize create notes-index --dimensions=768--metric=cosine

然后配置wrangler.jsonc(或wrangler.toml):

{ "name": "rag-notes-app", "main": "src/index.ts", "compatibility_date": "2024-01-01", "node_compat": true, // AI 绑定 "ai": { "binding": "AI" }, // D1 数据库绑定 "d1_databases": [ { "binding": "DB", "database_name": "notes-db", "database_id": "你的数据库ID" // 从上面创建命令的输出复制 } ], // Vectorize 索引绑定 "vectorize": [ { "binding": "VECTORIZE", "index_name": "notes-index" } ], // Workflow 绑定(处理异步向量化任务) "workflows": [ { "binding": "RAG_WORKFLOW", "name": "rag-workflow", "class_name": "RAGWorkflow" } ] }

初始化数据库表:

-- schema.sqlCREATETABLEIFNOTEXISTSnotes(idINTEGERPRIMARYKEYAUTOINCREMENT,textTEXTNOTNULL,created_atDATETIMEDEFAULTCURRENT_TIMESTAMP);

运行:

wrangler d1 execute notes-db --file=./schema.sql

实现知识库录入功能

这是整个 RAG 的核心——把用户的笔记转成向量存起来。
创建src/workflow.ts(Workflow 处理异步任务):

import{WorkflowEntrypoint,WorkflowStep}from'cloudflare:workers';typeEnv={AI:Ai;DB:D1Database;VECTORIZE:VectorizeIndex;};typeParams={noteId:number;text:string;};exportclassRAGWorkflowextendsWorkflowEntrypoint<Env,Params>{asyncrun(event:WorkflowEvent<Params>,step:WorkflowStep){const{noteId,text}=event.payload;// 步骤1:确认 D1 记录已创建(由主路由完成)// 步骤2:生成向量constembeddings=awaitstep.do('generate embeddings',async()=>{constresponse=awaitthis.env.AI.run('@cf/baai/bge-base-en-v1.5',// 768维的 Embedding 模型{text:[text]});returnresponse.data[0];// 返回向量数组});// 步骤3:插入 Vectorizeawaitstep.do('insert vector',async()=>{awaitthis.env.VECTORIZE.insert([{id:noteId.toString(),values:embeddings,metadata:{text}// 存一份文本方便调试}]);});}}

主路由src/index.ts(处理添加笔记):

import{Hono}from'hono';import{RAGWorkflow}from'./workflow';typeBindings={AI:Ai;DB:D1Database;VECTORIZE:VectorizeIndex;RAG_WORKFLOW:Workflow;};constapp=newHono<{Bindings:Bindings}>();// 添加笔记app.post('/notes',async(c)=>{const{text}=awaitc.req.json<{text:string}>();if(!text?.trim()){returnc.json({error:'Text is required'},400);}// 插入 D1constresult=awaitc.env.DB.prepare('INSERT INTO notes (text) VALUES (?) RETURNING id').bind(text).first<{id:number}>();if(!result){returnc.json({error:'Failed to create note'},500);}// 触发 Workflow 异步生成向量awaitc.env.RAG_WORKFLOW.create({params:{noteId:result.id,text}});returnc.json({id:result.id,message:'Note created, vectorization in progress'});});exportdefaultapp;export{RAGWorkflow};

这样一来,用户发 POST 请求添加笔记时:

  1. 文本立即存到 D1
  2. 后台 Workflow 慢慢生成向量、插入 Vectorize
  3. 就算向量化要几秒钟,也不会阻塞用户请求

实现智能问答功能

现在可以存笔记了,接下来做查询。
src/index.ts添加:

// 查询问答app.get('/',async(c)=>{constquery=c.req.query('q');if(!query){returnc.json({error:'Query parameter "q" is required'},400);}// 第一步:把问题转成向量constqueryEmbedding=awaitc.env.AI.run('@cf/baai/bge-base-en-v1.5',{text:[query]});// 第二步:在 Vectorize 里找最相似的 3 条笔记constmatches=awaitc.env.VECTORIZE.query(queryEmbedding.data[0],{topK:3,returnMetadata:true});if(matches.count===0){returnc.json({answer:'没有找到相关笔记'});}// 第三步:从 D1 获取完整文本(如果需要)constnoteIds=matches.matches.map(m=>m.id);constnotes=awaitc.env.DB.prepare(`SELECT text FROM notes WHERE id IN (${noteIds.map(()=>'?').join(',')})`).bind(...noteIds).all();// 第四步:构造 Prompt,调用 LLM 生成答案constcontext=notes.results.map((n:any)=>n.text).join('\n\n---\n\n');constprompt=`以下是相关的笔记内容:${context}用户问题:${query}请基于上述笔记内容回答用户问题。如果笔记中没有相关信息,请说明。`;constaiResponse=awaitc.env.AI.run('@cf/meta/llama-3-8b-instruct',// 或者用 claude-3-5-sonnet-latest{messages:[{role:'system',content:'你是一个智能笔记助手'},{role:'user',content:prompt}]});returnc.json({answer:aiResponse.response,sources:matches.matches.map(m=>({id:m.id,score:m.score,text:m.metadata?.text}))});});

测试一下:

# 本地运行wrangler dev# 添加笔记curl-X POST http://localhost:8787/notes\-H"Content-Type: application/json"\-d'{"text": "Cloudflare Workers AI 支持 Llama 3 和 Claude 模型"}'curl-X POST http://localhost:8787/notes\-H"Content-Type: application/json"\-d'{"text": "Vectorize 使用余弦相似度进行向量检索"}'# 等几秒让 Workflow 完成向量化# 提问curl"http://localhost:8787/?q=Workers%20AI%20有哪些模型"

如果一切正常,你会收到基于笔记内容的回答。

删除和更新功能

删除笔记时,记得同时删除 D1 和 Vectorize 的数据:

app.delete('/notes/:id',async(c)=>{constid=c.req.param('id');// 从 D1 删除awaitc.env.DB.prepare('DELETE FROM notes WHERE id = ?').bind(id).run();// 从 Vectorize 删除awaitc.env.VECTORIZE.deleteByIds([id]);returnc.json({message:'Note deleted'});});

更新的话,最简单的方式是先删后加(重新生成向量)。
完整代码可以参考 Cloudflare 官方示例。

进阶优化 - 让你的 RAG 更聪明

基础功能跑起来了,但要真正用在实际项目里,还有些细节值得优化。

文本分块策略

现在咱们是把整条笔记当一个单元存的。如果笔记很长(比如一篇技术文档),这样做会有问题:

  1. 检索时整篇文档的相似度可能不高(只有部分段落相关)
  2. Prompt 太长会超出 LLM 的上下文窗口限制
    更好的做法是把长文本切成小块(chunk),每块单独生成向量。
    简单的分块方法:
functionsplitText(text:string,chunkSize:number=500,overlap:number=50):string[]{constchunks:string[]=[];letstart=0;while(start<text.length){constend=Math.min(start+chunkSize,text.length);chunks.push(text.slice(start,end));start=end-overlap;// 重叠一点,避免句子被切断}returnchunks;}

更智能的方式是按段落或语义分割(可以用 LangChain 的RecursiveCharacterTextSplitter),不过对大部分场景来说,固定长度+重叠已经够用了。
修改 Workflow,给每个 chunk 分配唯一 ID:

constchunks=splitText(text);for(leti=0;i<chunks.length;i++){constchunkId=`${noteId}-${i}`;constembeddings=awaitthis.env.AI.run('@cf/baai/bge-base-en-v1.5',{text:[chunks[i]]});awaitthis.env.VECTORIZE.insert([{id:chunkId,values:embeddings.data[0],metadata:{noteId,chunkIndex:i,text:chunks[i]}}]);}

提升检索准确度

调整 topK 和相似度阈值
默认返回 top 3 可能不够,也可能太多。试试调到 5 条,同时过滤掉相似度太低的:

constmatches=awaitc.env.VECTORIZE.query(queryEmbedding.data[0],{topK:5,returnMetadata:true});// 只保留相似度 > 0.7 的结果constrelevantMatches=matches.matches.filter(m=>m.score>0.7);

相似度分数范围是 0-1(余弦相似度),0.7 以上一般算比较相关。
优化 Prompt
别光把检索到的内容扔给 AI,告诉它怎么用这些信息:

constprompt=`你是一个智能笔记助手。以下是从笔记库中检索到的相关内容(按相关性排序):${context}请严格基于上述内容回答用户问题。如果内容不足以回答问题,明确说明"笔记中没有找到相关信息",不要编造答案。 用户问题:${query}`;

关键点:

  • 明确告诉 AI 这是检索到的资料
  • 要求它只基于这些内容回答
  • 允许它承认"不知道"
    这样能减少 AI 瞎编的情况。

成本控制和限流

Workers AI 免费层每天有 Neurons 额度限制(具体数值会变,去 Pricing 页面 查最新的)。

监控用量
在 Cloudflare Dashboard → Workers AI 里能看到每日消耗。不同模型消耗不同,Embedding 模型便宜,LLM 生成贵一些。

降级策略
如果担心超额,可以:

  1. 限制每个用户的请求频率(用 KV 或 Durable Objects 计数)
  2. 超出额度后改用更小的模型或返回缓存结果
  3. 对于非关键请求,直接返回检索到的原文,不调 LLM
// 简单限流示例constuserKey=c.req.header('X-User-ID')||'anonymous';constrequestCount=awaitc.env.KV.get(`rate:${userKey}`)||0;if(requestCount>100){returnc.json({error:'Rate limit exceeded'},429);}awaitc.env.KV.put(`rate:${userKey}`,requestCount+1,{expirationTtl:86400});

切换更强的模型

Llama 3 8B 已经挺不错了,但如果想要更好的理解能力,可以试试 Claude:

// 需要先在 Dashboard 绑定 Anthropic API keyconstaiResponse=awaitc.env.AI.run('claude-3-5-sonnet-latest',{messages:[{role:'system',content:'你是一个智能笔记助手'},{role:'user',content:prompt}]});

Claude 的理解能力和输出质量确实更好,但消耗的 Neurons 也更多。根据实际需求选吧。
我自己的经验是:

  • 简单问答:Llama 3 够用
  • 需要推理、总结:Claude 明显好一些
  • 预算有限:先用 Llama 测试,确定需求后再升级

部署上线和实际应用场景

部署流程

本地测试没问题后,部署超简单:

wrangler deploy

就这一行,Cloudflare 会自动:

  • 打包你的代码
  • 部署到全球边缘节点
  • 生成一个.workers.dev域名
    你会看到类似这样的输出:
Published rag-notes-app https://rag-notes-app.your-account.workers.dev

这就是你的 API 地址了。

绑定自定义域名(可选):
如果你有域名托管在 Cloudflare,可以绑定:

wrangler domainsaddapi.yourdomain.com

或者在 Dashboard → Workers & Pages → 你的 Worker → Settings → Domains 里添加。

环境变量和 Secrets
如果你用了 Anthropic API key 或其他敏感信息:

wrangler secret put ANTHROPIC_API_KEY# 输入你的 key

代码里这样用:

constapiKey=c.env.ANTHROPIC_API_KEY;

真实应用场景

这套 RAG 架构能做的事挺多,分享几个实际场景:

1. 企业知识库问答

场景:公司有几百页员工手册、技术文档、FAQ,新员工找资料很麻烦。
做法:

  • 把所有文档上传,按章节分块存入 Vectorize
  • 做个简单的 Web 界面或接入企业微信机器人
  • 员工直接问"报销流程是什么",系统自动检索相关章节回答
    好处:24 小时在线,比翻文档快多了。

2. 智能客服

场景:电商网站有大量商品信息和售后政策,客服重复回答相同问题。
做法:

  • 把常见问题、商品描述、退换货政策存进去
  • 用户咨询时先让 RAG 系统回答
  • 答不上来的再转人工
    效果:某个开发者用这套方案,把客服压力减少了 60%+。

3. 个人笔记助手

场景:你用 Notion 或 Obsidian 记了几年笔记,想快速找到某个知识点。
做法:

  • 定期把笔记导出,通过 API 添加到 RAG 系统
  • 需要时直接问"上次看的那个 TypeScript 技巧是啥来着"
  • 系统检索出相关笔记片段
    我自己就在用类似的工具,找资料效率真的提升了不少。

4. “Chat with PDF” 工具

场景:用户上传一份 PDF(论文、合同、报告),想快速提取信息。
做法(参考 Rohit Patil 的案例):

  • 用户上传 PDF 到 R2
  • Worker 读取 PDF,提取文本,分块向量化
  • 用户可以问"这份合同的付款条款是什么"
    这个场景特别实用,很多法律、咨询行业的人需要。

<StatsGrid stats={[
{ value: “24小时”, label: “企业知识库在线” },
{ value: “60%+”, label: “智能客服压力减少” },
{ value: “10倍”, label: “个人笔记检索效率提升” }
]} source=“实际应用案例数据” />

常见问题排查

问题1:向量维度不匹配

错误:dimension mismatch: expected 768, got 512
原因:Vectorize 索引创建时设的维度(768)和模型输出的维度不一致。
解决:确保索引维度和模型匹配。bge-base-en-v1.5是 768 维,别用错模型。

问题2:D1 和 Vectorize 数据不一致

现象:查询返回的 note ID 在 D1 里不存在。
原因:可能删除 D1 记录时忘了删 Vectorize,或者 Workflow 失败了。
解决:删除操作要么包在事务里,要么用 Workflow 确保两边都删干净。

问题3:Workflow 超时

错误:workflow execution timeout
原因:向量化大量文本时超过 Workflow 的时间限制。
解决:把大文档拆成多个 Workflow 任务,或者批量处理。

// 分批处理constbatchSize=10;for(leti=0;i<chunks.length;i+=batchSize){constbatch=chunks.slice(i,i+batchSize);awaitc.env.RAG_WORKFLOW.create({params:{noteId,chunks:batch,offset:i}});}

结论

说了这么多,回顾一下咱们做了啥:

  • 弄懂了 RAG 原理:检索增强生成,就是给 AI 开卷考试的权限,先找资料再回答
  • 搭了个能跑的应用:笔记问答系统,从环境准备到代码实现,完整走了一遍
  • 学了优化技巧:文本分块、检索调优、成本控制,这些细节让应用真正可用
  • 看了实际场景:企业知识库、智能客服、个人助手、PDF 聊天,都是可以落地的方向
    Cloudflare 这套方案最大的优势是门槛低。不用租 GPU、不用搭数据库、不用操心运维,免费额度对个人项目来说绝对够用。就算是生产环境,付费计划也比自建便宜多了。
    接下来你可以:
  1. 立即动手:克隆 官方示例代码,wrangler dev跑起来,5 分钟就能看到效果
  2. 接入真实数据:把你的笔记、文档、FAQ 导进去,看看检索质量如何
  3. 做个前端界面:用 React/Vue 做个简单的聊天界面,或者直接用 Cloudflare Pages 部署
  4. 探索更多可能:试试多模态 RAG(结合图片、表格)、GraphRAG(知识图谱增强)等高级玩法
    RAG 是当前 AI 应用最实用的架构之一,掌握它能让你做出很多有意思的东西。试下来,Cloudflare 全家桶确实能解决不少实际问题。
    要是碰到问题,可以去 Cloudflare Discord 或 Community 论坛 问,社区挺活跃的。

原文首发自个人博客

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/18 21:30:46

Casdoor 终极指南:一站式身份认证管理平台

Casdoor 终极指南&#xff1a;一站式身份认证管理平台 【免费下载链接】casdoor An open-source UI-first Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA and R…

作者头像 李华
网站建设 2026/1/16 11:48:06

智谱 Open-AutoGLM 2.0 实战指南(AutoML新纪元降临)

第一章&#xff1a;智谱 Open-AutoGLM 2.0 概述Open-AutoGLM 2.0 是智谱AI推出的新一代自动化大语言模型工具链&#xff0c;旨在降低开发者与企业使用大型语言模型&#xff08;LLM&#xff09;的技术门槛。该平台融合了自然语言理解、代码生成、任务自动规划等核心能力&#xf…

作者头像 李华
网站建设 2026/1/19 6:19:58

ollydbg下载及安装核心要点:避免常见错误

如何安全下载与配置 OllyDbg&#xff1a;避开90%初学者都踩过的坑 你是不是也曾在搜索引擎里输入“ollydbg下载”时&#xff0c;被一堆打着“绿色免安装”“中文汉化版”旗号的网站搞得眼花缭乱&#xff1f;点进去后不是跳转广告、捆绑挖矿程序&#xff0c;就是刚运行就被杀软…

作者头像 李华
网站建设 2026/1/19 13:30:33

多GPU并行训练:TensorFlow MirroredStrategy详解

多GPU并行训练&#xff1a;TensorFlow MirroredStrategy详解 在深度学习模型参数动辄上亿的今天&#xff0c;单块GPU已经很难支撑起完整的训练任务。一个典型的ResNet或Transformer模型&#xff0c;在ImageNet或大规模文本语料上的训练周期可能长达数天甚至数周——这显然无法满…

作者头像 李华
网站建设 2026/1/20 8:03:42

如何快速制作专业答题卡:Word插件终极指南

如何快速制作专业答题卡&#xff1a;Word插件终极指南 【免费下载链接】答题卡制作Word插件 答题卡制作Word插件是一款专为教师、学生及教育工作者设计的实用工具&#xff0c;可轻松在Word中创建答题卡。插件支持快速生成、自定义模板及批量制作&#xff0c;操作简单&#xff0…

作者头像 李华
网站建设 2026/1/20 8:20:42

轻量化部署:TensorFlow模型转ONNX格式

轻量化部署&#xff1a;TensorFlow模型转ONNX格式 在AI工程化落地的深水区&#xff0c;一个看似简单的技术决策——“模型用什么格式部署”——往往决定了整个系统的灵活性与成本。我们见过太多团队在训练阶段游刃有余&#xff0c;却在上线时被环境依赖、推理延迟和跨平台适配…

作者头像 李华