Accéder au contenu principal

Kimi K2 Thinking : guide open source des LLM, benchmarks et outils

Tutoriel pratique pour exécuter Kimi K2 Thinking, créer des workflows de tool calling, afficher le raisonnement transparent et le comparer à GPT-5 et Claude 4.5.
· 15 min lire

Explorez l'IA

Un modèle open source dépasse GPT-5 et Claude Sonnet 4.5 sur les principaux benchmarks pour une fraction du coût : Kimi K2 Thinking, la variante de raisonnement de Moonshot AI, publiée en novembre 2025.

Kimi K2 Thinking peut exécuter de façon autonome 200–300 appels d’outils séquentiels, ce qui le rend idéal pour des workflows agentiques complexes. Il expose également son processus de raisonnement via un champ dédié dans l’API, pour que vous puissiez voir exactement comment il aborde les problèmes.

Ce tutoriel vous montre comment utiliser l’API Kimi K2 Thinking pour des tâches de raisonnement. Vous allez implémenter des workflows d’appels d’outils, créer une app de chat comparative pour tester K2 face à GPT-5 et Claude, et apprendre à quel moment les atouts de K2 en font le meilleur choix. Si vous souhaitez aller plus loin dans la création d’applications avec des LLM, je vous recommande le cours Developing LLM Applications with LangChain. Découvrez aussi nos autres projets sur GPT-5.1-Codex et Qwen3-Max-Thinking. Je recommande également notre guide sur le nouveau Kimi K2.5 avec Agent Swarm.

Voici un aperçu de l’application :

Avant de passer à la pratique, voyons ce qui distingue K2 Thinking des modèles de langage classiques.

Qu’est-ce que Kimi K2 Thinking ?

La plupart des modèles génèrent immédiatement des réponses. K2 Thinking fonctionne autrement. Il est conçu pour les problèmes en plusieurs étapes, où le modèle doit planifier, raisonner et agir de façon autonome.

Architecture et conception

Le modèle s’appuie sur une architecture Mixture-of-Experts (MoE) avec 1 billion de paramètres au total. Seuls 32 milliards s’activent pour une entrée donnée. K2 bénéficie ainsi de la puissance d’un très grand modèle sans les coûts d’inférence élevés. Sa fenêtre de contexte de 256 000 tokens permet d’ingérer des bases de code entieres, de longs documents ou des historiques de conversation étendus sans fractionnement.

Moonshot AI a publié deux versions : K2 Instruct gère les tâches directes comme la génération de texte, la classification et le Q&R simple, là où la vitesse prime. K2 Thinking est destiné aux tâches de raisonnement complexes.

Deux capacités phares

La première grande force de K2 Thinking est le raisonnement transparent. Vous voyez comment il décompose les problèmes, évalue les options et parvient à ses conclusions.

La seconde est l’orchestration d’outils. K2 gère des séquences d’appels d’outils très longues, au-delà de la plupart des modèles. Il choisit quels outils utiliser, quand et comment combiner les résultats, sans intervention à chaque étape.

Fonctionnalités supplémentaires

K2 inclut des options pour différents contextes de déploiement. En production, quand la précision est critique, le Heavy Mode exécute huit chemins de raisonnement en parallèle et sélectionne la meilleure réponse, avec un coût de calcul plus élevé.

Pour les applications sensibles à la latence, la quantification INT4 double la vitesse d’inférence avec une perte de précision minime, pratique pour des environnements à haut débit.

Kimi K2 Thinking vs GPT-5 vs Claude Sonnet 4.5 vs DeepSeek

Voici comment K2 se compare à GPT-5, Claude Sonnet 4.5 et DeepSeek V3.2.

Métrique

Kimi K2 Thinking

GPT-5 (High)

Claude Sonnet 4.5

DeepSeek-V3.2

HLE (avec outils)

44,9

41,7

32

20,3

HLE Heavy Mode

51

42

—

—

AIME25 (avec python)

99,1 %

99,6 %

100 %

58,1 %

GPQA

84,5

85,7

83,4

79,9

BrowseComp

60,2

54,9

24,1

40,1

Frames

87

86

85

80,2

SWE-bench Verified

71,3 %

74,9 %

77,2 %

67,8 %

LiveCodeBench

83,1 %

87,0 %

64,0 %

74,1 %

Fenêtre de contexte

256 k tokens

400 k tokens

200 k tokens

128 k tokens

Tarification entrée

$0,60 / 1 M

$1,25 / 1 M

$3,00 / 1 M

$0,55 / 1 M

Tarification sortie

$2,50 / 1 M

$10,00 / 1 M

$15,00 / 1 M

$2,19 / 1 M

Appels d’outils max.

200–300

Des dizaines +

Des dizaines +

Non spécifié

