Base de connaissances IA en 20 minutes ? Workers AI + Vectorize : tutoriel RAG pas à pas (code complet)

Vous voulez un service client intelligent pour votre entreprise, vous parcourez les tutos RAG, et soit c’est théorique à perdre le fil, soit on vous demande de louer un GPU et monter un environnement. Configurer LangChain et une base vectorielle peut facilement prendre deux jours — sans garantie que ça tourne.
Puis j’ai découvert la suite d’outils IA de Cloudflare : Workers AI + Vectorize + D1, entièrement managés, avec une généreuse offre gratuite. En les utilisant pour une app de Q&R sur mes notes, du zéro au fonctionnel en moins de 20 minutes, une centaine de lignes de code.
Cet article vous guide pas à pas sur le flux complet :
- Comprendre ce qu’est vraiment le RAG (sans jargon inutile)
- Construire une app de Q&R sur base de connaissances fonctionnelle (code complet)
- Optimiser pour un retrieval plus précis et des coûts plus bas
- Déployer et l’utiliser en production
Il vous faut un peu de JavaScript, un compte Cloudflare (gratuit), et suivre les étapes.
C’est quoi le RAG ? Comprendre le principe en 5 minutes
Le RAG, expliqué avec une analogie d’examen
Une image simple. À l’examen, en contrôle sans documents, vous ne répondez qu’avec ce que vous avez en tête — si vous oubliez, vous inventez. Avec documents autorisés, vous pouvez consulter vos sources : la réponse est bien plus fiable.
Le RAG (Retrieval-Augmented Generation), c’est donner ce droit de consultation à l’IA.
Un LLM classique, c’est l’examen sans documents : il ne répond qu’avec ce qu’il a vu à l’entraînement. Problèmes :
- les données d’entraînement vieillissent, pas les dernières actus
- il n’a jamais vu vos docs internes
- il oublie des détails et invente (on appelle ça des « hallucinations »)
Le RAG : d’abord chercher dans votre base de connaissances, puis donner ces extraits à l’IA pour qu’elle réponde. Réponses plus fiables et à jour.
Les trois étapes clés du RAG
Le flux tient en trois étapes :
Étape 1 : transformer le savoir en vecteurs
Vous avez des documents. Le RAG convertit chaque passage en une suite de nombres (vecteur ou embedding) qui encode le sens.
« Les chats sont mignons » et « les chatons sont adorables » utilisent des mots différents, mais le sens est proche : leurs vecteurs seront voisins. Ces vecteurs vont dans une base comme Vectorize.
Étape 2 : à la question, trouver les passages pertinents
Quand l’utilisateur demande « comment éduquer un chat », la question devient aussi un vecteur ; on cherche dans la base les entrées les plus « proches » — sémantiquement les plus pertinentes.
C’est la recherche par similarité : quelques millisecondes pour trouver les 3-5 meilleurs résultats parmi des dizaines de milliers.
Étape 3 : alimenter le LLM avec le contenu récupéré
On assemble un prompt pour l’IA :
以下是相关资料:
[检索到的内容1]
[检索到的内容2]
...
用户问题:怎么训练猫咪?
请基于上述资料回答。
Avec ces « références », l’IA produit une réponse précise et étayée.
Pourquoi la suite Cloudflare ?
Beaucoup de stacks RAG existent — LangChain, LlamaIndex, etc. — mais configurer l’environnement, choisir la base vectorielle et gérer le GPU, c’est lourd.
Les avantages de Cloudflare :
Workers AI — une quinzaine de modèles open source (Llama 3, Claude, etc.), API directe, pas de GPU à louer. La couche gratuite offre un quota Neurons quotidien, suffisant pour un projet perso.
Vectorize — base vectorielle managée, pas besoin de Milvus ou Pinecone. Créer un index, insérer des vecteurs, recherche par similarité : quelques lignes de code.
D1 — SQLite Cloudflare pour le texte brut. Vectorize ne stocke que les vecteurs ; le contenu textuel vient de D1.
Tout managé — le plus agréable : pas de serveurs, scaling ou backups à gérer, concentrez-vous sur le code. Le réseau edge Cloudflare accélère l’accès mondial.
"En 2025, Cloudflare a lancé AutoRAG : uploadez des docs sur R2, découpage, vectorisation, retrieval et génération sont automatiques"
Cloudflare a aussi sorti AutoRAG en 2025 pour simplifier encore — upload sur R2, le reste est automatique. Ici on monte le flux à la main pour comprendre les mécanismes sous-jacents.
Assez de théorie, passons à la pratique.
Mise en pratique — votre première application RAG
On construit une app de Q&R sur notes : l’utilisateur ajoute des notes, pose des questions, le système retrouve le contenu pertinent et répond.
Initialisation du projet et préparation de l’environnement
Installez Wrangler (CLI Cloudflare) :
npm install -g wrangler
wrangler login # 登录你的 Cloudflare 账号
Créez le projet :
npm create cloudflare@latest rag-notes-app
# 选择 "Hello World" worker
# 选择 TypeScript
cd rag-notes-app
Installez Hono (routeur plus pratique que l’API Workers native) :
npm install hono
Créez la base D1 et l’index Vectorize :
# 创建 D1 数据库存原始笔记
wrangler d1 create notes-db
# 创建 Vectorize 索引(768 维,配合 bge-base-en-v1.5 模型)
wrangler vectorize create notes-index --dimensions=768 --metric=cosine
Configurez wrangler.jsonc (ou 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"
}
]
}
Initialisez les tables :
-- schema.sql
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
Exécutez :
wrangler d1 execute notes-db --file=./schema.sql
Implémenter l’ingestion dans la base de connaissances
C’est le cœur du RAG — transformer les notes en vecteurs stockés.
Créez src/workflow.ts (Workflow pour les tâches asynchrones) :
import { WorkflowEntrypoint, WorkflowStep } from 'cloudflare:workers';
type Env = {
AI: Ai;
DB: D1Database;
VECTORIZE: VectorizeIndex;
};
type Params = {
noteId: number;
text: string;
};
export class RAGWorkflow extends WorkflowEntrypoint<Env, Params> {
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
const { noteId, text } = event.payload;
// 步骤1:确认 D1 记录已创建(由主路由完成)
// 步骤2:生成向量
const embeddings = await step.do('generate embeddings', async () => {
const response = await this.env.AI.run(
'@cf/baai/bge-base-en-v1.5', // 768维的 Embedding 模型
{ text: [text] }
);
return response.data[0]; // 返回向量数组
});
// 步骤3:插入 Vectorize
await step.do('insert vector', async () => {
await this.env.VECTORIZE.insert([
{
id: noteId.toString(),
values: embeddings,
metadata: { text } // 存一份文本方便调试
}
]);
});
}
}
Route principale src/index.ts (ajout de notes) :
import { Hono } from 'hono';
import { RAGWorkflow } from './workflow';
type Bindings = {
AI: Ai;
DB: D1Database;
VECTORIZE: VectorizeIndex;
RAG_WORKFLOW: Workflow;
};
const app = new Hono<{ Bindings: Bindings }>();
// 添加笔记
app.post('/notes', async (c) => {
const { text } = await c.req.json<{ text: string }>();
if (!text?.trim()) {
return c.json({ error: 'Text is required' }, 400);
}
// 插入 D1
const result = await c.env.DB.prepare(
'INSERT INTO notes (text) VALUES (?) RETURNING id'
).bind(text).first<{ id: number }>();
if (!result) {
return c.json({ error: 'Failed to create note' }, 500);
}
// 触发 Workflow 异步生成向量
await c.env.RAG_WORKFLOW.create({
params: { noteId: result.id, text }
});
return c.json({
id: result.id,
message: 'Note created, vectorization in progress'
});
});
export default app;
export { RAGWorkflow };
Quand l’utilisateur envoie un POST pour ajouter une note :
- le texte est immédiatement stocké dans D1
- le Workflow génère les vecteurs et les insère dans Vectorize en arrière-plan
- même si la vectorisation prend quelques secondes, la requête utilisateur n’est pas bloquée
Implémenter la Q&R intelligente
Les notes sont stockées, passons aux requêtes.
Ajoutez dans src/index.ts :
// 查询问答
app.get('/', async (c) => {
const query = c.req.query('q');
if (!query) {
return c.json({ error: 'Query parameter "q" is required' }, 400);
}
// 第一步:把问题转成向量
const queryEmbedding = await c.env.AI.run(
'@cf/baai/bge-base-en-v1.5',
{ text: [query] }
);
// 第二步:在 Vectorize 里找最相似的 3 条笔记
const matches = await c.env.VECTORIZE.query(
queryEmbedding.data[0],
{ topK: 3, returnMetadata: true }
);
if (matches.count === 0) {
return c.json({ answer: '没有找到相关笔记' });
}
// 第三步:从 D1 获取完整文本(如果需要)
const noteIds = matches.matches.map(m => m.id);
const notes = await c.env.DB.prepare(
`SELECT text FROM notes WHERE id IN (${noteIds.map(() => '?').join(',')})`
).bind(...noteIds).all();
// 第四步:构造 Prompt,调用 LLM 生成答案
const context = notes.results.map((n: any) => n.text).join('\n\n---\n\n');
const prompt = `以下是相关的笔记内容:
${context}
用户问题:${query}
请基于上述笔记内容回答用户问题。如果笔记中没有相关信息,请说明。`;
const aiResponse = await c.env.AI.run(
'@cf/meta/llama-3-8b-instruct', // 或者用 claude-3-5-sonnet-latest
{
messages: [
{ role: 'system', content: '你是一个智能笔记助手' },
{ role: 'user', content: prompt }
]
}
);
return c.json({
answer: aiResponse.response,
sources: matches.matches.map(m => ({
id: m.id,
score: m.score,
text: m.metadata?.text
}))
});
});
Testez :
# 本地运行
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有哪些模型"
Si tout va bien, vous recevrez une réponse basée sur le contenu de vos notes.
Suppression et mise à jour
Lors d’une suppression, effacez D1 et Vectorize :
app.delete('/notes/:id', async (c) => {
const id = c.req.param('id');
// 从 D1 删除
await c.env.DB.prepare('DELETE FROM notes WHERE id = ?').bind(id).run();
// 从 Vectorize 删除
await c.env.VECTORIZE.deleteByIds([id]);
return c.json({ message: 'Note deleted' });
});
Pour une mise à jour, le plus simple : supprimer puis recréer (re-générer le vecteur).
Code complet : exemple officiel Cloudflare.
Optimisations avancées — un RAG plus intelligent
Les bases tournent ; pour un usage réel, quelques détails valent le coup.
Stratégie de découpage de texte
Aujourd’hui chaque note entière est une unité. Pour une note longue (doc technique), deux problèmes :
- la similarité globale du document peut être faible alors qu’un paragraphe est pertinent
- un prompt trop long dépasse la fenêtre de contexte du LLM
Mieux vaut découper en chunks, chacun vectorisé séparément.
Méthode simple :
function splitText(text: string, chunkSize: number = 500, overlap: number = 50): string[] {
const chunks: string[] = [];
let start = 0;
while (start < text.length) {
const end = Math.min(start + chunkSize, text.length);
chunks.push(text.slice(start, end));
start = end - overlap; // 重叠一点,避免句子被切断
}
return chunks;
}
Plus fin : découpage par paragraphe ou sémantique (ex. RecursiveCharacterTextSplitter de LangChain) ; pour la plupart des cas, taille fixe + overlap suffit.
Modifiez le Workflow pour un ID unique par chunk :
const chunks = splitText(text);
for (let i = 0; i < chunks.length; i++) {
const chunkId = `${noteId}-${i}`;
const embeddings = await this.env.AI.run('@cf/baai/bge-base-en-v1.5', {
text: [chunks[i]]
});
await this.env.VECTORIZE.insert([{
id: chunkId,
values: embeddings.data[0],
metadata: { noteId, chunkIndex: i, text: chunks[i] }
}]);
}
Améliorer la précision du retrieval
Ajuster topK et le seuil de similarité
Par défaut top 3 peut être trop ou pas assez. Essayez 5, en filtrant les scores trop bas :
const matches = await c.env.VECTORIZE.query(queryEmbedding.data[0], {
topK: 5,
returnMetadata: true
});
// 只保留相似度 > 0.7 的结果
const relevantMatches = matches.matches.filter(m => m.score > 0.7);
Score entre 0 et 1 (similarité cosinus) ; au-dessus de 0,7, généralement pertinent.
Optimiser le prompt
Ne vous contentez pas de coller le contenu récupéré — dites à l’IA comment l’utiliser :
const prompt = `你是一个智能笔记助手。以下是从笔记库中检索到的相关内容(按相关性排序):
${context}
请严格基于上述内容回答用户问题。如果内容不足以回答问题,明确说明"笔记中没有找到相关信息",不要编造答案。
用户问题:${query}`;
Points clés :
- préciser que ce sont des extraits récupérés
- exiger une réponse strictement basée sur ce contenu
- autoriser à dire « je ne sais pas »
Cela réduit les hallucinations.
Maîtrise des coûts et rate limiting
La couche gratuite Workers AI a un quota Neurons quotidien (valeur variable — voir la page Pricing).
Suivi de consommation : Dashboard Cloudflare → Workers AI. Les modèles d’embedding coûtent peu ; la génération LLM coûte plus.
Stratégie de dégradation :
- limiter la fréquence par utilisateur (compteur KV ou Durable Objects)
- au-delà du quota, modèle plus petit ou résultats en cache
- pour les requêtes non critiques, renvoyer le texte récupéré sans appeler le LLM
// 简单限流示例
const userKey = c.req.header('X-User-ID') || 'anonymous';
const requestCount = await c.env.KV.get(`rate:${userKey}`) || 0;
if (requestCount > 100) {
return c.json({ error: 'Rate limit exceeded' }, 429);
}
await c.env.KV.put(`rate:${userKey}`, requestCount + 1, { expirationTtl: 86400 });
Passer à un modèle plus puissant
Llama 3 8B est déjà solide ; pour une meilleure compréhension, essayez Claude :
// 需要先在 Dashboard 绑定 Anthropic API key
const aiResponse = await c.env.AI.run('claude-3-5-sonnet-latest', {
messages: [
{ role: 'system', content: '你是一个智能笔记助手' },
{ role: 'user', content: prompt }
]
});
Claude est meilleur en qualité, mais consomme plus de Neurons. Adaptez au besoin.
Mon retour d’expérience :
- Q&R simples : Llama 3 suffit
- Raisonnement, synthèse : Claude nettement meilleur
- Budget serré : tester d’abord avec Llama, upgrader une fois le besoin confirmé
Déploiement et cas d’usage réels
Processus de déploiement
Tests locaux OK, déploiement en une commande :
wrangler deploy
Cloudflare s’occupe de :
- packager votre code
- déployer sur le réseau edge mondial
- générer un domaine
.workers.dev
Sortie typique :
Published rag-notes-app
https://rag-notes-app.your-account.workers.dev
Voilà l’URL de votre API.
Domaine personnalisé (optionnel) :
Si votre domaine est sur Cloudflare :
wrangler domains add api.yourdomain.com
Ou via Dashboard → Workers & Pages → votre Worker → Settings → Domains.
Variables d’environnement et Secrets :
Pour une clé Anthropic ou autre secret :
wrangler secret put ANTHROPIC_API_KEY
# 输入你的 key
Dans le code :
const apiKey = c.env.ANTHROPIC_API_KEY;
Scénarios d’application réels
Cette architecture RAG couvre beaucoup de cas :
1. Q&R base de connaissances entreprise
Scénario : des centaines de pages de manuel, docs techniques, FAQ — difficile pour les nouveaux de trouver l’info.
Approche :
- uploader tous les docs, découper par chapitre dans Vectorize
- interface web simple ou bot WeChat entreprise
- l’employé demande « quelle est la procédure de remboursement ? », le système retrouve et répond
Bénéfice : disponible 24h/24, bien plus rapide que feuilleter des PDF.
2. Service client intelligent
Scénario : site e-commerce, infos produits et politiques SAV, mêmes questions en boucle.
Approche :
- stocker FAQ, descriptions, politique de retour
- le RAG répond en premier
- escalade humaine si insuffisant
Résultat : un développeur a réduit la charge support de plus de 60 %.
3. Assistant notes personnelles
Scénario : des années de notes Notion ou Obsidian, retrouver un détail précis.
Approche :
- export périodique des notes via API vers le système RAG
- demander « c’était quoi déjà ce truc TypeScript que j’avais noté ? »
- retrieval des passages pertinents
J’utilise un outil similaire : gain d’efficacité net pour retrouver l’info.
4. Outil « Chat with PDF »
Scénario : l’utilisateur uploade un PDF (article, contrat, rapport) et veut extraire des infos rapidement.
Approche (voir le cas de Rohit Patil) :
- upload PDF sur R2
- Worker extrait le texte, découpe, vectorise
- l’utilisateur demande « quelles sont les clauses de paiement de ce contrat ? »
Très utile en juridique et conseil.
Dépannage des problèmes courants
Problème 1 : dimensions de vecteurs incohérentes
Erreur : dimension mismatch: expected 768, got 512
Cause : la dimension de l’index Vectorize (768) ne correspond pas à celle du modèle.
Solution : aligner index et modèle. bge-base-en-v1.5 = 768 dimensions.
Problème 2 : D1 et Vectorize désynchronisés
Symptôme : un ID de note retourné n’existe pas dans D1.
Cause : suppression D1 sans Vectorize, ou Workflow en échec.
Solution : transaction ou Workflow garantissant la cohérence des deux côtés.
Problème 3 : timeout Workflow
Erreur : workflow execution timeout
Cause : vectorisation d’un gros volume dépasse la limite de temps.
Solution : plusieurs tâches Workflow ou traitement par lots.
// 分批处理
const batchSize = 10;
for (let i = 0; i < chunks.length; i += batchSize) {
const batch = chunks.slice(i, i + batchSize);
await c.env.RAG_WORKFLOW.create({
params: { noteId, chunks: batch, offset: i }
});
}
Conclusion
Récapitulons :
- Principe RAG : retrieval augmenté, « examen avec documents » — chercher d’abord, répondre ensuite
- App fonctionnelle : système de Q&R sur notes, de l’environnement au code
- Optimisations : découpage, tuning du retrieval, maîtrise des coûts
- Cas réels : base entreprise, service client, assistant perso, chat PDF
Le grand avantage Cloudflare : barrière basse. Pas de GPU, pas de base à installer, pas d’ops — l’offre gratuite suffit pour un projet perso. En production, les plans payants restent souvent moins chers qu’un stack self-hosted.
Prochaines étapes :
- Agir tout de suite : clonez l’exemple officiel,
wrangler dev, effet en 5 minutes - Brancher vos données : importez notes, docs, FAQ, testez la qualité du retrieval
- Ajouter une interface : chat React/Vue simple, ou déploiement Cloudflare Pages
- Aller plus loin : RAG multimodal (images, tableaux), GraphRAG (graphe de connaissances)
Le RAG est l’une des architectures IA les plus utiles aujourd’hui. La suite Cloudflare règle beaucoup de problèmes concrets.
Des questions ? Discord Cloudflare ou le forum Community — communauté très active.
FAQ
Quelle est la différence entre le RAG et un moteur de recherche classique ?
• retourne des liens vers des documents via la correspondance de mots-clés
RAG :
• comprend le sens, récupère le contenu pertinent et génère une réponse en langage naturel
• sait que « les chats sont mignons » et « les chatons sont adorables » veulent dire la même chose
• la recherche classique ne matche que les mots-clés identiques
• le RAG donne directement la réponse, sans faire feuilleter plusieurs documents
Quelle taille de base de connaissances la version gratuite de Cloudflare peut-elle supporter ?
• D1 gratuit : 10 Go de stockage
• Vectorize gratuit : 5 millions de vecteurs (environ 5 Go de texte)
Largement suffisant pour les projets personnels et les bases de connaissances PME.
Pour plus de capacité, passez à une offre payante ou répartissez sur plusieurs index.
Comment améliorer la précision du retrieval RAG ?
1) Découpage raisonnable :
• chunk size 500-1000 caractères
• overlap 50-100 caractères
2) Ajustement des paramètres :
• topK (généralement 3-5)
• seuil de similarité (>0,7)
3) Optimiser le prompt pour que l'IA réponde clairement à partir du contenu récupéré
4) Utiliser un meilleur modèle d'embedding (ex. text-embedding-3 d'OpenAI)
5) Mettre en cache les réponses aux questions fréquentes (FAQ)
Comment maîtriser les coûts d'une application RAG ?
1) Utiliser la couche gratuite Workers AI (quota Neurons quotidien fixe)
2) Limiter la fréquence des requêtes utilisateur (compteur KV)
3) Mettre en cache les réponses aux questions fréquentes
4) Llama 3 pour les Q&R simples, Claude pour les tâches complexes
5) Surveiller la consommation quotidienne ; près de la limite, ne renvoyer que les résultats de retrieval sans appeler le LLM
Quels cas d'usage concrets pour le RAG ?
1) Q&R base de connaissances entreprise (manuel employé, docs techniques, politiques)
2) Service client intelligent (infos produits, SAV, FAQ)
3) Assistant notes personnelles (retrouver rapidement des années de notes)
4) Outil Q&R documentaire (upload PDF/Word, extraction intelligente)
Tout scénario où il faut répondre à partir de connaissances existantes convient.
14 min de lecture · Publié le: 1 déc. 2025 · Mis à jour le: 27 juil. 2026
Guide Cloudflare AI Stack
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Base vectorielle trop chère ? Vectorize gratuit : recherche sémantique en 30 minutes
Tutoriel Cloudflare Vectorize à coût zéro : recherche sémantique en 30 minutes, ~50 $/mois économisés vs Pinecone. Code complet, pièges à éviter, idéal MVP et projets perso (quota gratuit jusqu'à 5 M de vecteurs).
Partie 4 sur 5
Suivant
C’est le dernier article publié dans cette série pour le moment.



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire