Brief IA

Wikis LLM: Why a Pure Python Compiler is More Efficient

🔬 Research·Tom Levy·

Wikis LLM: Why a Pure Python Compiler is More Efficient

Wikis LLM: Why a Pure Python Compiler is More Efficient
Key Takeaways
1Traditional LLM wikis rely on agents and embeddings to organize notes.
2A pure Python compiler can transform markdown into a structured wiki without excessive complexity.
3Using the standard library allows for bug fixes and performance improvements across different systems.
💡Why it mattersThis approach simplifies the management of textual data, reducing reliance on complex models.
Le brief IA que lisent les pros

Le brief IA que les pros lisent chaque soir

Les 7 actus IA du jour, décryptées en 5 min. Gratuit.

Inclus dès l'inscription : notre sélection des meilleurs guides & comparatifs IA.

Choisis ton rythme

Gratuit · Pas de spam · Désabonnement en 1 clic

📄
Full Analysis

Wikis LLM : pourquoi un compilateur Python pur est plus efficace

Modèles de Langage de Grande Taille

Un développeur a mis au point un pipeline qui compile un dossier de notes textuelles brutes et désordonnées en un wiki markdown lié et vérifié. Aucun appel à un LLM, pas d'embeddings, pas d'API externes, uniquement la bibliothèque standard.

Le pipeline se compose de quatre étapes : un extracteur regex, un constructeur de graphes qui détecte les références croisées, un réécrivain conscient des sections qui préserve tout ce qui est écrit à la main, et un linter qui vérifie sa propre sortie.

Deux véritables bugs ont été rencontrés lors de la construction de ce système : un constructeur de graphes qui ne se scalait pas bien, et un linter qui comptait silencieusement les pages orphelines. Les deux sont décrits dans cet article avec leurs solutions.

Le pipeline complet a été évalué sur trois tailles de corpus sur deux machines différentes (Linux et Windows) et il a été vérifié si les sorties déterministes correspondaient réellement. Elles correspondaient, exactement.

Le code complet, tous les 17 tests et la sortie terminale non arrondie sont inclus ci-dessous pour que chacun puisse tout relancer soi-même.

Pourquoi cet article a été écrit

L'auteur a essayé de construire un wiki LLM à la manière de Karpathy. Boucles d'agents. Appels récursifs à des LLM. Embeddings pour tout.

L'entrée était un dossier de fichiers markdown locaux déjà en possession de l'auteur, stockés sur son propre disque.

Et à mi-chemin, il est apparu à l'auteur qu'il payait des tokens pour réorganiser un texte qu'il possédait déjà.

L'ensemble du pipeline a donc été remplacé par un compilateur Python pur.