Définitions rapides des benchmarks : HLE évalue des connaissances de niveau master, AIME25 utilise des problèmes de mathématiques de compétition, BrowseComp et Frames testent la navigation web et la synthèse, SWE-bench Verified mesure la correction de bugs dans du code open source, LiveCodeBench teste la génération de code, et GPQA couvre des questions scientifiques de niveau master.

La formation de K2 aux outils se voit surtout sur les benchmarks agentiques. Heavy Mode bat GPT-5 de 9 points sur HLE car il exécute huit chemins de raisonnement en parallèle. L’entraînement de Claude sur le code lui donne l’avantage sur SWE-bench Verified, ce qui en fait le meilleur choix pour les projets d’ingénierie logicielle.

Sur les tâches de raisonnement pur, les trois modèles sont globalement équivalents. Les différences apparaissent quand les outils entrent en jeu. La capacité de K2 à gérer 200–300 appels d’outils lui permet de mener des workflows de recherche autonomes, des pipelines de débogage et des analyses de données multi-étapes sans intervention à chaque phase.

Quand choisir chaque modèle

  • Choisissez K2 Thinking pour des workflows agentiques nécessitant une forte orchestration d’outils, de la recherche web et des tâches de synthèse d’information, ou lorsque vous avez besoin de chaînes de raisonnement transparentes pour le débogage ou la conformité.
  • Choisissez GPT-5 pour la plus grande fenêtre de contexte (400k tokens) ou quand vous souhaitez des performances équilibrées sur différentes tâches avec un écosystème mûr.
  • Choisissez Claude Sonnet 4.5 pour les projets d’ingénierie logicielle où le débogage et les corrections de code sont prioritaires.
  • Choisissez DeepSeek si votre priorité est le budget avec des exigences open source sous licence MIT.

Configurer l’accès à l’API Kimi K2 Thinking

Vous avez deux options pour accéder à K2 Thinking : directement via la plateforme de Moonshot AI platform.moonshot.ai, ou via OpenRouter, une passerelle API unifiée. Nous utiliserons OpenRouter car il donne accès à K2, GPT-5, Claude et des dizaines d’autres modèles avec une seule clé API. Cet accès unifié devient essentiel plus loin quand vous construisez l’app comparative. OpenRouter gère aussi automatiquement le rate limiting et le failover, évitant d’avoir à maintenir plusieurs comptes fournisseurs.

Commencez par vous rendre sur openrouter.ai et créez un compte. Vous pouvez vous inscrire avec Google ou GitHub. Une fois connecté, allez dans la section « Keys » du tableau de bord et générez une nouvelle clé API.

OpenRouter offre $5 de crédits gratuits à l’inscription, suffisants pour tester K2 Thinking sur plusieurs requêtes. Si vous avez besoin de plus, ajoutez un moyen de paiement dans la section « Credits ».

Copiez votre clé API et conservez-la en lieu sûr. Vous en aurez besoin dans un instant. Ne la commitez pas dans le contrôle de version et ne la partagez pas publiquement : toute personne détenant votre clé peut effectuer des appels API sur votre compte.

Passons à la configuration de votre environnement Python. Il vous faut le SDK Python OpenAI, compatible avec l’API OpenRouter, et python-dotenv pour gérer votre clé en sécurité. Installez les deux packages :

!pip install openai python-dotenv

Créez un fichier .env dans le répertoire du projet et ajoutez votre clé API OpenRouter :

OPENROUTER_API_KEY=your_key_here

Si vous utilisez git, ajoutez .env à votre fichier .gitignore pour éviter de commiter vos identifiants par erreur.

Voici un test rapide pour vérifier que tout fonctionne :

import os
from openai import OpenAI
from dotenv import load_dotenv

# Load API key from .env file
load_dotenv()

# Configure client for OpenRouter
client = OpenAI(
   base_url="https://openrouter.ai/api/v1",
   api_key=os.getenv("OPENROUTER_API_KEY")
)

# Test call to K2 Thinking
response = client.chat.completions.create(
   model="moonshotai/kimi-k2-thinking",
   messages=[
       {"role": "user", "content": "What is 15 * 24?"}
   ]
)

print(response.choices[0].message.content)

Sortie :

15 * 24 = **360**

Si vous voyez la réponse, tout est prêt.

Comprendre le mode Thinking de Kimi K2

Nous avons évoqué plus haut le raisonnement transparent de K2. Voyons désormais comment y accéder et l’exploiter dans votre code. K2 Thinking expose automatiquement son processus de raisonnement via un champ dédié dans l’API.

Contrairement à d’autres modèles où il faut activer manuellement le mode de réflexion, K2 inclut par défaut le contenu de raisonnement dans chaque réponse.

Comment accéder au contenu de raisonnement

Quand vous appelez l’API de K2 Thinking, la réponse contient deux champs. Le champ content contient la réponse finale, et le champ reasoning expose le raisonnement étape par étape. Voici un exemple concret avec un calcul de remise nécessitant plusieurs étapes :

import os
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()

