L'API Kimi K3 parle le dialecte Anthropic. Brancher notre boucle agentique dessus nous a pris vingt minutes ; la faire tourner proprement nous a pris deux jours.
On a passé une feature réelle dans les deux : ajout d'un export CSV filtré dans un dashboard Next.js + Supabase, six fichiers touchés, tests inclus. Même prompt de départ, même arborescence, même définition de « terminé » (tests au vert, lint propre). Kimi K3 a fini, mais il a mis 1,5× plus de temps et coûté 2,84 $ là où Claude était déjà payé par le forfait. Voilà le détail, les mesures, et les quatre endroits où le montage casse.
Le montage : vingt minutes
Moonshot expose un endpoint compatible avec le format messages d'Anthropic, donc si ta boucle est déjà écrite contre le SDK Anthropic, tu ne changes que deux lignes :
export KIMI_API_KEY="sk-..."
export KIMI_BASE_URL="https://api.moonshot.ai/anthropic"
from anthropic import Anthropic
client = Anthropic(
api_key=os.environ["KIMI_API_KEY"],
base_url=os.environ["KIMI_BASE_URL"],
)
resp = client.messages.create(
model="kimi-k3",
max_tokens=8192,
tools=TOOLS, # mêmes schémas que chez Anthropic
messages=history,
)
Notre banc, pour que ce soit reproductible :
- boucle maison, 12 outils (
read,write,edit,bash,grep,test…), pas de framework - streaming activé, un seul thread, aucune parallélisation d'outils
- même machine, même connexion, mesures prises entre 14 h et 17 h le 21/07
- contexte de départ : 34 fichiers épinglés, ~28 000 tokens
- au 22/07, les poids ne sont pas publics : tout passe par l'API hébergée
Le premier run est parti du premier coup, et c'est précisément ce qui rend la suite piégeuse : ça marche, donc on ne regarde pas la facture tout de suite.
Piège 1 — le cache de prompt ne se déclenche pas comme chez Anthropic
Notre premier run a coûté 7,10 $. Le second, à travail identique, 2,84 $. Entre les deux, on n'a touché à aucun outil ni à aucun prompt : on a figé l'ordre du préfixe.
Chez Anthropic, tu marques explicitement les blocs à mettre en cache avec cache_control. Kimi ne fonctionne pas comme ça : le cache est un cache de préfixe automatique, facturé 0,30 $/M au lieu de 3 $/M en entrée, et il ne se déclenche que si les premiers octets de la requête sont strictement identiques d'un tour à l'autre. Notre boucle sérialisait les outils depuis un dict, donc l'ordre bougeait ; et on injectait un horodatage dans le system prompt. Deux détails, une facture multipliée par dix sur l'entrée.
# le préfixe doit être identique octet pour octet, à chaque tour
PREFIX = [SYSTEM_BLOCK_STATIC, *sorted(TOOLS, key=lambda t: t["name"])]
# l'horodatage, les compteurs, l'état : à la FIN, jamais au début
Le champ cache_control est accepté sans erreur, mais il ne fait rien. C'est le pire cas de figure : pas d'exception, juste une facture.
Piège 2 — les arguments d'outils ne reviennent pas toujours propres
Sur 46 tours, on a eu 3 blocs tool_use dont les arguments arrivaient en chaîne de caractères au lieu d'objet, dont un enveloppé dans des barrières de code markdown. Rien de dramatique quand tu le sais, une exception non rattrapée quand tu ne le sais pas. Le schéma JSON est suivi dans le fond — les clés étaient bonnes — mais l'enveloppe ne l'est pas toujours.
def parse_tool_input(block):
raw = block.input
if isinstance(raw, str):
raw = json.loads(re.sub(r"^```
(?:json)?|
```$", "", raw.strip()))
return raw
Deux autres différences à traiter avant de lancer quoi que ce soit sur un dépôt réel :
-
appels parallèles : K3 renvoie volontiers plusieurs blocs
tool_usedans une même réponse. Si ta boucle n'en exécute qu'un et jette le reste, tu perds des tours sans t'en apercevoir. -
stop_reason: la valeurmax_tokenstombe plus souvent qu'avec Claude sur les gros patchs. Prévois la reprise, sinon tu écris des fichiers tronqués.
Piège 3 — la lenteur compose
Le débit annoncé, 62 tokens/s, est en dessous de la médiane du marché (71 selon Artificial Analysis). Sur une réponse isolée, ça ne se sent pas. Dans une boucle qui enchaîne quarante tours, en revanche, ça se paie deux fois : le modèle est plus lent et il a eu besoin de plus de tours pour converger.
| Mesure (même feature) | Kimi K3 (API) | Claude (Claude Code) |
|---|---|---|
| Tours d'agent | 46 | 38 |
| Tokens de sortie cumulés | 31 200 | 24 900 |
| Débit médian | 62 t/s | 78 t/s |
| Time-to-first-token médian | 1,9 s | 1,1 s |
| Temps au mur | 11 min 50 | 7 min 50 |
| Tests au vert au premier passage | non (2 reprises) | oui |
| Coût direct de la tâche | 2,84 $ | inclus au forfait |
-20 % de débit et +21 % de tours, ça ne fait pas -41 % : ça fait un facteur 1,5 sur le temps réel. C'est la seule métrique que je regarde encore, parce que c'est celle que tu subis quand tu attends devant ton terminal.
Piège 4 — la fenêtre d'un million est un piège de facturation
Un contexte de 1 M tokens, dans une boucle agentique, c'est une invitation à ne jamais compacter. Sauf que ta boucle renvoie tout l'historique à chaque tour : le coût d'entrée croît de façon quadratique avec le nombre de tours, et c'est l'entrée qui domine la facture, pas la sortie. Sur notre run, les 31 200 tokens générés ont coûté 0,47 $ — le reste, 2,37 $, c'est du contexte renvoyé en boucle.
Avec un forfait mensuel, cette dérive est invisible et tu peux te permettre d'être négligent ; au token, elle est linéaire sur ta carte bleue. On a fini par imposer une compaction dure à 120 000 tokens, ce qui a coupé la facture d'un tiers sans dégrader le résultat. Le raisonnement économique complet — forfait contre compteur, et pourquoi tous les comparatifs se trompent de grille — est dans notre article de fond.
Ce qu'on garde
K3 est premier au Frontend Code Arena, et sur du composant one-shot bien cadré, ça se voit : le HTML/CSS sort propre, souvent mieux structuré. On l'a gardé pour ça, appelé ponctuellement depuis nos scripts, jamais comme moteur de la boucle.
Pour un chantier multi-fichiers avec tests, on reste sur Claude Code — pas par attachement, mais parce que le harness fait le gros du travail et qu'aucune économie au token ne rattrape 4 minutes de plus par feature, plusieurs fois par jour. Si tu veux le détail de ce qu'un harness ajoute réellement à un modèle, on l'a documenté dans notre guide Claude Code.
Réserve honnête : les poids sont annoncés pour le 27/07, et tant qu'ils ne sont pas tombés, tout ce qui précède mesure une API hébergée, pas un modèle. On refera le banc après la publication, et on postera les chiffres bruts — y compris s'ils nous contredisent.
Tu veux monter ce genre de boucle proprement plutôt que de la déboguer deux jours ? Notre formation Claude Code part exactement de là.
Top comments (0)