Un développeur crée un système RAG basé sur des modèles locaux et fait passer la précision de recherche de 20 % à 53 %

Un développeur (auteur du projet sur GitHub sous le pseudonyme tzar26) a assemblé un système RAG entièrement auto-hébergé pour l'analyse de l'actualité — sans un seul appel à OpenAI ou Anthropic. L'ensemble de la pile repose sur des modèles locaux Qwen 2.5 14B et BGE-M3 via Ollama, avec une base PostgreSQL. L'objectif principal est l'indépendance vis-à-vis des fournisseurs externes et le contrôle total des données. Au départ, la recherche sur les 12 000 articles collectés fonctionnait uniquement par embeddings vectoriels, et pour la requête « or », le système renvoyait des articles sur un patineur ayant décroché l'or lors d'une compétition, plutôt que sur le cours du métal. Le développeur a ajouté une recherche textuelle classique BM25 et l'a combinée à la recherche vectorielle via l'algorithme RRF — résultat : la part d'articles pertinents dans le top 5 est passée de 20 % à 53 %. Le prompt de classification des sujets a lui aussi été réécrit : auparavant, par crainte de se tromper, le modèle reléguait 74 % des articles dans la catégorie fourre-tout « other » ; après correction, ce chiffre est tombé à 0,03 %, avec une précision de classification de 85 % confirmée par vérification manuelle. • L'agent basé sur LangGraph choisit lui-même parmi trois outils : recherche textuelle, agrégation de métriques en SQL, et recherche par entreprises mentionnées avec analyse de tonalité • Le passage de LangChain à un client Ollama direct a accéléré le pipeline d'un facteur 9 • Le réglage d'Ollama (deux requêtes parallèles au lieu d'une) a accéléré la classification des articles de 1,5 fois

Traité par IA depuis Habr AI ; édité par Hamidun News
Un développeur crée un système RAG basé sur des modèles locaux et fait passer la précision de recherche de 20 % à 53 %
Source : Habr AI. Collage: Hamidun News.
Écouter l'article
Fiche synthèse et chiffres clés
ParamètreDonnées
Source primaireHabr AI ↗
Rédacteur en chef
Chiffre clé #1Le passage de LangChain à un client Ollama direct a accéléré le pipeline d'un facteur 9
Chiffre clé #2Le réglage d'Ollama (deux requêtes parallèles au lieu d'une) a accéléré la classification des articles de 1,5 fois
Chiffre clé #3`search_articles` — recherche hybride classique dans le texte

Pourquoi la recherche vectorielle classique échoue sur les homonymes

Un développeur connu sous le pseudonyme tzar26 a publié sur GitHub une analyse détaillée de son système d'analyse d'actualités — entièrement autonome, sans aucun appel à des API cloud comme OpenAI ou Anthropic. Tous les modèles tournent localement via Ollama : Qwen 2.5 14B pour le raisonnement et la classification, BGE-M3 pour les représentations vectorielles de texte. La raison de cette approche est explicitement mentionnée dans l'article : résilience face aux sanctions et indépendance vis-à-vis des fournisseurs externes. La pile obtenue — Python, FastAPI, PostgreSQL avec l'extension pgvector, Celery pour les tâches en arrière-plan, LangGraph pour l'agent et Langfuse pour le monitoring — a été conteneurisée avec Docker et couverte de tests via GitHub Actions.

Le système a rassemblé plus de 12 000 articles et, dans un premier temps, ne les recherchait que via la distance cosinus entre embeddings BGE-M3. Sur les requêtes simples, tout fonctionnait correctement, mais des sujets complexes comme « taux clé de la banque centrale » renvoyaient du bruit. La requête « or » a mis le problème en évidence de façon particulièrement frappante : au lieu d'articles sur le cours du métal, la recherche retrouvait honnêtement des articles sur un patineur ayant décroché l'or lors d'une compétition — une confusion classique due à la polysémie du mot, que le vecteur ne sait pas désambiguïser selon le contexte.

La solution a été une recherche hybride : à la comparaison vectorielle s'est ajoutée une recherche textuelle exacte BM25 basée sur PostgreSQL (via le tsvector intégré), et les résultats des deux méthodes ont été fusionnés grâce à l'algorithme RRF (Reciprocal Rank Fusion) — qui prend la position d'un document dans chaque liste de résultats et calcule un rang global. BM25 capture bien les termes exacts comme « OPEP » ou « taux », tandis que la recherche vectorielle gère les synonymes et les liens sémantiques. Au total, la part de documents pertinents dans les cinq premiers résultats de recherche (métrique Recall@5) est passée de 0,2 à 0,53, soit plus du double.

Comment arrêter de tout reléguer dans la catégorie fourre-tout

Un problème distinct est apparu lors de la classification automatique des articles par thème. Dans la première version du prompt, le modèle envoyait 74 % de tous les articles dans la catégorie « other » — c'est-à-dire que près des trois quarts de la base se retrouvaient sans étiquette utile. La cause s'est révélée simple : l'instruction contenait la phrase « en cas de doute, choisis other », et le modèle, par crainte de se tromper, en abusait massivement.

Le développeur a réécrit le prompt : il a ajouté des descriptions précises pour chaque catégorie, notamment le commerce de détail (retail), la macroéconomie (macro) et les incidents (incident), et a supprimé la formulation sur le doute. Après cela, la part d'articles non classés est tombée à 0,03 %. Pour s'assurer de la fiabilité de ces chiffres, l'auteur a en plus vérifié manuellement un échantillon aléatoire d'articles classés — la précision de la classification s'élevait à 85 %.