client = OpenAI(
   base_url="https://openrouter.ai/api/v1",
   api_key=os.getenv("OPENROUTER_API_KEY")
)

response = client.chat.completions.create(
   model="moonshotai/kimi-k2-thinking",
   messages=[
       {"role": "user", "content": "A laptop costs $850. There's a 20% discount today, then 8% sales tax applies to the discounted price. What's the final amount I pay?"}
   ],
   temperature=1.0
)

print("Final answer:")
print(response.choices[0].message.content)
print("\nReasoning process:")
print(response.choices[0].message.reasoning)

Sortie :

Final answer:
The final amount you pay is **$734.40**.

Here's the breakdown:

1. **Discount:** 20% of $850 = $170
2. **Discounted price:** $850 - $170 = $680
3. **Sales tax:** 8% of $680 = $54.40
4. **Final amount:** $680 + $54.40 = **$734.40**

Processus de raisonnement (tronqué pour la lisibilité) :

The user wants to know the final amount they will pay for a laptop with a discount and then sales tax applied.

Step 1: Calculate the discount amount.
Discount amount = $850 * 0.20 = $170

Step 2: Calculate the discounted price.
Discounted price = $850 - $170 = $680

Step 3: Calculate the sales tax amount.
Sales tax amount = $680 * 0.08 = $54.40

Step 4: Calculate the final amount to pay.
Final amount = $680 + $54.40 = $734.40

Let me double-check the calculations...
[verification steps omitted]

The final amount is $734.40

Le champ content fournit la réponse claire visible par vos utilisateurs. Le champ reasoning montre comment K2 a traité le problème, ce qui vous aide à juger si le modèle a vraiment bien raisonné ou s’il a eu de la chance.

K2 génère les tokens de raisonnement pendant l’inférence, pas après. Le modèle réfléchit donc au problème avant de s’engager sur une réponse, comme vous pourriez le faire sur une feuille de brouillon avant d’écrire le résultat final. Le raisonnement se produit en temps réel, au fil de la génération.

Paramètres recommandés pour le mode Thinking

Réglez temperature=1.0 avec K2 Thinking. Des températures plus basses brident l’exploration du raisonnement, ce qui va à l’encontre de l’objectif du mode Thinking. Prévoyez aussi max_tokens=4096 ou plus, car les chaînes de raisonnement consomment des tokens avant même le début de la réponse finale.

response = client.chat.completions.create(
   model="moonshotai/kimi-k2-thinking",
   messages=[{"role": "user", "content": "Your question here"}],
   temperature=1.0,
   max_tokens=4096
)

Maintenant que vous maîtrisez le mode Thinking, passons à l’autre capacité clé de K2 : les appels d’outils. Beaucoup de modèles gèrent des usages de base, mais l’approche de K2 se distingue par l’échelle et l’autonomie.

Capacités d’appels d’outils de Kimi K2

Les appels d’outils permettent à K2 d’exécuter des fonctions pendant son raisonnement. Vous définissez des outils sous forme de schémas JSON décrivant ce que fait chaque fonction et les paramètres requis. Quand K2 a besoin de données ou de calculs externes, il appelle le bon outil et attend les résultats.

Cela crée une boucle aller-retour : K2 lit votre prompt et raisonne. S’il a besoin d’un outil, il renvoie finish_reason: "tool_calls". Vous exécutez la fonction, renvoyez les résultats avec role: "tool", et K2 poursuit. Cela se répète jusqu’à ce que K2 renvoie finish_reason: "stop" avec la réponse finale.

Le schéma suit le format d’OpenAI avec un nom, une description et des paramètres. K2 les lit pour comprendre quand utiliser chaque outil. Des descriptions claires sont essentielles car elles guident les décisions du modèle.

Créer l’outil d’analyse CSV

Créons un outil pratique qui analyse des fichiers CSV, une tâche fréquente en data science. Il lit un CSV, extrait les informations de colonnes et renvoie des statistiques résumées. Il montre comment K2 peut accéder à des données externes pendant le raisonnement, essentiel pour des applications basées sur les données.

Voici l’implémentation complète :

import csv
import os
import json

# Define the tool schema
tools = [
   {
       "type": "function",
       "function": {
           "name": "analyze_csv",
           "description": "Read and analyze the first few rows of a CSV file. Returns columns, sample rows, total row count, and file size.",
           "parameters": {
               "type": "object",
               "properties": {
                   "filepath": {
                       "type": "string",
                       "description": "Path to the CSV file"
                   },
                   "num_rows": {
                       "type": "integer",
                       "description": "Number of rows to read",
                       "default": 10
                   }
               },
               "required": ["filepath"]
           }
       }
   }
]

Le schéma définit un outil de fonction selon le format OpenAI. Le champ description explique à K2 ce que fait l’outil et l’aide à décider quand l’utiliser.

L’objet parameters spécifie les entrées : filepath est requis, tandis que num_rows est optionnel avec une valeur par défaut de 10. Des descriptions précises aident K2 à comprendre quand cet outil correspond au besoin de l’utilisateur.

