Comprendre et implémenter le RAG pour enrichir les réponses des LLM avec vos propres données via embeddings et vector stores.
Qu'est-ce que le RAG ?
RAG (Retrieval-Augmented Generation) est une technique qui enrichit les réponses d'un LLM avec des données externes pertinentes, récupérées dynamiquement à chaque question.
Sans RAG, un LLM ne connaît que ses données d'entraînement. Avec RAG, il peut répondre sur tes propres documents (documentation, base de connaissance, PDF, etc.).
- Indexation — tes documents sont découpés, convertis en vecteurs et stockés
- Recherche — la question de l'utilisateur est comparée aux vecteurs pour trouver les passages pertinents
- Génération — le LLM reçoit la question + les passages trouvés et génère une réponse contextualisée
Les embeddings
Un embedding est une représentation vectorielle (tableau de nombres) d'un texte. Des textes similaires ont des vecteurs proches dans l'espace mathématique.
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// Générer un embedding pour un texte
const response = await openai.embeddings.create({
model: 'text-embedding-3-small',
input: 'Angular est un framework TypeScript développé par Google.',
});
const vector = response.data[0].embedding;
console.info((`Vecteur de dimension : ${vector.length}`); // 1536 dimensions
console.info(vector.slice(0, 5)); // [-0.012, 0.034, -0.007, ...]
text-embedding-3-small (1536 dimensions, 0.02$/1M tokens) est le meilleur rapport qualité/prix. text-embedding-3-large (3072 dimensions) est plus précis mais plus cher.
Vector Store
Un vector store est une base de données spécialisée pour stocker et rechercher des vecteurs efficacement.
# Options populaires :
# - Pinecone : cloud, scalable, simple
# - Chroma : open source, local ou cloud
# - pgvector : extension PostgreSQL
# - Qdrant : open source haute performance
# - Supabase : PostgreSQL + pgvector managé
npm install chromadb @langchain/community
import { Chroma } from '@langchain/community/vectorstores/chroma';
import { OpenAIEmbeddings } from '@langchain/openai';
import { Document } from '@langchain/core/documents';
const embeddings = new OpenAIEmbeddings();
// Créer et peupler le vector store
const vectorStore = await Chroma.fromDocuments(
[
new Document({ pageContent: 'Angular utilise TypeScript.', metadata: { source: 'doc-1' } }),
new Document({ pageContent: 'React est une librairie JavaScript.', metadata: { source: 'doc-2' } }),
new Document({ pageContent: 'Vue.js est progressif et léger.', metadata: { source: 'doc-3' } }),
],
embeddings,
{ collectionName: 'frameworks-web' }
);
Recherche sémantique
La recherche sémantique trouve les documents dont le sens est proche de la question, même sans mots-clés exacts.
// Recherche par similarité (top 3)
const results = await vectorStore.similaritySearch(
'quel framework utilise TypeScript ?',
3
);
results.forEach((doc, i) => {
console.info(`[${i+1}] ${doc.pageContent} (source: ${doc.metadata.source})`);
});
// [1] Angular utilise TypeScript.
// [2] React est une librairie JavaScript.
// [3] Vue.js est progressif et léger.
// Avec score de pertinence
const resultsWithScore = await vectorStore.similaritySearchWithScore(
'TypeScript',
2
);
resultsWithScore.forEach(([doc, score]) => {
console.info(`Score: ${score.toFixed(3)} — ${doc.pageContent}`);
});
Génération avec contexte
Combine les résultats de la recherche avec le LLM pour générer une réponse ancrée dans tes données.
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
async function answerWithRAG(question, vectorStore) {
// 1. Rechercher les documents pertinents
const docs = await vectorStore.similaritySearch(question, 3);
const context = docs.map(d => d.pageContent).join('\n');
// 2. Construire le prompt avec contexte
const systemPrompt = `Tu es un assistant. Réponds uniquement en te basant sur ce contexte :
${context}
Si la réponse n'est pas dans le contexte, dis que tu ne sais pas.`;
// 3. Générer la réponse
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: question },
],
});
return response.choices[0].message.content;
}
const answer = await answerWithRAG('Quel framework utilise TypeScript ?', vectorStore);
console.info(answer); // "Angular utilise TypeScript."
Pipeline RAG complet
LangChain propose un RetrievalQAChain qui automatise tout le pipeline RAG en quelques lignes.
import { RetrievalQAChain } from 'langchain/chains';
import { ChatOpenAI } from '@langchain/openai';
const model = new ChatOpenAI({ model: 'gpt-4o' });
const retriever = vectorStore.asRetriever({ k: 3 });
const chain = RetrievalQAChain.fromLLM(model, retriever, {
returnSourceDocuments: true,
});
const result = await chain.invoke({ query: 'Quel framework utilise TypeScript ?' });
console.info(result.text);
console.info('Sources:', result.sourceDocuments.map(d => d.metadata.source));
- Découpe tes documents en chunks de 500-1000 tokens avec overlap pour ne pas perdre le contexte
- Utilise des métadonnées (
source,date) pour filtrer les résultats - Teste la qualité de la recherche avant la génération — c'est souvent là que ça coince
- Hybride search (vecteurs + mots-clés) améliore la précision de 20-30%