Concevoir des moteurs divinatoires sans hallucination : machines à états Rust déterministes et ancrage sémantique par LLM
Un LLM qui calcule seul un thème se trompe sur les traits mutants et les étoiles, car l'échantillonnage de tokens ne préserve pas les invariants discrets. Cette étude de cas lit l'architecture d'InsightApp : un noyau Rust pur produit un graphe de faits JSON, le modèle n'écrit que le texte. Trois limites restent ouvertes.
Transparence : InsightApp et sns.style sont gérés par le même opérateur. Tout le code cité provient du backend d'InsightApp au commit `22cccf4`, avec les chemins de fichiers pour la traçabilité ; le dépôt n'est pas public. Il s'agit d'une étude de cas, pas d'une évaluation indépendante. La version complète est l'édition chinoise ; ceci en est le résumé en français.
Demandez à un grand modèle de langage de tirer un hexagramme du Yi Jing ou de dresser un thème de Zi Wei Dou Shu, puis de l'interpréter : le texte paraît convaincant, mais il résiste mal à la vérification. Un trait mutant est faux, une étoile principale occupe deux palais, ou la transformation « Ji » tombe sur une étoile absente du thème. Le problème n'est pas l'intelligence du modèle, c'est la forme de la tâche. Le calcul du thème relève de la combinatoire discrète ; l'interprétation relève de la langue.
Le moteur Yi Jing et Zi Wei d'InsightApp sépare les deux. Un noyau Rust déterministe calcule le thème et produit un graphe de faits en JSON structuré ; le modèle ne fait que traduire ce graphe en langage. Le « zéro hallucination » du titre vaut pour la couche du thème, pas pour la couche du texte.
Le noyau
Le palais de la Vie vaut `mod12(lunar_month + 1 - hour)`, le palais du Corps `(lunar_month + 1 + hour) % 12`, et le bureau des éléments se lit dans une table 5×6 `NA_YIN_JU` (`backend/src/ziwei/calc.rs`). Les 14 étoiles principales doivent apparaître exactement une fois dans les 12 palais. Un échantillonneur de tokens ne garantit pas ce type d'invariant. Nous n'avons pas mesuré de taux d'erreur pour un modèle seul : c'est un argument structurel, pas un résultat expérimental.
Pour le Yi Jing, le hasard n'intervient qu'au lancer des trois pièces (`backend/src/agent/hexagram.rs`). Chaque pièce vaut 2 ou 3 avec une probabilité de 1/2 ; la somme vaut 6, 7, 8 ou 9 avec des probabilités de 1/8, 3/8, 3/8 et 1/8. Chaque trait est mutant avec une probabilité de 1/4, et l'absence de tout trait mutant survient dans environ 17,8 % des tirages. Si la recherche d'un hexagramme échoue, le moteur renvoie une `EngineError` au lieu d'une valeur par défaut plausible. Voir la page de recherche des 64 hexagrammes et le guide complet des 64 hexagrammes.
La fonction `full_chart` (`backend/src/ziwei/chart.rs`) est pure : ni entrée-sortie, ni hasard. Les champs dérivés `patterns` et `feixing` ne peuvent venir que du serveur. Selon un commentaire du code, la règle des mois intercalaires a été ajoutée après une comparaison avec la bibliothèque libre iztro sur 505 échantillons aléatoires, avec zéro écart ensuite. La chaîne des transformations « Ji » (`backend/src/ziwei/feixing.rs`) est un parcours de graphe borné à une profondeur de 4, qui signale les cycles par `is_loop`. Voir la page des étoiles volantes.
Les limites
Les points d'entrée d'interprétation reçoivent le thème envoyé par le client et ne le recalculent pas côté serveur. La tige céleste annuelle utilise l'approximation `(year - 4) mod 10`, fausse d'un ou deux jours autour de Lichun, comme le code l'indique lui-même. Aucun contrôle ne compare le texte généré au thème après coup. La correction du temps solaire vrai se fait dans le frontend, pas en Rust.
Les tables `STARS_14` et `PALACES_12` génèrent 168 pages « étoile dans un palais », par exemple Zi Wei dans le palais de la Vie. D'autres articles se trouvent sur le blog d'InsightApp.
Sources
FAQ
Pourquoi ne pas laisser un LLM calculer le thème ?
Le calcul enchaîne arithmétique modulaire et lectures de tables, avec des invariants comme l'unicité des 14 étoiles principales. L'échantillonnage de tokens ne les garantit pas. Aucun taux d'erreur n'a été mesuré : c'est un argument structurel.
Que signifie « zéro hallucination » ici ?
Seulement la couche du thème : le noyau Rust est pur et peut être comparé à iztro échantillon par échantillon. Le texte du LLM peut encore se tromper, et rien ne le vérifie après génération.
Quelles limites restent ouvertes ?
Les points d'entrée d'interprétation font confiance au thème envoyé par le client, la tige annuelle est approximée autour de Lichun, et aucun validateur ne contrôle le texte généré. Le temps solaire vrai est corrigé dans le frontend.