L’implémentation gère le traitement effectif du fichier :

# Implement the function
def analyze_csv(filepath: str, num_rows: int = 10) -> dict:
   if not os.path.exists(filepath):
       return {"error": f"File not found: {filepath}"}

   try:
       with open(filepath, 'r') as f:
           reader = csv.DictReader(f)
           columns = reader.fieldnames
           sample_rows = [dict(row) for i, row in enumerate(reader) if i < num_rows]
           f.seek(0)
           total_rows = sum(1 for _ in f) - 1

       return {
           "columns": list(columns),
           "sample_rows": sample_rows,
           "total_rows": total_rows,
           "file_size_kb": round(os.path.getsize(filepath) / 1024, 2)
       }
   except Exception as e:
       return {"error": str(e)}

La fonction valide le chemin du fichier, puis utilise csv.DictReader pour parser le CSV en dictionnaires où les clés sont les noms de colonnes. Elle lit les num_rows premières entrées, réinitialise le pointeur de fichier avec seek(0), puis compte les lignes totales.

Le dictionnaire retourné inclut les noms de colonnes, un échantillon de données, le nombre de lignes et la taille du fichier en kilo-octets. La gestion d’erreur assure un retour utile en cas d’échec.

Implémenter la boucle d’exécution des outils

Une fois l’outil défini et implémenté, il faut une boucle qui gère la conversation entre K2 et vos fonctions. Les appels d’outils ne sont pas monolithiques. K2 peut nécessiter plusieurs itérations : appeler un outil, analyser le résultat, décider d’un autre appel, et recommencer. Il faut donc une boucle qui gère cet aller-retour jusqu’à la réponse finale de K2.

Voici l’implémentation complète avec un exemple réel :

from openai import OpenAI

client = OpenAI(
   base_url="https://openrouter.ai/api/v1",
   api_key=os.getenv("OPENROUTER_API_KEY")
)

messages = [
   {"role": "user", "content": "Analyze sample_employees.csv and tell me the average salary for Engineering department employees."}
]

On initialise le client OpenAI configuré pour l’API d’OpenRouter et on crée la liste de messages initiale avec la requête sur l’analyse des salaires.

while True:
   response = client.chat.completions.create(
       model="moonshotai/kimi-k2-thinking",
       messages=messages,
       tools=tools,
       temperature=1.0
   )

   message = response.choices[0].message
   finish_reason = response.choices[0].finish_reason

   messages.append({
       "role": "assistant",
       "content": message.content,
       "tool_calls": message.tool_calls
   })

La boucle principale envoie l’historique de conversation à K2 avec les outils disponibles. Après extraction de la réponse et du motif de fin, on l’ajoute à l’historique pour préserver le contexte.

  if finish_reason == "tool_calls":
       for tool_call in message.tool_calls:
           function_name = tool_call.function.name
           arguments = json.loads(tool_call.function.arguments)

           if function_name == "analyze_csv":
               result = analyze_csv(**arguments)

           messages.append({
               "role": "tool",
               "content": json.dumps(result),
               "tool_call_id": tool_call.id
           })

   elif finish_reason == "stop":
       print(message.content)
       break

Quand K2 demande des appels d’outils, nous exécutons chaque fonction avec les arguments fournis et renvoyons les résultats dans la conversation avec les tool_call_id correspondants. Quand K2 termine et renvoie « stop », on affiche la réponse finale et on sort de la boucle.

Pour cet exemple, créez un fichier sample_employees.csv avec des données d’employés, incluant nom, département et salaire. Utilisez environ 12 profils répartis entre Engineering, Marketing, Sales et HR pour tester. Au lancement, K2 appelle généralement analyze_csv() avec num_rows à 12 ou plus pour couvrir l’ensemble, puis identifie les employés d’Engineering et calcule leur salaire moyen.

Sortie :

Based on the CSV data, I found 5 Engineering employees in the sample:
- Alice Johnson: $95,000
- Carol White: $110,000
- Eve Davis: $88,000
- Iris Martinez: $102,000
- Kate Thomas: $92,000

The average salary for Engineering department employees is $97,400.

Le tool_call_id de chaque réponse relie les résultats à l’appel initial. K2 peut demander plusieurs outils à la fois : chaque appel doit donc être identifié pour un appariement correct. Conserver tout l’historique fournit à K2 le contexte nécessaire à un raisonnement cohérent à travers les appels.

Comprendre l’orchestration autonome de K2

Une fois à l’aise avec les appels d’outils, la vraie force de K2 saute aux yeux : l’orchestration étendue. K2 a été entraîné dès le départ pour l’orchestration d’outils, pas en ajout tardif. Cela change sa manière de gérer les tâches en plusieurs étapes. La plupart des modèles gèrent 20–50 appels séquentiels avant de décrocher. K2 en gère 200–300 en maintenant un raisonnement cohérent.

