Retour aux réalisations

Projet de recherche · 2025

NPC-LLM

Des dialogues naturels, un scénario maîtrisé

Dialogue de personnages non-joueurs : un graphe écrit à la main, formulé par un modèle

2 personnages, chacun dans son univers, en trois langues · un fichier de persona et un graphe de dialogue par personnage · back et front déployés, démonstration jouable en ligne

Résumé

Problème
Un arbre de dialogue garde le scénario sous contrôle mais enferme le joueur dans un menu. Un modèle libre converse naturellement, sans garantir qu’il livre l’information utile à la quête.
Statut
Projet de recherche, 2025. Démonstration jouable et code du serveur publics.
Rôle
Conception et implémentation.
Solution
Le graphe reste écrit par l’auteur. Le modèle reconnaît l’intention du joueur parmi les suites prévues et formule la réplique dans la voix du personnage.
Résultat
Deux personnages, chacun dans son propre univers, en trois langues. Ajouter un personnage revient à déposer un persona et un graphe, sans modifier le code.
Limite
Aucune mesure automatique ne vérifie la classification des intentions. Ce que le graphe ne précise pas est réinventé à chaque partie.

L’objectif

L'objectif

Dans un jeu de rôle, on parle à un personnage non-joueur avec une manette, en choisissant une réplique dans une liste. Le joueur sait à tout moment qu'il navigue dans un menu.

npc-llm part d'une autre entrée : le joueur écrit ce qu'il veut, en langage naturel, et le personnage lui répond. La contrainte qui commande tout le reste est de ne rien céder sur le scénario. L'auteur garde la main sur ce que le joueur finit par apprendre, et le jeu continue de recevoir un état exploitable. Le joueur peut formuler librement ses messages ; la progression reste définie par le graphe.

L'arbre et le modèle libre

L'arbre de dialogue classique donne ce contrôle. L'auteur écrit chaque réplique, chaque branche mène à une suite prévue d'avance, et le moteur de jeu sait toujours où en est la conversation. Le coût est connu : le joueur choisit dans un menu, deux parties se ressemblent, et l'échange n'a rien d'une conversation.

Brancher un modèle de langage à la place règle la question de la langue et en ouvre deux autres. Le personnage répond à n'importe quelle formulation, différemment à chaque partie, ce qui est précisément l'effet recherché. Rien ne garantit en revanche qu'il finisse par livrer l'information qui débloque la quête, et le moteur de jeu se retrouve avec du texte libre là où il attend un état exploitable, comme le fait que la quête ait été acceptée.

npc-llm conserve l'arbre et déplace le rôle du modèle. Le graphe reste écrit à la main. Le modèle reconnaît ce que le joueur a voulu dire parmi les suites prévues par l'auteur à cet endroit, et rédige la réplique correspondante dans la voix du personnage.

Schéma d'un tour de dialogue : le PNJ parle, le joueur répond en texte libre, le modèle fait correspondre la réponse aux intentions du graphe, puis génère la réplique du nœud atteint.
Un tour de dialogue : le graphe reste écrit à la main, le modèle reconnaît l'intention et formule la réplique.

Décisions techniques

Le graphe de dialogue et les répliques

Le graphe d'un personnage est un fichier JSON. Chaque nœud porte un identifiant, un contenu narratif, une action décrivant ce que le personnage fait à ce moment de l'échange, un indicateur d'accessibilité globale, et la liste des intentions qui en partent. Une intention associe une formulation possible du joueur à l'identifiant du nœud vers lequel elle mène.

{  "id": "info_ia",  "global": true,  "content": "C'est un protocole fantôme militaire. Adaptatif, rapide et hostile. Les hacks ordinaires rebondissent dessus.",  "action": "Décrire l'IA et ses capacités.",  "intents": [    { "content": "Comment on la bat ?", "targetNodeId": "info_contre_mesure" },    { "content": "Peu importe. J'y vais.", "targetNodeId": "fin_conversation" }  ]}
Un nœud réel du graphe de Nexus, cyber-opérateur indépendant.

L’auteur décrit les actions et les chemins possibles dans le graphe. Le modèle formule la réplique à partir de l’action du nœud atteint.

Un tour de dialogue

À chaque tour, le serveur reçoit le message du joueur, l'identifiant du nœud courant, la réplique précédente et le résumé de la conversation. Il rassemble les destinations possibles, réduites à leur identifiant et à leur action, et les soumet au classifieur.

Le modèle renvoie trois éléments : l'identifiant de l'intention retenue, une réplique formulée à partir de l'action de ce nœud, et un résumé mis à jour de l'échange. Le serveur retrouve alors le nœud cible dans le graphe et le renvoie au client, avec la réplique substituée à son contenu par défaut.

Le modèle choisit donc un identifiant dans une liste que le serveur lui soumet, et cette liste ne contient que des nœuds réellement écrits. Une destination hors du graphe n'existe pas comme option. La première réplique fait exception et sort telle qu'elle a été écrite : l'entrée en matière d'un personnage est fixe, la suite est formulée.

Les nœuds globaux

Un arbre strict enferme la conversation. Arrivé au nœud qui décrit la menace, le joueur ne peut plus revenir sur l'équipement. Chaque nœud porte donc un drapeau d'accessibilité globale, et les intentions des nœuds globaux s'ajoutent aux intentions locales avant chaque appel au classifieur.