Un agent qui calcule, pas seulement qui cherche

Une recherche classique dans la base répond à des questions comme « qu'écrit-on sur le pétrole », mais c'est insuffisant pour de l'analyse poussée. L'auteur a donc construit sur LangGraph un agent disposant de trois outils au choix :

  • `search_articles` — recherche hybride classique dans le texte
  • `get_metrics` — agrégation SQL, par exemple compter le nombre d'articles sur l'énergie au cours des trois derniers jours
  • `search_by_entity` — recherche par noms d'entreprises extraits, avec prise en compte de la tonalité du texte (résultat de modèles NER et de sentiment distincts)

Face à la question « y a-t-il des nouvelles négatives sur la banque centrale », l'agent décide lui-même quel outil appeler — il n'a pas besoin qu'on lui précise explicitement qu'il faut calculer une tonalité plutôt que simplement chercher du texte. Pour déboguer cette logique, une instance auto-hébergée de Langfuse a été déployée — elle affiche chaque étape de la chaîne « planificateur → appel d'outil → réponse finale », le nombre de tokens consommés à chaque étape et les arguments exacts transmis par le modèle aux fonctions.

Les embûches techniques du matériel local

L'exécution locale des modèles a apporté ses propres problèmes, atypiques pour des API cloud :

  • Ollama décharge les modèles de la mémoire vidéo lors des changements entre eux, et une requête pouvait prendre jusqu'à 60 secondes — corrigé avec la variable `OLLAMA_MAX_LOADED_MODELS=2`
  • La bibliothèque LangChain utilise en interne une agrégation en streaming des réponses, ce qui provoquait un ralentissement par neuf — elle a été retirée du pipeline au profit du client direct `ollama.AsyncClient`
  • SQLAlchemy lie le pool de connexions à la boucle d'événements (event loop), et lorsque Celery interrompait une tâche, les connexions restaient « zombies » — résolu en appelant `await engine.dispose()` après chaque tâche
  • Par défaut, Ollama traite les requêtes de façon séquentielle ; la classification d'un article prenait environ 10 secondes, et faire passer le paramètre `OLLAMA_NUM_PARALLEL` de 1 à 2 a accéléré le processus d'au moins 1,5 fois

Le projet est actuellement au stade de MVP public, disponible en accès libre sur GitHub. La prochaine étape, selon l'auteur, est déjà en cours en privé : relier les entreprises mentionnées aux tickers de la Bourse de Moscou (comme SBER et GAZP) et construire des tableaux de bord prédictifs par action. Pour les ingénieurs qui envisagent une pile locale plutôt que des API cloud, la conclusion pratique principale est la suivante : les économies sur les appels d'API sont réelles, mais elles se paient en temps consacré au réglage de l'infrastructure — du paramétrage du parallélisme d'Ollama à la gestion des connexions dans du code asynchrone.

Dossier

Questions clés sur cet article

Pourquoi la recherche vectorielle classique échoue sur les homonymes?

Un développeur connu sous le pseudonyme tzar26 a publié sur GitHub une analyse détaillée de son système d'analyse d'actualités — entièrement autonome, sans aucun appel à des API cloud comme OpenAI ou Anthropic. Tous les modèles tournent localement via Ollama : Qwen 2.5 14B pour le raisonnement et la classification, BGE-M3 pour les représentations vectorielles de texte. La raison de cette approche est explicitement mentionnée dans l'article : résilience face aux sanctions et indépendance vis-à-vis des fournisseurs externes. La pile obtenue — Python, FastAPI, PostgreSQL avec

Comment arrêter de tout reléguer dans la catégorie fourre-tout?

Un problème distinct est apparu lors de la classification automatique des articles par thème. Dans la première version du prompt, le modèle envoyait 74 % de tous les articles dans la catégorie « other » — c'est-à-dire que près des trois quarts de la base se retrouvaient sans étiquette utile. La cause s'est révélée simple : l'instruction contenait la phrase « en cas de doute, choisis other », et le modèle, par crainte de se tromper, en abusait massivement. Le développeur a réécrit le prompt : il a ajouté des descriptions précises pour chaque catégorie, notamment le commerce

Que sait-on sur Un agent qui calcule, pas seulement qui cherche ?

Une recherche classique dans la base répond à des questions comme « qu'écrit-on sur le pétrole », mais c'est insuffisant pour de l'analyse poussée. L'auteur a donc construit sur LangGraph un agent disposant de trois outils au choix : `search_articles` — recherche hybride classique dans le texte `get_metrics` — agrégation SQL, par exemple compter le nombre d'articles sur l'énergie au cours des trois derniers jours `search_by_entity` — recherche par noms d'entreprises extraits, avec prise en compte de la tonalité du texte (résultat de modèles NER et de sentiment distincts) Fa

ZK
Zhemal Khamidun — CPO d'Alpina Digital, product manager d'AlpinaGPT. Conçoit des produits IA depuis 2019. Hamidun News est un projet personnel devenu un agrégateur en production avec plus de 6 000 lecteurs.
✦ Hands-On AI Engineering · Hamidun Academy

Build & Ship Production AI Agents Without Boilerplate Code

Start your free 72-hour trial at Hamidun Academy (academy.hamidun.com) — interactive lessons on Claude Code & Cursor, live Tech Radar, and production agent templates.

Start 72h Free Trial →Vibe-Coding Intensive
Qu'en pensez-vous ?
Chargement des commentaires…