Aller au contenu

SFT et modèle de conversation XTML

L'ajustement supervisé

Le SFT établit la politique de démarrage à froid (cold-start policy) sur laquelle le RL pourra travailler.

Ce qui change par rapport aux générations précédentes

Le pipeline est celui de Kimi K2 et K2.5, mais le jeu de données est substantiellement élargi, en particulier sur les tâches agentiques complexes.

La chaîne de production des données :

1. Synthèse de trajectoires par des modèles spécialisés
   de la série Kimi précédente
              │
              ▼
2. Vérification multi-étapes
              │
              ▼
3. Annotation avec humain dans la boucle
              │
              ▼
4. Sérialisation au format XTML

La boucle générationnelle

Les données de SFT de K3 sont produites par les modèles Kimi antérieurs. C'est devenu la norme : chaque génération sert de professeur à la suivante.

Le risque associé — la dérive et l'amplification des biais du professeur — est mitigé par la vérification et l'annotation humaine, mais pas éliminé. Le rapport ne le discute pas.

Ce que le SFT installe

Le rapport énumère trois capacités : raisonnement adaptatif, appel d'outils précis, exécution robuste dans des scénarios agentiques long-horizon.

La quantification commence ici

Point important

La QAT MXFP4 est appliquée dès le stade SFT, et se poursuit dans tout le post-entraînement, RL compris. Le modèle ne découvre donc jamais la quantification après coup : il apprend avec elle.

Détail en Quantification et modèle brouillon.

Le format XTML

eXtensible Token Markup Language. C'est la contribution la moins spectaculaire du rapport, et l'une des plus réutilisables.

Les trois objectifs de conception

Objectif Énoncé
Extensibilité De nouvelles capacités doivent s'introduire par des formats de messages rétrocompatibles, pas par des révisions du gabarit — un seul gabarit doit servir toute la génération du modèle
Faible taxe d'alignement Le format doit s'apprendre avec un minimum de données supervisées, pour qu'un modèle pré-entraîné légèrement affiné puisse passer directement au RL
Convivialité de décodage La structure doit admettre des encodeurs simples, des analyseurs en flux et des contraintes grammaticales

La syntaxe

Trois jetons réservés remplacent les chevrons XML :

Jeton Rôle
[open] Ouverture d'élément
[sep] Séparateur attributs / contenu
[close] Fermeture d'élément
[end_of_msg] Marqueur d'arrêt de génération

Un élément s'écrit :

[open]tag attr="valeur"[sep] … contenu … [close]tag[sep]

Pourquoi des jetons plutôt que des caractères

C'est isomorphe à du XML, mais chaque frontière structurelle est un jeton spécial explicite. Deux gains concrets :

  1. Suppression de l'ambiguïté de tokenisation aux frontières. Avec des balises textuelles, la façon dont <tool_call> est découpé en jetons dépend du contexte qui le précède. Avec un jeton réservé, jamais.
  2. Décodage sous contrainte simplifié. Un analyseur grammatical peut opérer directement au niveau des jetons, sans reconstruire le texte.

L'anatomie du contexte