Chez Nexus, un seul nœud sur neuf reste hors de cette accessibilité générale, celui qui clôt l'échange. Pour le joueur, la conversation ressemble donc à un échange libre ; pour le moteur de jeu, elle reste un déplacement dans un graphe. Un nœud autre recueille ce qui ne correspond à aucune intention, ce qui donne au personnage une réponse en caractère quand le joueur sort du sujet.

La voix du personnage

Chaque personnage a un fichier de persona en texte libre : nom, rôle, âge, ton, traits, motivation, contexte, et une caractéristique distinctive. Ce fichier devient le prompt système, avec la consigne de rester en personnage en toutes circonstances. Celui de Nexus le décrit comme un ancien ingénieur corporatif devenu cyber-opérateur, sang-froid et sarcastique, méfiant envers l'autorité, qui parle comme s'il avait toujours cinq coups d'avance et mêle jargon technique et argot de rue.

Le résumé de conversation forme la seconde partie du prompt système, limité aux cinq derniers échanges. Le modèle le réécrit à chaque tour, dans la même réponse que la classification.

Ajouter un personnage revient à déposer deux fichiers, un persona et un graphe. Aucun code ne change : l'écriture des dialogues reste un travail sur des fichiers de contenu, ce qui permet aux deux personnages d'exister chacun dans son univers, en trois langues.

Stack

TypeScript Node.js Express Mistral AI OpenAPI Swagger Redoc React Vite Vercel

Classification et formulation par mistral-small, température 0,1. Back et front déployés sur Vercel.

Interface
React Vite
API
Node.js Express

Serveur sans état

Modèle
Mistral AI

Classification + formulation

Contenu
Persona + graphe JSON

Fichiers par personnage

Limites et suites

Ce qui n'est pas construit

L'état de la conversation voyage dans la requête. Le nœud courant, la réplique précédente et le résumé sont envoyés par le client à chaque tour, ce qui rend le serveur sans état et déployable en fonction serverless. Un client peut aussi les modifier à sa guise.

Personas et graphes sont des fichiers embarqués dans le déploiement, et le persona entier part dans chaque appel.

Un seul appel assure la classification et la formulation, à une température de 0,1. Le réglage sert la stabilité du classement d'intention, et limite du même coup la variété des formulations, qui est l'autre moitié de ce que le modèle apporte ici. Deux appels séparés rendraient chaque réglage indépendant.

Aucune mesure automatique ne vérifie que le classifieur retient la bonne intention. Le système se juge à l'usage, sur la démonstration.

Une autre limite concerne les informations sur l’univers du jeu. Chez Nexus, la menace est un protocole fantôme militaire, et l'action du nœud correspondant demande d'en décrire les capacités. Le modèle produit tout le reste, si bien que ce que l'action ne précise pas est réinventé à chaque partie. Un joueur qui demande, par exemple, en quelle année ce protocole a été mis en service et pourquoi il a basculé obtient une réponse convaincante ; un autre joueur en obtient une autre, tout aussi convaincante et incompatible. C'est une hallucination au sens strict : le modèle comble un vide que personne n'a rempli, et le joueur n'a aucun moyen de s'en apercevoir.

Les suites identifiées

La réponse à ce dernier point passe par une base de lore que le serveur consulte pour répondre, selon le principe du RAG. L'univers du jeu, ses dates, ses factions, ses évènements, ses personnages, devient un corpus écrit par l'auteur et indexé. Au moment de formuler une réplique, le serveur y retrouve les fragments que la question appelle et les remet au modèle, qui les met en mots. Pour reprendre l'exemple précédent, la date de mise en service du protocole fantôme devient la même pour tous les joueurs, quelle que soit la formulation qui l'a fait sortir, et l'auteur retrouve sur les détails le contrôle qu'il exerce déjà sur les temps forts.

Cette piste permettrait aussi d’étendre le persona et la mémoire du personnage. Un personnage peut porter un passé plus profond que ce qui tient dans un prompt, puisque son persona cesse de partir en entier à chaque appel. Et sa mémoire cesse d'être une fenêtre glissante de cinq répliques, l'historique devenant lui aussi une matière que l'on interroge.

Le reste suit cette logique. Un stockage en base à la place des fichiers, pour un nombre significatif de personnages. Un état de conversation tenu côté serveur, en session authentifiée, qui ferme la possibilité de le manipuler depuis le client. Une comptabilité des tokens avec gestion de la fenêtre de contexte et résumé automatique. Puis un contrôle plus fin du registre émotionnel, et le multilingue.

Au-delà du jeu

La spécification de l'agent de classification a été exercée sur des cas de jeu de rôle, et sur un suivi de commande. Le mécanisme ne tient à rien de spécifique au jeu vidéo : un parcours de conversation écrit à l'avance, dans lequel un modèle reconnaît l'intention et formule la réponse, décrit aussi bien un accueil client guidé.

Contact

Discutons de votre projet.

Vous cherchez à intégrer une fonctionnalité IA, développer une application web ou en confier la responsabilité technique ? Présentez-moi votre contexte, votre équipe et le calendrier envisagé.

Je privilégie les missions longues, entièrement à distance.