Cette capacité compte pour les workflows autonomes où le modèle décide, collecte l’information, valide les résultats et itère jusqu’à résolution. Pensez à des tâches de recherche où K2 interroge des bases, recoupe, identifie des lacunes, affine les requêtes et synthétise. Ou à des pipelines de données à valider à chaque étape. Ou à des workflows de débogage testant plusieurs hypothèses.

Si votre cas d’usage est « exécuter cette action unique », la plupart des modèles suffisent. S’il est « travaillez jusqu’à résoudre », la capacité étendue de K2 devient déterminante.

Construire une app de chat comparative multi-modèles

Vous avez vu comment K2 Thinking gère des tâches individuelles avec appels d’outils et raisonnement transparent. Mettons-le maintenant à l’épreuve face à ses concurrents. Vous allez construire une app Streamlit qui interroge Kimi K2 Thinking, GPT-5 et Claude Sonnet 4.5 avec le même prompt en parallèle. L’interface affiche les trois réponses côte à côté pour comparer leurs approches.

Vous trouverez le script complet de l’application dans ce GitHub Gist. Si vous voulez uniquement les résultats des tests, vous pouvez passer cette section. Les étapes suivantes détaillent un script de plus de 200 lignes : gardez cette lecture pour plus tard si besoin. Allons-y.

Étape 1 : configuration du projet et dépendances

Cette app comparative requiert l’accès API aux trois modèles. Il vous faut votre compte OpenRouter (déjà configuré avec $5 de crédits gratuits) et, en option, des clés API OpenAI et Anthropic. Les $5 d’OpenRouter devraient suffire pour tester plusieurs requêtes sur les trois modèles. Avec OpenRouter seul, vous pouvez tout de même comparer K2 à d’autres modèles disponibles via OpenRouter.

Installez Streamlit pour l’interface web et le SDK d’Anthropic pour accéder à Claude :

pip install streamlit anthropic

Créez un fichier nommé model_comparison_chat.py. Toute l’application tient dans ce fichier. Commencez par les imports :

import os
import time
from typing import Dict, List
from concurrent.futures import ThreadPoolExecutor, as_completed
from dotenv import load_dotenv
import streamlit as st
from openai import OpenAI
from anthropic import Anthropic

load_dotenv()

Étape 2 : configurer les connexions API

Vous avez déjà OPENROUTER_API_KEY dans votre fichier .env. Ajoutez les clés pour GPT-5 et Claude :

OPENROUTER_API_KEY=your_openrouter_key  # Already set up
OPENAI_API_KEY=your_openai_key           # Add this
ANTHROPIC_API_KEY=your_anthropic_key     # Add this

Récupérez votre clé OpenAI sur platform.openai.com et votre clé Anthropic sur console.anthropic.com. Pour plus de détails sur GPT-5, consultez le guide GPT-5. Pour Claude Sonnet 4.5, voyez la présentation de Claude Sonnet 4.5.

Initialisez les trois clients :

KIMI_CLIENT = OpenAI(
   api_key=os.getenv("OPENROUTER_API_KEY"),
   base_url="https://openrouter.ai/api/v1"
)
GPT_CLIENT = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
CLAUDE_CLIENT = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

Étape 3 : créer des fonctions utilitaires par modèle

Créez une fonction unifiée qui route vers le bon modèle selon le nom. Votre code reste propre et vous pourrez ajouter facilement d’autres modèles.

Commencez par l’appel à Kimi K2 :

def call_model(model_name: str, messages: List[Dict], **kwargs) -> Dict:
   """Call any model with unified interface."""
   try:
       start_time = time.time()

       if model_name == "Kimi K2 Thinking":
           enable_thinking = kwargs.get("enable_thinking", True)

           completion = KIMI_CLIENT.chat.completions.create(
               model="moonshotai/kimi-k2-thinking",
               messages=messages,
               temperature=1.0,
               extra_body={"include_reasoning": True}
           )

           message = completion.choices[0].message
           content = message.content

           # Extract reasoning from the dedicated field
           reasoning_content = None
           if enable_thinking and hasattr(message, 'reasoning') and message.reasoning:
               reasoning_content = message.reasoning

           return {
               "content": content,
               "reasoning_content": reasoning_content,
               "response_time": time.time() - start_time,
               "tokens_used": {
                   "input": completion.usage.prompt_tokens,
                   "output": completion.usage.completion_tokens,
                   "total": completion.usage.total_tokens
               },
               "error": None
           }