┌──────────────────────────────────────────────────────────┐
│ OPTIONS GLOBALES                                          │
│   • déclaration d'outils (type="tool-declare")            │
│   • effort de raisonnement (type="thinking-effort")       │
├──────────────────────────────────────────────────────────┤
│ MESSAGES D'ENTRÉE                                         │
│   system / user / assistant / tool                        │
│   ┌ (option intercalée : chargement dynamique d'outils) ┐ │
├──────────────────────────────────────────────────────────┤
│ OPTIONS PONCTUELLES                                       │
│   • tool_choice                                           │
│   • response_format                                       │
└──────────────────────────────────────────────────────────┘

Le placement est dicté par le cache KV

Type Position Raison
Globales Avant tout Changent rarement ; les modifier invalide le cache de toute façon
Ponctuelles Après tout Un changement par requête laisse l'historique en cache intact
Intercalées Au milieu Permet d'ajouter des outils sans reconstruire le contexte précédent

Le chargement dynamique d'outils en découle : les outils récupérés en cours de conversation sont annoncés par un message tool-declare supplémentaire, et l'outillage disponible s'élargit sans invalidation.

Les canaux

Le corps d'un message assistant est organisé en canaux, concept inspiré du format Harmony d'OpenAI :

Canal Contenu
think La trace de raisonnement
response La réponse visible par l'utilisateur
tools Les appels d'outils

Un seul gabarit, deux modes

Les deux modes de génération sont sélectionnés uniquement par le préfixe de génération :

  • [open]think[sep] → mode réflexion ;
  • [open]response[sep] → mode instruction.

Pas de gabarits séparés. C'est une application directe du principe d'extensibilité.

La réflexion préservée

Kimi K3 ne supporte que le preserved thinking : en mode réflexion, le canal think est toujours conservé dans l'historique, même vide, pour que le modèle observe une structure de message cohérente d'un tour à l'autre. En mode instruction, les messages historiques ne contiennent que response et tools.

Conséquence pratique impérative

L'API exige que le message assistant complet soit renvoyé tel quel dans messages, y compris reasoning_content et tool_calls. Ne renvoyer que content dégrade le comportement — c'est d'ailleurs une limitation explicitement reconnue par Moonshot.

L'appel d'outil

Dans le canal tools, chaque appel porte deux attributs :

  • tool : le nom de l'outil ;
  • index : numérote les appels parallèles au sein d'un même message.

Chaque message de résultat répète la paire tool/index et suit l'ordre de son appel : l'association résultat ↔ appel est donc non ambiguë, même avec des appels parallèles.

Les arguments typés

Les arguments de type chaîne apparaissent en texte brut ; seules les valeurs d'autres types JSON sont sérialisées de façon compacte.

Conséquence, énoncée par le rapport : free-form text such as code is therefore a first-class citizen rather than an escaped JSON string.

Concrètement, un bloc de code n'a plus besoin d'échapper ses guillemets, ses retours à la ligne et ses antislashs. C'est un gain de robustesse et de jetons.

Un bloc de repli JSON pur couvre les entrées dont les arguments ne se décomposent pas en blocs typés. Il n'apparaît que dans les jetons d'entrée, jamais en sortie du modèle, et sa perte est masquée pendant l'entraînement.

L'effort de raisonnement comme message

L'effort n'est pas un paramètre de décodage ni un budget de jetons exposé. C'est un message d'option globale de type thinking-effort, inséré après la déclaration d'outils et avant les messages d'entrée, qui énonce le niveau demandé en langage naturel et agit comme une contrainte de génération.

Le schéma réserve quatre niveaux — low, medium, high, max — dont Kimi K3 supporte un sous-ensemble (low, high, max d'après la carte de modèle).

Le principe généralisé

C'est l'implémentation commune de toutes les options : tool_choice, response_format et thinking-effort sont chacune traduites en une courte instruction en langage naturel placée dans le contexte, plutôt qu'en syntaxe dédiée.

Justification donnée : parce que le modèle pré-entraîné suit déjà bien ce genre d'instruction, de nouvelles options peuvent être introduites avec peu ou pas d'entraînement supplémentaire — l'incarnation directe du principe de faible taxe d'alignement.

Vérification de compréhension

Pourquoi masquer la perte sur le bloc JSON de repli ?

Parce qu'il ne doit jamais apparaître en sortie du modèle. Le laisser dans la perte apprendrait au modèle à le produire, alors qu'il n'existe que pour ingérer des entrées mal formées venues de l'extérieur.

Quel est l'intérêt concret de « un seul gabarit pour toute la génération » ?

Un changement de gabarit invalide toutes les données de SFT existantes, tous les caches KV en production, et tous les clients déjà déployés. En concevant l'extensibilité dans le format, Moonshot peut ajouter des capacités à K3.1, K3.2… sans rien casser.


Chapitre précédent : Extension du contexte à 1 M · Chapitre suivant : Apprentissage par renforcement