Jsiphon - un parseur JSON pour le streaming LLM avec suivi des deltas et détection d’ambiguïté
(github.com/webtoon-today)Bonjour, je vous présente Jsiphon. Il résout un problème fréquent lorsqu’on utilise des réponses structurées avec le streaming LLM.
Quand on utilise des réponses structurées (mode JSON) d’un LLM en même temps que le streaming, on se heurte souvent au problème du parsing de réponses partielles. Dans ce cas, on ne peut pas simplement faire un JSON.parse() et on finit souvent par utiliser une méthode qui tente de restaurer de manière répétée un JSON incomplet.
Mais en exploitant la propriété « append-only, sans inversion d’ordre » des réponses LLM, on peut résoudre ce problème de façon plus élégante, et Jsiphon fournit les trois fonctionnalités suivantes.
-
Parsing append-only — lorsqu’une réponse partielle comme
{"msg": "Helarrive, l’outil renvoie immédiatement une réponse complète comme{msg: "Hel"}. Dans cet exemple, tout ce qui précède le champmsgdans le schéma est déjà considéré comme finalisé. -
Suivi des deltas — à chaque réponse produite, l’outil fournit non seulement le snapshot complet, mais aussi séparément le dernier contenu ajouté. Par exemple, si vous affichez plusieurs bulles de conversation dans un chatbot, cela permet de ne pas tout redessiner, mais seulement d’actualiser l’incrément de la dernière bulle. Si, dans l’exemple précédent, le LLM continue avec
lo, World!, vous pouvez immédiatement retrouver{msg: "lo, World!"}dans ledeltade la réponse. Il n’est donc plus nécessaire de refaire à chaque snapshot un parsing de restauration JSON puis un diff. -
Détection d’ambiguïté — l’outil renvoie un arbre d’ambiguïté (
ambiguity tree) ayant exactement la même structure arborescente que la réponse. Il indique, à plusieurs niveaux de profondeur, si les données présentes dans le snapshot sont déjà déterminées ou si la lecture de la réponse est encore en cours. Par exemple, lors du streaming des données suivantes{"header":{"title": "abcdefghijk","date": "..."},"body": "..."}
en utilisant
isAmbiguous(ambiguous.header.title), il devient possible d’utilisertitleen toute sécurité à partir du moment où il est terminé (réponse n°3), sans attendre que les champs suivants soient finalisés. Comme l’outil fournit une finalisation partielle à tous les niveaux, et pas uniquement une finalisation globale,isAmbiguous(ambiguous.header)ne renverrafalseque lorsque tous les descendants deheaderseront terminés.
Il existe déjà de nombreuses bibliothèques de restauration/parsing de JSON partiel (partial-json, gjp-4-gpt, etc.) qui résolvent très bien le problème fondamental du parsing. Mais Jsiphon exploite la caractéristique append-only du streaming LLM pour aller plus loin que la simple fourniture de snapshots : il fournit aussi des deltas par champ et permet d’identifier, à chaque itération, les champs déjà finalisés.
Si vous travaillez déjà sur un problème similaire, cela vous parlera probablement. De mon côté, je combine Jsiphon avec du SSE multi-type pour qu’un chatbot puisse streamer du texte tout en déterminant en temps réel plusieurs indicateurs (is_adult, need_admin, etc.).
En plus, côté pratique, il est sans dépendance, ne lève pas d’erreur même avec des réponses incorrectes, et inclut des fonctions utilitaires comme la suppression du texte sans signification avant et après le JSON.
GitHub: https://github.com/webtoon-today/jsiphon
npm install jsiphon
Si cela peut vous être utile, n’hésitez pas à l’essayer et à me faire part de vos retours.
L’ambiguity tree me semble être un choix de conception assez ambitieux, et je serais curieux de savoir s’il existe une meilleure approche. Je vous serais reconnaissant pour tout feedback sur le design de l’API.
Aucun commentaire pour le moment.