GPT-5 adopte une autre approche avec une endpoint responses et un « reasoning effort » configurable :

      elif model_name == "GPT-5":
           reasoning_effort = kwargs.get("reasoning_effort", "medium")
           input_messages = [
               {"role": m["role"], "content": m["content"]}
               for m in messages
           ]

           response = GPT_CLIENT.responses.create(
               model="gpt-5",
               input=input_messages,
               reasoning={
                   "effort": reasoning_effort,
                   "summary": "auto"
               }
           )

           # Parse response structure
           reasoning_text = None
           content_text = ""

           for item in response.output:
               if item.type == "reasoning" and hasattr(item, "summary"):
                   summaries = [s.text for s in item.summary if hasattr(s, "text")]
                   reasoning_text = "\n\n".join(summaries) if summaries else None
               elif item.type == "message" and hasattr(item, "content"):
                   content_text += "".join(c.text for c in item.content if hasattr(c, "text"))

           return {
               "content": content_text,
               "reasoning_content": reasoning_text,
               "response_time": time.time() - start_time,
               "tokens_used": {
                   "input": getattr(response.usage, "input_tokens", 0),
                   "output": getattr(response.usage, "output_tokens", 0),
                   "total": getattr(response.usage, "total_tokens", 0)
               },
               "error": None
           }

GPT-5 propose quatre niveaux d’effort de raisonnement : minimal, low, medium et high. La réponse sépare les résumés de raisonnement et le contenu, que vous parsez séparément avant de renvoyer la même structure standardisée que pour Kimi K2.

Claude Sonnet 4.5 propose un mode de réflexion étendu avec un budget de tokens :

    else:  # Claude Sonnet 4.5
           enable_thinking = kwargs.get("enable_thinking", True)
           params = {
               "model": "claude-sonnet-4-5",
               "max_tokens": 10000,
               "messages": messages
           }
           if enable_thinking:
               params["thinking"] = {
                   "type": "enabled",
                   "budget_tokens": 5000
               }

           message = CLAUDE_CLIENT.messages.create(**params)

           # Extract content and thinking blocks
           content_text = ""
           thinking_text = None

           for block in message.content:
               if block.type == "thinking":
                   thinking_text = block.thinking
               elif block.type == "text":
                   content_text += block.text

           return {
               "content": content_text,
               "reasoning_content": thinking_text,
               "response_time": time.time() - start_time,
               "tokens_used": {
                   "input": message.usage.input_tokens,
                   "output": message.usage.output_tokens,
                   "total": message.usage.input_tokens + message.usage.output_tokens
               },
               "error": None
           }

   except Exception as e:
       return {
           "content": None,
           "reasoning_content": None,
           "response_time": 0,
           "tokens_used": {"input": 0, "output": 0, "total": 0},
           "error": f"{model_name} Error: {str(e)}"
       }

Claude alloue un budget de tokens pour le raisonnement interne avant la réponse finale. La réponse contient plusieurs blocs que vous itérez, en séparant les blocs de pensée des blocs de texte. La gestion d’erreur renvoie toujours une structure standardisée avec un message, pour éviter qu’une API en échec ne casse l’interface.

Étape 4 : construire l’interface Streamlit

Avec la couche API prête, construisez l’interface web. Commencez par configurer la page :

def main():
   st.set_page_config(
       page_title="Multi-Model Comparison Chat",
       page_icon="🤖",
       layout="wide",
       initial_sidebar_state="expanded"
   )

   st.session_state.setdefault("messages", [])
   st.session_state.setdefault("model_responses", [])

La mise en page « wide » libère de l’espace pour trois colonnes. L’état de session préserve l’historique et les réponses lors des relances de script.

Ajoutez le titre de page et les contrôles de la barre latérale :

st.title("🤖 Multi-Model Comparison Chat")
   st.markdown("""
   Compare **Kimi K2 Thinking**, **GPT-5**, and **Claude Sonnet 4.5** side-by-side.
   All three models support reasoning modes - see how they approach problems differently.
   """)

   with st.sidebar:
       st.header("⚙️ Settings")

       st.subheader("Thinking Mode")
       kimi_thinking = st.checkbox("Enable Kimi K2 Thinking", value=True)
       gpt5_reasoning = st.selectbox(
           "GPT-5 Reasoning Effort",
           options=["minimal", "low", "medium", "high"],
           index=2
       )
       claude_thinking = st.checkbox("Enable Claude Thinking", value=True)

La barre latérale permet d’activer les modes de réflexion. Kimi K2 et Claude ont des interrupteurs binaires. GPT-5 propose quatre niveaux car son API expose ce réglage fin.

Sous ces réglages, ajoutez un indicateur d’état des API pour savoir quels services sont connectés :

st.subheader("API Status")
       st.markdown(f"""
       - Kimi K2: {"✅" if os.getenv("OPENROUTER_API_KEY") else "❌"}
       - GPT-5: {"✅" if os.getenv("OPENAI_API_KEY") else "❌"}
       - Claude: {"✅" if os.getenv("ANTHROPIC_API_KEY") else "❌"}
       """)

Les coches s’affichent quand les variables d’environnement sont définies. Une croix rouge signifie qu’il faut ajouter la clé correspondante dans votre .env.

Étape 5 : implémenter la logique de comparaison

