Ask HN : Comment implémentez-vous le RAG en local ?
(news.ycombinator.com)- Sur Hacker News, un utilisateur demande comment les autres implémentent le Retrieval-Augmented Generation (RAG) dans un environnement local
- Une tendance forte se dégage : en RAG local, il est souvent possible de très bien s’en sortir sans base de données vectorielle, avec de la recherche textuelle comme SQLite FTS5, BM25 ou
grep - Pour la recherche dans le code, beaucoup rapportent que les embeddings sont lents et bruités, et plusieurs estiment qu’une approche à base de mots-clés comme BM25 + trigrammes fonctionne mieux
- Même lorsqu’une recherche vectorielle est nécessaire, de nombreux exemples montrent qu’on peut s’en sortir avec une configuration légère comme Postgres + pgvector, le stockage de vecteurs en BLOB dans SQLite, ou un chargement FAISS en mémoire
- Il est possible d’améliorer la qualité de recherche avec des combinaisons comme la recherche hybride BM25 + vecteurs, le RRF (Reciprocal Rank Fusion), le reranking ou l’expansion multi-requêtes
- Plutôt que de figer le principe « RAG = base de données vectorielle », on voit se dessiner une tendance consistant à choisir entre recherche simple → hybride → agentique selon le type de documents, l’échelle et la charge opérationnelle
Conclusion commune sur l’étape de recherche
- Au lieu de partir du principe qu’une base vectorielle ou un graphe est indispensable, beaucoup privilégient une approche consistant à commencer simplement selon l’infrastructure existante, les types de fichiers et les performances requises
- Certains mentionnent qu’une approche où un agent interroge directement le système de fichiers ou des API est plus simple à configurer et à maintenir, mais peut être un peu plus lente
- L’idée que « ce que le RAG transmet au LLM, ce sont de courts fragments textuels issus de la recherche » amène à recentrer les efforts d’optimisation sur la qualité de la recherche
- À propos de la « définition du RAG », certains répondent que retrieval + generation suffit à parler de RAG, même sans base vectorielle, tandis que d’autres estiment que le terme suppose souvent ce type d’outil
Modèles d’embedding et recherche vectorielle
- Le modèle d’embedding mdbr-leaf-ir, développé chez MongoDB, fonctionne uniquement sur CPU et s’est classé 1er sur plusieurs leaderboards dans cette catégorie de taille
- Sur un serveur standard à 2 vCPU, il peut traiter environ 22 documents par seconde et 120 requêtes par seconde
- Il obtient 53,55 sur le benchmark BEIR (contre 42,69 pour all-MiniLM-L12-v2)
- Des embeddings statiques de mots comme model2vec/minish sont plus rapides en inférence, mais moins précis pour la recherche
- Ils se limitent à la tokenisation + table de correspondance + moyenne, donc restent plus rapides que les approches basées sur des transformers
- Une autre approche consiste à générer des vecteurs par chunk de texte avec Meta-Llama-3-8B, à les stocker dans une colonne BLOB SQLite, puis à effectuer la recherche avec FAISS
- À l’échelle de 5 millions de chunks, cela consomme environ 40 Go de mémoire
- Sur une A6000,
faiss-gpuest très rapide, et sur un M1 Ultra,faiss-cpuest plus lent mais reste suffisant pour quelques requêtes par jour
Recommandations pour la recherche dans le code
- Pour le code, il est recommandé d’éviter les bases de données vectorielles et de privilégier une combinaison BM25 + trigrammes
- Les embeddings sont lents et peu adaptés au code
- Sans reranker, le bruit est important, et la réindexation des fichiers est coûteuse
- La vitesse de réponse est élevée et la qualité des résultats est jugée excellente
- Dans PostgreSQL, il est possible d’implémenter une recherche BM25 avec plpgsql_bm25
- Le support de la recherche hybride avec pgvector + Reciprocal Rank Fusion est également mentionné
- Appliquer des embeddings au chemin de fichier + à la signature, puis fusionner cela avec BM25, peut donner de bons résultats
- Une approche agentique consistant à exécuter gpt-oss 20B avec
ripgrepdans une bouclewhileest aussi décrite comme efficace
Solutions basées sur des bases de données
- SQLite FTS5 : bien adapté aux documents basés sur des fichiers Markdown, et permet de mettre en place un RAG même sans base de données vectorielle
- On peut ajouter à chaque fichier un court champ descriptif pour naviguer dans les documents via la recherche par mots-clés
- Il est aussi possible de stocker des vecteurs fp16 dans SQLite sous forme de BLOB, de créer un sous-ensemble via des filtres, puis de calculer la similarité en mémoire
- Parmi les autres options citées : sqlite-vec, sqlite-vector, vec0 et le bm25 de SQLite
- « SQLite fonctionne étonnamment bien »
- PostgreSQL + pgvector : permet de réutiliser les compétences Postgres déjà en place et facilite la transmission à l’équipe d’exploitation
- La bibliothèque llmemory prend aussi en charge le BM25 hybride, l’expansion multi-requêtes et le reranking
- LanceDB : une base vectorielle embarquée pratique à utiliser
- Utilisée avec les embeddings nomic-embed-text d’Ollama
- DuckDB : propose une extension de recherche par similarité vectorielle, adaptée aux petits projets de moins de 3 Go
- Meilisearch, Typesense, Manticore : plus simples à exploiter qu’Elasticsearch/OpenSearch
Recherche hybride et agentique
- nori (usenori.ai) : combine recherche sémantique et recherche lexicale avec SQLite + vec0 + fts5
- Turbopuffer : prend en charge la recherche hybride vecteurs + BM25
- La simple combinaison de recherche agentique et de recherche textuelle peut déjà donner de très bons résultats
- Ajouter une recherche vectorielle et un graph RAG peut apporter un léger gain de vitesse et de qualité
- Claude Code / Codex utilisent ripgrep en interne
- Appliquer des embeddings aux chemins de fichiers peut aussi être efficace, et la fusion avec BM25 améliore encore les résultats
Cas d’usage de BM25
- shebe : outil CLI/MCP d’indexation et de recherche de code basé sur BM25
- Particulièrement utile dans les workflows de refactoring (par ex. lister les emplacements à modifier lors d’une mise à niveau d’Istio)
- Dans 85 % des cas, une simple correspondance par tags suffit sans base de données vectorielle
- Des opérateurs ont ajouté des tags à la fois aux entrées et aux documents pour atteindre un taux de correspondance de 100 %
- Certains considèrent que la plupart des bases vectorielles sont « un marteau pour résoudre un problème de non-trouvabilité »
Outils et bibliothèques spécifiques
- qmd : outil CLI de recherche dans des fichiers Markdown, avec de meilleurs résultats en requêtes floues que
fzf - ck : outil de grep sémantique écrit en Rust
- Kiln : permet d’ajouter des fichiers en glisser-déposer et de comparer plusieurs configurations
- Prend en charge la comparaison des méthodes d’extraction, des modèles d’embedding et des modes de recherche (BM25, hybride, vectoriel)
- Inclut l’évaluation de la précision de recherche et la génération automatique de jeux de données d’évaluation
- libragen : serveur CLI/MCP servant à créer une bibliothèque de contenus RAG versionnée
- Peut transformer un dépôt GitHub en base de données RAG
- piragi : bibliothèque Python de RAG simple, prenant en charge diverses sources comme le local, S3 ou des API
- ragtune : outil CLI pour le débogage et le benchmarking de la recherche dans un RAG local
Traitement documentaire et OCR
- discovery : effectue l’OCR de documents avec Qwen-3-VL-8B et stocke les vecteurs dans ChromaDB
- Met en œuvre un RAG hybride BM25 + embeddings
- docling : outil d’extraction de documents utilisé dans plusieurs projets RAG
- Lors de la conversion de PDF, le traitement des tableaux, des mises en page multi-colonnes et des tableaux s’étendant sur plusieurs pages reste difficile
- Le modèle Mistral OCR donne les meilleurs résultats (modèle non public)
Mémoire et gestion du contexte
- Ce que le RAG transmet au LLM, ce sont uniquement de courtes chaînes de résultats de recherche
- Sur les petits modèles, une valeur de TOP_K autour de 5 semble être une limite, au-delà de laquelle on observe un oubli du contexte
- On peut améliorer cela en pré-résumant les fichiers et dossiers
- Certains utilisent aussi une approche consistant à tout mettre dans le contexte avec Sonnet + une fenêtre de contexte de 1M
- Un exemple mentionne la construction d’un système de mémoire pour Claude Code via recherche sémantique sur des fichiers de session
Usage en entreprise et à grande échelle
- Lorsqu’on traite 300 000 interactions clients par jour, la latence et la précision sont des facteurs critiques
- Une approche hybride embeddings + recherche plein texte + IVF-HNSW est utilisée
- La gestion de la diffusion de l’information à travers environ 600 systèmes distribués constitue un défi
- Une approche KAG (Knowledge Augmented Generation) est testée pour cartographier des règles métier
- Un RAG entièrement local a aussi été mis en place avec succès sur plus de 500 000 articles de presse via une base vectorielle Postgres
Autres outils et approches
- AnythingLLM : inclut un bundle de base vectorielle pour les documents
- LibreChat : inclut également une base vectorielle packagée pour les documents
- ChromaDB : utilisé via une extension Obsidian pour la recherche sémantique/hybride
- SurrealDB : utilisé en combinaison avec une vectorisation locale
- Interface de requêtes OData : efficace lorsqu’elle est fournie comme outil au LLM, y compris pour analyser un fichier Excel de 40 000 lignes
- Nextcloud MCP Server : utilise Qdrant comme base vectorielle et fournit une recherche sémantique sur des documents personnels
- LSP (Language Server Protocol) : ajouté à Claude Code, mais des bugs existent actuellement
- TreeSitter peut être plus utile (recherche par nom de symbole, navigation entre définitions et usages)
3 commentaires
En voyant les performances de notre système RAG interne assez bricolé, ce genre de post me fait effectivement un peu changer de perspective.
Je me demande si le coréen est bien pris en charge.
Avis sur Hacker News
Notre équipe exploite une base de données de questions-réponses
Les questions et les réponses sont toutes indexées à la fois avec un index trigramme et des embeddings, puis stockées dans Postgres
Lors de la recherche, nous utilisons
pgvectoret la recherche trigramme ensemble, puis fusionnons les résultats à l’aide d’un score de pertinencePour l’étape de recherche, nous avons développé un modèle d’embedding de texte très efficace et optimisé pour le CPU
Il s’agit du modèle MongoDB/mdbr-leaf-ir, classé n°1 du leaderboard parmi les modèles de même taille
Il est compatible avec le modèle Snowflake/snowflake-arctic-embed-m-v1.5
Le démo search-sensei permet de comparer recherche sémantique vs BM25 vs hybride
Par exemple, le modèle d’embedding reconnaît que « j lo » signifie « Jennifer Lopez »
Nous avons aussi publié la recette d’entraînement, qui permet un apprentissage facile même avec du matériel modeste
Je génère des vecteurs avec Meta-Llama-3-8B depuis avril 2024
J’utilisais Python et Transformers sur une RTX-A6000 : c’était rapide, mais il y avait beaucoup de bruit et de chaleur
Je suis ensuite passé à un M1 Ultra avec la bibliothèque MLX d’Apple, avec une vitesse similaire mais bien plus silencieuse
Les modèles Llama ont 4k dimensions, soit 8 KB par chunk en fp16, et je les stocke avec
numpy.save()dans une colonne BLOB de SQLiteLors de la recherche, je charge tous les vecteurs depuis SQLite, je les transforme en
numpy.array, puis je fais la recherche avec FAISSLe faiss-gpu de la RTX6000 est extrêmement rapide, et le faiss-cpu du M1 Ultra est aussi largement suffisant pour mon usage (quelques requêtes par jour)
Avec 5 millions de chunks, l’utilisation mémoire est d’environ 40 GB, ce que les deux machines gèrent sans problème
La plupart de mes documents complexes sont des fichiers Markdown
Je recommande un petit outil CLI appelé tobi/qmd
Avant, j’utilisais un workflow basé sur fzf, mais cet outil offre une meilleure recherche floue
Je ne l’utilise pas pour la recherche dans le code
Je déconseille d’utiliser une base de données vectorielle pour la recherche de code
Les embeddings sont lents et mal adaptés au code
La combinaison BM25 + trigramme donne de meilleurs résultats et répond plus vite
On peut regarder le projet plpgsql_bm25
Il inclut des exemples de fusion BM25 + pgvector avec Reciprocal Rank Fusion ainsi que des notebooks Jupyter
Avec des modèles non conçus pour le code, la recherche vectorielle génère beaucoup de bruit
Maintenant, faire tourner
gpt-oss 20Ben boucle avec ripgrep est bien plus rapide et précisC’est encore meilleur en le fusionnant avec BM25
J’ai créé local-LLM-with-RAG pour expérimenter le RAG en local
Je génère les embeddings avec « nomic-embed-text » d’Ollama et j’utilise LanceDB comme base vectorielle
Récemment, je l’ai mis à jour vers un « agentic RAG », mais c’est peut-être excessif pour de petits projets
Je stocke des vecteurs fp16 dans SQLite sous forme de BLOB, puis après filtrage je les charge en mémoire et je calcule la similarité via un produit matrice-vecteur (matvec)
Avec le multithreading / BLAS / GPU de numpy ou torch, c’est très rapide
Si cela devient un goulot d’étranglement, je migrerai vers sqlite-vector
Comme les filtres sur la date ou la localisation réduisent fortement le volume de données, c’est efficace
Le backend est caché derrière une interface interchangeable
95 % de mes documents sont de petits fichiers Markdown, donc j’utilise SQLite FTS5 avec un index de recherche en texte intégral
L’index existait déjà, je l’ai donc branché directement à un agent mastra
Chaque fichier a un court champ de description : après une recherche par mots-clés, si la description correspond, je charge le document complet
La mise en place a pris environ une heure et cela fonctionne très bien
La recherche par embeddings est plus courante, mais au fond le principe est le même
Comme nous connaissons bien Postgres, nous avons commencé avec PGVector
Plus tard, nous avons constaté qu’un contenu nécessitant des champs semi-structurés dans le prompt correspondait à 100 %
C’est parce que les opérateurs ont commencé à ajouter des tags à la fois aux entrées et aux documents (environ 50 documents)
Nous cherchons donc d’abord dans les champs pour insérer le bon fichier dans le prompt, puis nous faisons ensuite une recherche par embeddings
Au final, dans 85 % des cas, la base vectorielle n’est pas nécessaire
J’ai créé llmemory, que j’utilise à la fois en local et dans l’app de mon entreprise
C’est basé sur PostgreSQL + pgvector, avec BM25 hybride, expansion multi-requêtes et reranking
Je le rends public pour la première fois, donc il peut encore y avoir quelques bugs
Je suis assez satisfait des performances