Cet article décrit ce système en détail : transformer un dossier de notes textuelles brutes et mal formatées en un wiki markdown lié et vérifié, sans aucun appel à un LLM, aucune API externe et aucune dépendance tierce. Chaque chiffre de référence ci-dessous est réel, a été exécuté sur deux machines différentes (un conteneur Linux et le propre PC Windows de l'auteur), et les deux bugs réels rencontrés lors de sa construction sont inclus.

Pour ceux qui recherchent un compilateur markdown en Python pur, une alternative déterministe aux outils de base de connaissances basés sur des agents, ou une analyse pratique de la construction d'une alternative RAG locale, cet article est fait pour eux.

L'état d'esprit du compilateur

Voici le cadre sur lequel le reste de cet article est construit :

Un agent décide à quoi pourrait ressembler un wiki. Un compilateur garantit à quoi il doit ressembler.

Les pipelines d'agents stochastiques contre les pipelines de compilateurs déterministes. Alors que les flux de travail basés sur des agents introduisent de la variabilité à travers des appels itératifs à des LLM, les architectures basées sur des compilateurs fournissent des sorties cohérentes et reproductibles.

L'auteur voulait que ce wiki soit prévisible. Contrairement à un LLM qui varie sa sortie, un compilateur donne le même résultat chaque fois qu'il est exécuté. Cette cohérence est essentielle pour les notes de référence personnelles de l'auteur. Le système a été structuré de sorte que les pages markdown agissent comme des fichiers objets. Elles sont générées à partir de sources et peuvent être reconstruites à volonté. Le contenu édité à la main est gardé séparé des sections générées par la machine. Voici comment le pipeline est configuré :

L'architecture du système étape par étape du pipeline de compilation Markdown, décrivant les phases d'extraction automatisée, de génération de graphes de liens, de réécriture de sections et de vérification structurelle.

Cela a été décomposé en quatre étapes. Chacune gère une tâche déterministe unique et peut être testée indépendamment. Toute étape qui dépend d'un modèle pour prendre une décision a été évitée.

Pourquoi l'absence de dépendances est importante ici

Tout dans cette base de code fonctionne uniquement sur la bibliothèque standard Python. Pas de sentence-transformers, pas de base de données vectorielle, pas de client HTTP pour une API d'embedding. Ce n'est pas un test de pureté pour le plaisir. C'est une conséquence directe du problème que ce pipeline résout.

Une fois que les appels LLM sont retirés, ce qui reste à faire est l'analyse de texte, la manipulation de chaînes et le parcours de graphes sur un dictionnaire en mémoire. Ce sont exactement les types de problèmes pour lesquels re, os, et les structures de données Python classiques ont été conçus. Se tourner vers une dépendance plus lourde ici n'apporterait pas de correction, cela apporterait juste des frictions d'installation et une chose de plus qui peut échouer pour des raisons qui n'ont rien à voir avec les notes réelles. Si quelqu'un a déjà eu un pip install qui se bloque sur Windows parce qu'une roue compilée pour une bibliothèque d'apprentissage automatique n'était pas disponible pour sa version de Python, il sait déjà pourquoi "ça fonctionne simplement" vaut la peine d'être protégé.

Le problème avec les wikis pilotés par des agents

L'idée d'utiliser un LLM pour construire et maintenir un wiki personnel n'est pas nouvelle, et ce n'est pas l'auteur qui l'a inventée. Elle a gagné en popularité après qu'Andrej Karpathy ait décrit le modèle dans un post largement partagé, où il expliquait qu'il dépensait moins de son budget de tokens à générer du code et plus à construire des bases de connaissances structurées et persistantes à partir de ses notes de recherche. Il a suivi avec un "fichier d'idées" public décrivant l'architecture plus en détail, et a explicitement comparé le processus à la compilation : des sources brutes entrent, un wiki structuré et interconnecté sort, et le LLM est celui qui effectue la compilation.

L'auteur pense que ce cadre de compilation est tout à fait juste. Il ne pense juste pas qu'un LLM doive être le compilateur.

Voici le problème pratique. Si la source brute est déjà locale, déjà textuelle, et déjà déterministe, la faire passer par un système probabiliste pour l'organiser introduit trois coûts qu'un parseur ou un compilateur n'a tout simplement pas :

  • Coût : Chaque fois qu'un nouveau document est ajouté, un wiki piloté par un agent relit le contenu, décide ce qui a changé et réécrit les pages. C'est une dépense de tokens pour un travail d'organisation, pas de synthèse. Cela s'accumule rapidement une fois que le dossier source contient des centaines de fichiers au lieu d'une douzaine.

  • Latence : Chaque cycle de lecture-décision-écriture est un aller-retour réseau si un modèle hébergé est utilisé, et un coût de calcul réel même si quelque chose est exécuté localement. Pour un travail qui consiste fondamentalement à restructurer un texte existant, cette latence n'a aucune raison d'exister.

  • Non-déterminisme : C'est celui qui a réellement affecté l'auteur. Il a exécuté le même dossier à travers un prototype précoce basé sur un agent deux fois et a obtenu deux structures de liens différentes. Rien n'avait changé dans les fichiers source. Le modèle a simplement fait des jugements légèrement différents à chaque fois sur ce qui était considéré comme lié. Pour le code, c'est parfois charmant. Pour ce qui est utilisé comme source de vérité, c'est un problème.

Tout cela ne signifie pas que les LLM sont le mauvais outil pour le travail de connaissance en général. Cela signifie qu'ils sont le mauvais outil pour la partie spécifique du travail qui est réellement déterministe : prendre des entrées connues et produire une structure connue et reproductible. Cette partie est un problème de parsing, pas un problème de raisonnement.

Étape 1 : L'extracteur de métadonnées regex

Les véritables dossiers de notes sont un désordre. Certains fichiers utilisent un # Header, d'autres une ligne en majuscule, et certains n'ont pas de header du tout. Des métadonnées comme "created:" ou "aliases:" peuvent être manquantes ou cachées au milieu du fichier. Tout extracteur s'attendant à un formatage cohérent échoue dès qu'il rencontre un fichier du monde réel, donc l'extracteur a été construit pour gérer le désordre.

Il vérifie d'abord la présence d'un # header. Si cela échoue, il recherche une ligne en majuscule. S'il ne trouve toujours rien, il se base sur le nom de fichier. Il scanne les champs de métadonnées où qu'ils se trouvent plutôt que d'exiger qu'ils soient à un endroit spécifique.

Cela signifie que le pipeline ne plante pas sur une note mal formée ; il fonctionne simplement avec ce qu'il trouve. C'est la partie la plus ennuyeuse du projet, mais elle nettoie la majeure partie du désordre, c'est pourquoi le plus de temps a été passé à s'assurer que cette étape tienne vraiment le coup.

Étape 2 : Le constructeur de graphes

Cette étape gère les liens entre les notes. Un mur de performance a été rencontré ici.

La première version exécutait une regex séparée pour chaque entité contre chaque autre fichier. C'était une approche O(n^2). Avec 100 fichiers, ça allait. Avec 1 000 fichiers, cela prenait 4,4 secondes. Avec 5 000 fichiers, cela prenait 107 secondes. Il avait été supposé que le fait de ne pas appeler une API signifiait que le code serait rapide par défaut. C'était une erreur. L'algorithme compte plus que l'absence d'appels réseau.

Le matching pairwise regex a été remplacé par un matcher de phrases indexé par mots. Maintenant, chaque fichier est tokenisé une fois. En parcourant les tokens, une recherche dans un dictionnaire est utilisée pour vérifier uniquement les noms d'entités qui commencent par le mot actuel. Au lieu de tester chaque nom d'entité contre chaque position, seuls les candidats qui pourraient effectivement correspondre sont vérifiés. Cela transforme un processus qui croît de manière quadratique en un qui évolue beaucoup plus efficacement à mesure que le corpus s'agrandit.

Les résultats ont changé radicalement. L'exécution avec 1 000 fichiers est passée de 4,4 secondes à moins de 50 millisecondes. L'exécution avec 5 000 fichiers est passée de 107 secondes à moins d'une seconde. Ces chiffres spécifiques proviennent de tests préliminaires dans l'environnement de développement Linux, avant même que le pipeline ne soit exécuté sur Windows, donc il ne faut pas s'attendre à ce qu'ils correspondent exactement aux chiffres de Windows plus bas dans cet article ; la section des benchmarks plus loin contient les véritables chiffres de Windows. Les chiffres comptent, donc voici la progression réelle :

| Approche | 100 fichiers | 1 000 fichiers | 5 000 fichiers | |----------|--------------|----------------|----------------| | Regex pairwise naïf (première version) | ~46 ms | ~4 400 ms | ~107 000 ms | | Alternation regex combinée (intermédiaire) | ~12 ms | ~597 ms | ~14 000 ms | | Matcher de phrases indexé par mots (final) | ~2 ms | ~33 ms | ~492 ms |

La ligne du milieu du benchmark mérite d'être notée, car c'était la première tentative de correction et elle a échoué. Une tentative a été faite pour combiner chaque nom d'entité en un seul motif d'alternation massif (Name1|Name2|Name3...). Bien que cela ait réduit le nombre d'objets regex, le moteur sous-jacent devait toujours vérifier la liste complète à chaque position de caractère qu'il scannait. Avec 5 000 entités, cela reste un comportement quadratique déguisé en comportement linéaire. Le matcher indexé par mots était la seule version qui a réellement corrigé la complexité, plutôt que de la cacher derrière un facteur constant plus rapide.

Voici à quoi ressemble réellement le graphe résultant pour trois entités réelles du corpus de test :

Une mise en page architecturale illustrant la relation directe entre la syntaxe de backlink Markdown brute et la visualisation du graphe bidirectionnel analysé.

Brief IA — L'actualité IA en français

L'essentiel de l'actualité de l'intelligence artificielle, décrypté et expliqué chaque jour.