Voici le cœur de l’app. Quand l’utilisateur envoie un message, vous appelez les trois modèles en parallèle et affichez les résultats côte à côté.

def call_models_parallel(messages: List[Dict], selected_models: List[str],
                       kimi_thinking: bool, gpt5_reasoning: str,
                       claude_thinking: bool) -> Dict[str, Dict]:
   """Call multiple models in parallel."""
   model_kwargs = {
       "Kimi K2 Thinking": {"enable_thinking": kimi_thinking},
       "GPT-5": {"reasoning_effort": gpt5_reasoning},
       "Claude Sonnet 4.5": {"enable_thinking": claude_thinking}
   }

   with ThreadPoolExecutor(max_workers=3) as executor:
       futures = {
           executor.submit(call_model, m, messages, **model_kwargs[m]): m
           for m in selected_models if m in model_kwargs
       }
       return {futures[f]: f.result() for f in as_completed(futures)}

Cette fonction lance trois appels API simultanément et collecte les résultats à mesure. Des appels séquentiels prendraient 15–30 secondes. En parallèle, on tombe à 5–10 secondes : vous attendez seulement le plus lent.

Intégrez l’exécution parallèle dans l’interface de chat :

   if prompt := st.chat_input("Ask a question to all models..."):
       st.session_state.messages.append({"role": "user", "content": prompt})

       with st.chat_message("user"):
           st.markdown(prompt)

       api_messages = [
           {"role": m["role"], "content": m["content"]}
           for m in st.session_state.messages
       ]

       with st.spinner("🤔 Models are thinking..."):
           responses = call_models_parallel(
               api_messages,
               ["Kimi K2 Thinking", "GPT-5", "Claude Sonnet 4.5"],
               kimi_thinking,
               gpt5_reasoning,
               claude_thinking
           )

       cols = st.columns(3)
       for idx, (model_name, response_data) in enumerate(responses.items()):
           with cols[idx]:
               st.markdown(f"### {model_name}")
               if response_data["reasoning_content"]:
                   with st.expander("🧠 Thinking Process", expanded=False):
                       st.markdown(response_data["reasoning_content"])
               st.markdown(response_data["content"])

Cela crée trois colonnes et affiche chaque réponse dans sa colonne. Le processus de pensée est replié par défaut : les utilisateurs voient d’abord les réponses finales, puis déplient pour analyser le raisonnement.

Étape 6 : tester et affiner

Lancez l’app avec :

streamlit run model_comparison_chat.py

Commencez par un test simple pour valider le tout :

What is 2+2?

Les trois modèles devraient répondre en quelques secondes. Cela valide vos connexions API et confirme l’exécution parallèle. L’app tourne en local : vous contrôlez quand les APIs sont appelées. Chaque requête a un coût (environ $0,01–0,05 pour une comparaison à trois, selon la longueur des réponses), mais en local, vous décidez quand dépenser.

Tester l’app avec des prompts complexes

Vous avez construit l’app comparative et validé des questions simples. Les vraies différences apparaissent en poussant plus loin. Pour les illustrer, j’ai testé les trois modèles avec des prompts complexes. Vous pouvez reproduire ces tests dans votre app. Voici les principaux enseignements.

Les prompts de test

Nous avons choisi trois défis pour évaluer des compétences de raisonnement distinctes.

Test 1 : raisonnement mathématique avancé

Un jardin rectangulaire mesure 24 pieds de long et 18 pieds de large. Un sentier de 2 pieds de large longe l’extérieur du périmètre du jardin. Si Sarah plante des fleurs à une densité de 4 fleurs par pied carré, puis décide d’ajouter des pierres décoratives sur 30 % de la zone plantée (en retirant ces fleurs), combien de fleurs restent ? Et quelle est la surface totale (en pieds carrés) couverte par le sentier ?

Test 2 : raisonnement logique en plusieurs étapes

Quatre amis — Alice, Bob, Carol et David — doivent se placer en ligne pour une photo. Les règles suivantes s’appliquent :

1. Alice doit se tenir à côté de Bob

2. Carol ne peut pas se placer aux extrémités

3. David doit être à gauche d’Alice

Listez toutes les dispositions valides de gauche à droite.

Test 3 : génération de code avec contraintes

Écrivez une fonction Python qui vérifie si une chaîne est une adresse IPv4 valide, avec ces exigences :

1. Valider le format (quatre octets séparés par des points)

2. Chaque octet doit être entre 0 et 255 (pas de zéros non significatifs sauf « 0 »)

3. Rejeter les formats invalides (chaînes vides, trop/pas assez d’octets, caractères non numériques)

4. Complexité en O(n) où n est la longueur de la chaîne

5. Inclure une docstring complète avec exemples

6. Ajouter des annotations de type pour tous les paramètres et la valeur de retour

7. Gérer les cas limites (chaîne vide, None, caractères spéciaux)

Expliquez aussi votre approche de validation et pourquoi elle est en O(n).

Résultats

