RAG (Retrieval Augmented Generation) : donnez un cerveau à vos LLM avec votre documentation technique
Vous avez déployé un LLM local avec Ollama, mais ses connaissances s’arrêtent à sa date d’entraînement. Impossible de lui poser des questions sur votre propre code, votre documentation interne, ou vos procédures ops. C’est là que le RAG entre en jeu.
RAG = Retrieval Augmented Generation. On injecte du contexte externe dans le prompt du LLM pour qu’il réponde à partir de VOS données.
J’ai mis en place une stack RAG complète pour interroger ma documentation technique (procédures ops, schémas d’infra, notes de projet). Voici comment.
Comment ça marche
Le principe est simple en apparence :
- Indexation : on découpe les documents en chunks, on les vectorise, on les stocke dans une base vectorielle
- Recherche : à chaque question, on cherche les chunks les plus pertinents par similarité sémantique
- Génération : on fournit ces chunks au LLM en contexte, il répond à partir de ces seuls documents
La stack que j’utilise
| Composant | Technologie | Rôle |
|---|---|---|
| LLM | Ollama + llama3.2 | Génération des réponses |
| Embeddings | Ollama + nomic-embed-text | Vectorisation des chunks |
| Base vectorielle | ChromaDB | Stockage et recherche des vecteurs |
| Framework RAG | LangChain.js | Orchestration pipeline |
| Source des docs | Fichiers Markdown | Documentation technique |
Indexation des documents techniques
Première étape : charger et découper ma documentation. J’utilise LangChain.js avec un loader Markdown.
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter"; |
Le choix du chunkSize est important. Pour de la documentation technique (procédures, configs), je trouve que 1000 caractères avec 200 de overlap donne un bon équilibre entre granularité et contexte.
Vectorisation et stockage
On utilise ChromaDB qui tourne dans un conteneur Docker :
# docker-compose.yml |
Puis on vectorise et stocke :
import { Chroma } from "@langchain/community/vectorstores/chroma"; |
La recherche RAG
Quand un utilisateur pose une question, on cherche les 4 chunks les plus pertinents :
const retriever = vectorStore.asRetriever(4); |
Génération de la réponse
On injecte ces chunks dans le prompt du LLM :
import { ChatOllama } from "@langchain/ollama"; |
Pourquoi temperature à 0.1 ? Pour une RAG technique, on veut des réponses factuelles et reproductibles, pas créatives.
Améliorations possibles
Une fois la base fonctionnelle, j’ai ajouté quelques optimisations :
Hybrid search : ChromaDB supporte la recherche vectorielle ET par mots-clés. Utile pour les termes techniques précis (noms de packages, commandes).
Parent Document Retriever : au lieu de renvoyer des chunks isolés, on renvoie le document parent entier quand un chunk est matché. Meilleur contexte pour le LLM.
const parentSplitter = new RecursiveCharacterTextSplitter({ chunkSize: 2000 }); |
Reranking : on utilise un petit modèle de cross-encoding pour réordonner les résultats avant de les passer au LLM. Ça améliore significativement la qualité des réponses.
Intégration avec mon workflow
J’ai emballé tout ça dans une API Express avec une interface web minimaliste :
app.post("/ask", async (req, res) => { |
Conclusion
Le RAG est devenu mon outil principal pour explorer ma propre documentation. Plus besoin de fouiller dans 50 fichiers Markdown : je pose une question en langage naturel, j’obtiens une réponse sourcée.
La stack complète tient sur un Raspberry Pi 4 (Ollama + ChromaDB + l’app Node.js). Les embeddings et l’inférence sont un peu lents, mais pour de la consultation occasionnelle, ça fait le job.
Et vous, avez-vous mis en place une RAG pour votre documentation technique ? Quelle stack utilisez-vous ?