Les trois modèles résolvent correctement chaque problème, mais par des chemins très différents. Voici la synthèse des performances :

Test

Modèle

Temps (s)

Tokens

Résultat

Problème du jardin

Kimi K2

28,5

3 420

✓ Correct (1 209,6 fleurs, 184 ft²)

 

GPT-5

44,6

1 476

✓ Correct (1 209,6 fleurs, 184 ft²)

 

Claude

19,7

1 386

✓ Correct (1 210 fleurs, 184 ft²)

Disposition pour la photo

Kimi K2

50,5

6 249

✓ Trouve les 2 dispositions valides

 

GPT-5

39,4

1 914

✓ Trouve les 2 dispositions valides

 

Claude

31,3

2 310

✓ Trouve les 2 dispositions valides

Validateur IPv4

Kimi K2

192,6

5 245

✓ Solution O(n) fonctionnelle

 

GPT-5

73,7

4 233

✓ Solution O(n) fonctionnelle

 

Claude

43,1

3 330

✓ Solution O(n) fonctionnelle

Voici ce que fait concrètement chaque modèle pendant ce temps.

L’approche de Kimi K2

Il explore et se remet en question en continu. Sur le problème du jardin, il a visualisé la situation, déroulé les calculs, puis s’est interrompu : « Attendez, vérifions », avant de poursuivre. Pour la photo, il a testé chaque contrainte une par une en montrant son travail.

Le validateur IPv4 a pris plus de 3 minutes car il a passé en revue les cas limites un à un, démontré la complexité O(n) et vérifié plusieurs fois la logique. Vous observez quelqu’un penser à voix haute, se corriger et valider à chaque étape.

L’approche de GPT-5

Méthodique et structuré. Il a segmenté le problème du jardin en sections claires, numéroté les étapes et les a suivies dans l’ordre. Pour la photo, il a procédé poste par poste en vérifiant les règles.

Le code est accompagné d’explications claires et d’une documentation bien organisée. Il se remet moins en question que K2 et ne fonce pas comme Claude. Un bon équilibre entre transparence et concision.

L’approche de Claude

Rapide et efficace. Il identifie rapidement la voie de résolution à chaque test et l’exécute proprement. Pour la photo, il a organisé par cas et déroulé sans s’attarder. Le code IPv4 est propre et bien documenté, avec un accès direct au but.

Claude montre son raisonnement mais ne s’attarde pas sur les vérifications. La vitesse vient d’une confiance dans l’approche et d’un minimum de retours en arrière.

Ces approches différentes créent un arbitrage clair. Choisissez K2 si vous avez besoin d’un raisonnement détaillé pour apprendre, déboguer ou auditer. Choisissez Claude si la vitesse prime et que vous faites confiance au résultat sans inspecter la chaîne de raisonnement. Choisissez GPT-5 pour un compromis entre la verbosité de K2 et la rapidité de Claude.

Note : prenez ces résultats avec prudence ; ils ne couvrent pas de manière exhaustive toutes les capacités des trois modèles.

Conclusion

Vous avez configuré Kimi K2 Thinking via OpenRouter, exploré ses capacités de raisonnement, construit des workflows d’appels d’outils et créé une app comparative pour le confronter à GPT-5 et Claude. Les points forts de K2 sont l’orchestration autonome d’outils et le raisonnement transparent, idéaux pour des workflows complexes où vous devez vérifier les décisions du modèle.

La capacité et le coût de K2 rendent cela concret. Il peut enchaîner de très nombreux appels d’outils là où la plupart se limitent à quelques dizaines, et le champ reasoning_content expose chaque étape de pensée. À environ un quart du coût de GPT-5 et un sixième de celui de Claude pour les tokens de sortie, vous pouvez mener des expérimentations étendues sans grever le budget.

L’app comparative vous fournit des preuves concrètes de ces arbitrages. Testez-la avec vos propres problèmes et workflows pour jauger si le raisonnement détaillé de K2 compense des temps de réponse plus longs. Les tests en situation réelle sur vos cas d’usage révèleront des schémas que les benchmarks génériques ne captent pas.

Pour approfondir, consultez le tutoriel OpenRouter de DataCamp pour gérer plusieurs fournisseurs de LLM, le guide GPT-5 sur les niveaux d’effort de raisonnement, et le guide Claude Sonnet 4 pour le mode de réflexion étendu.

Bexruz (Bex) Tuychiev

Auteur

Bexruz (Bex) Tuychiev

Je suis créateur de contenu en science des données avec plus de 2 ans d’expérience et l’une des plus grandes audiences sur Medium. J’aime écrire des articles détaillés sur l’IA et le ML avec une pointe de sarcasme, histoire de les rendre un peu moins austères. J’ai publié plus de 130 articles et un cours DataCamp, avec un autre en préparation. Mes contenus ont été vus par plus de 5 millions de personnes, dont 20 000 sont devenues abonnées sur Medium et LinkedIn. 

Sujets