Comprenez les modeles de raisonnement OpenAI o3 et Claude extended thinking : reasoning tokens, reasoning effort, budget de reflexion, prompting adapte et maitrise des couts.
Qu'est-ce qu'un modele de raisonnement
Les modeles de langage classiques produisent leur reponse token par token, sans phase de planification explicite. Les modeles de raisonnement changent ce paradigme : avant de repondre, ils generent une chaine de reflexion interne, parfois tres longue, ou ils decomposent le probleme, testent des hypotheses et corrigent leurs erreurs.
Deux familles dominent : la serie o d'OpenAI (o1, o3, o3-mini) et le mode extended thinking de Claude chez Anthropic. Dans les deux cas, le principe est le meme : echanger du temps de calcul (et des tokens) contre une qualite de raisonnement nettement superieure sur les taches difficiles.
Comment fonctionnent les reasoning tokens
Quand vous appelez un modele de raisonnement, il produit deux types de tokens : les reasoning tokens (sa reflexion interne, generalement non visible) et les output tokens (la reponse finale). Les deux sont factures, mais seule la reponse vous est renvoyee en clair.
| Type de token | Visible ? | Facture ? | Role |
|---|---|---|---|
| Input tokens | Oui (votre prompt) | Oui | Le contexte fourni |
| Reasoning tokens | Non (ou resume) | Oui (tarif output) | La reflexion interne |
| Output tokens | Oui | Oui | La reponse finale |
Plus le probleme est dur, plus le modele consacre de reasoning tokens. C'est pourquoi le cout d'une requete varie fortement : une question triviale coute peu, un probleme algorithmique peut consommer des milliers de tokens de raisonnement invisibles.
OpenAI o3 : appel et reasoning effort
Les modeles o d'OpenAI s'appellent comme les autres via l'API, mais exposent un parametre cle : reasoning_effort. Il controle combien le modele « reflechit » : low, medium ou high.
// reasoning-o3.js — appel d'un modele de raisonnement OpenAI
import OpenAI from 'openai';
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const response = await client.responses.create({
model: 'o3',
// reasoning_effort regle la profondeur de reflexion
reasoning: { effort: 'high' }, // low | medium | high
input: [{
role: 'user',
content: `Un train part de Paris a 14h00 a 120 km/h.
Un second part de Lyon (450 km) a 14h30 a 150 km/h vers Paris.
A quelle heure et a quelle distance de Paris se croisent-ils ?`,
}],
});
console.log(response.output_text);
// Les tokens de raisonnement apparaissent dans usage
console.log('Reasoning tokens :', response.usage.output_tokens_details.reasoning_tokens);
console.log('Output tokens :', response.usage.output_tokens);
Choisir le bon effort
// Adapter reasoning_effort a la difficulte de la tache
function pickEffort(task) {
if (task.type === 'classification' || task.type === 'extraction') {
return 'low'; // taches structurees simples
}
if (task.type === 'code-review' || task.type === 'analysis') {
return 'medium'; // raisonnement modere
}
// Algorithmes, preuves, debug complexe
return 'high';
}
const effort = pickEffort({ type: 'analysis' });
const res = await client.responses.create({
model: 'o3-mini', // variante plus economique
reasoning: { effort },
input: [{ role: 'user', content: prompt }],
});
temperature est souvent ignore ou fixe : la « creativite » se regle differemment, par le contenu du prompt plutot que par l'echantillonnage.
Claude extended thinking
Chez Anthropic, le raisonnement s'active via le bloc thinking dans la requete. Vous allouez un budget de tokens de reflexion, et Claude l'utilise (ou non) selon la difficulte.
// reasoning-claude.js — extended thinking avec le SDK Anthropic
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const message = await client.messages.create({
model: 'claude-opus-4-8',
max_tokens: 4096,
// Activer le raisonnement avec un budget de tokens dedie
thinking: {
type: 'enabled',
budget_tokens: 8000, // budget max pour la reflexion interne
},
messages: [{
role: 'user',
content: `Optimise cet algorithme O(n^2) en O(n log n) et explique
la complexite de chaque etape : ${algorithme}`,
}],
});
// La reponse contient des blocs : thinking puis text
for (const block of message.content) {
if (block.type === 'thinking') {
console.log('--- Raisonnement ---');
console.log(block.thinking); // resume de la reflexion
} else if (block.type === 'text') {
console.log('--- Reponse ---');
console.log(block.text);
}
}
Streaming du raisonnement
// Diffuser le raisonnement puis la reponse en streaming
const stream = await client.messages.stream({
model: 'claude-opus-4-8',
max_tokens: 4096,
thinking: { type: 'enabled', budget_tokens: 6000 },
messages: [{ role: 'user', content: prompt }],
});
stream.on('thinking', (delta) => {
// Afficher la reflexion en direct (ex: indicateur "reflechit...")
process.stdout.write(delta);
});
stream.on('text', (delta) => {
// Afficher la reponse finale
process.stdout.write(delta);
});
const final = await stream.finalMessage();
Prompter un modele de raisonnement
Les techniques de prompting classiques ne s'appliquent pas. Demander « reflechis etape par etape » a un modele de raisonnement est inutile, voire contre-productif : il le fait deja, et l'instruction parasite sa reflexion native.
// MAUVAIS prompt pour un modele de raisonnement
"Reflechis etape par etape. D'abord analyse le probleme, puis liste
les options, puis compare-les, puis donne ta reponse finale en
detaillant chaque etape de ton raisonnement..."
// BON prompt : objectif clair + contraintes, pas de methode
"Trouve l'erreur de concurrence dans ce code Go et propose un
correctif minimal. Contraintes : ne pas changer l'API publique,
preserver les performances. Code : ..."
| Modele standard | Modele de raisonnement |
|---|---|
| Chain-of-thought explicite utile | CoT redondant (deja interne) |
| Few-shot ameliore souvent | Few-shot peut degrader |
| Decrire la methode | Decrire l'objectif et les contraintes |
| Prompts longs et detailles | Prompts concis et precis |
// Pattern recommande : objectif + contraintes + format de sortie
const prompt = `
OBJECTIF : refactoriser la fonction ci-dessous pour eliminer la
duplication, sans changer son comportement observable.
CONTRAINTES :
- Conserver la signature publique
- Pas de dependance externe nouvelle
- Couverture des cas limites existants
FORMAT : code corrige uniquement, suivi d'une liste a puces des
changements (3 lignes max).
CODE :
${sourceCode}
`;
Comparatif : raisonnement vs standard
Le choix n'est pas binaire. Beaucoup d'architectures combinent les deux : un modele standard pour le dialogue rapide, un modele de raisonnement appele uniquement quand la tache l'exige.
| Critere | Modele standard | Modele de raisonnement |
|---|---|---|
| Latence | Faible (instantane) | Elevee (reflexion) |
| Cout par requete | Bas | Eleve (reasoning tokens) |
| Maths / logique | Moyen | Excellent |
| Code complexe | Bon | Excellent |
| Chat / resume | Excellent | Sur-dimensionne |
| Planification multi-etapes | Limite | Excellent |
// Routeur de modele : aiguiller selon la complexite estimee
async function routeQuery(userQuery, complexity) {
if (complexity >= 0.7) {
// Tache difficile : modele de raisonnement
return client.responses.create({
model: 'o3',
reasoning: { effort: 'high' },
input: [{ role: 'user', content: userQuery }],
});
}
// Tache simple : modele rapide et economique
return client.responses.create({
model: 'gpt-4o-mini',
input: [{ role: 'user', content: userQuery }],
});
}
Couts et gestion du budget de raisonnement
Le piege principal : les reasoning tokens invisibles gonflent la facture sans que vous les voyiez dans la reponse. Surveillez systematiquement le champ usage.
// Tracker le cout reel incluant les reasoning tokens
function logCost(usage) {
const reasoning = usage.output_tokens_details?.reasoning_tokens ?? 0;
const visible = usage.output_tokens - reasoning;
console.log(`Input : ${usage.input_tokens} tokens`);
console.log(`Reasoning: ${reasoning} tokens (invisibles, factures)`);
console.log(`Reponse : ${visible} tokens visibles`);
// Alerter si le raisonnement explose
if (reasoning > 5000) {
console.warn('Raisonnement tres couteux — verifier la pertinence');
}
}
const res = await client.responses.create({
model: 'o3', reasoning: { effort: 'medium' },
input: [{ role: 'user', content: prompt }],
});
logCost(res.usage);
- Commencer en
effort: lowet monter seulement si necessaire - Plafonner
budget_tokenschez Claude - Router les taches simples vers un modele standard
- Mettre en cache les resultats deterministes
- Logger les reasoning tokens dans votre observabilite
Patterns d'usage en production
Pattern 1 : escalade progressive
// Essayer un modele rapide, escalader vers le raisonnement si echec
async function answerWithEscalation(question, validator) {
// 1. Tentative rapide
let res = await client.responses.create({
model: 'gpt-4o',
input: [{ role: 'user', content: question }],
});
// 2. Si la reponse echoue a la validation, escalader
if (!validator(res.output_text)) {
res = await client.responses.create({
model: 'o3',
reasoning: { effort: 'high' },
input: [{ role: 'user', content: question }],
});
}
return res.output_text;
}
Pattern 2 : planificateur + executeur
// Le modele de raisonnement planifie, un modele rapide execute chaque etape
async function planAndExecute(goal) {
// Le raisonnement decompose l'objectif en etapes
const plan = await client.responses.create({
model: 'o3',
reasoning: { effort: 'medium' },
input: [{ role: 'user', content: `Decompose en etapes JSON : ${goal}` }],
});
const steps = JSON.parse(plan.output_text);
// Chaque etape executee par un modele rapide
const results = [];
for (const step of steps) {
const r = await client.responses.create({
model: 'gpt-4o-mini',
input: [{ role: 'user', content: step.instruction }],
});
results.push(r.output_text);
}
return results;
}
Integrer le raisonnement dans une app web
Le frein numero un cote front-end, c'est la latence : un modele de raisonnement peut reflechir plusieurs secondes avant le premier token. Bloquer une requete HTTP synchrone aussi longtemps degrade l'experience et risque le timeout du navigateur ou du reverse proxy. Deux patterns s'imposent : le streaming SSE pour les reponses interactives, et la file asynchrone pour les traitements longs.
Endpoint Node/Express en Server-Sent Events
// server.js — streamer le raisonnement vers le navigateur en SSE
import express from 'express';
import OpenAI from 'openai';
const app = express();
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
app.get('/api/reason', async (req, res) => {
// En-tetes SSE : flux texte garde ouvert
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
});
const stream = await client.responses.stream({
model: 'o3-mini',
reasoning: { effort: 'medium' },
input: [{ role: 'user', content: String(req.query.q) }],
});
// On envoie un "ping" status pendant la phase de reflexion
stream.on('response.reasoning.delta', () => {
res.write('event: status\ndata: reflexion en cours\n\n');
});
// Puis les tokens de la reponse au fil de l'eau
stream.on('response.output_text.delta', (e) => {
res.write(`event: token\ndata: ${JSON.stringify(e.delta)}\n\n`);
});
stream.on('end', () => {
res.write('event: done\ndata: end\n\n');
res.end();
});
});
app.listen(3000);
Cote client : afficher l'etat puis la reponse
// front.js — consommer le flux SSE sans figer l'interface
const source = new EventSource('/api/reason?q=' + encodeURIComponent(question));
const box = document.getElementById('reponse');
// Indicateur tant que le modele reflechit (UX cruciale)
source.addEventListener('status', () => {
box.dataset.state = 'thinking'; // ex: afficher un spinner "reflechit..."
});
source.addEventListener('token', (e) => {
box.dataset.state = 'streaming';
box.textContent += JSON.parse(e.data); // append token par token
});
source.addEventListener('done', () => source.close());
jobId, le front interroge un endpoint de statut ou recoit une notification WebSocket. On evite ainsi tout timeout HTTP, frequent au-dela de 30 secondes derriere Nginx.
Cas d'usage concrets cote produit
Au-dela de la theorie, voici ou les modeles de raisonnement apportent une vraie valeur dans une application web, et le reglage d'effort recommande pour garder un budget maitrise.
| Cas d'usage | Pourquoi le raisonnement | Effort conseille |
|---|---|---|
| Assistant de code dans l'IDE | Debug subtil, refactoring multi-fichiers | high (a la demande) |
| Moteur de regles metier complexes | Contraintes multiples a satisfaire | medium |
| Analyse de contrats / documents legaux | Coherence et croisement de clauses | high |
| Generation de requetes SQL avancees | Jointures, fenetres, optimisation | medium |
| Tri / classification de tickets | Trivial : surcout injustifie | standard (pas de raisonnement) |
La regle produit : ne jamais brancher un modele de raisonnement sur le chemin critique d'une interaction temps reel sans fallback. Un routeur de modeles (vu plus haut) qui aiguille 80 % du trafic vers un modele rapide et reserve le raisonnement aux 20 % de requetes difficiles offre le meilleur ratio cout/qualite/latence en production.
Pensez aussi au cache semantique : beaucoup de questions complexes se repetent (memes bugs, memes patterns metier). Mettre en cache la reponse d'un modele de raisonnement, indexee par embedding de la question, evite de repayer un raisonnement couteux pour une requete quasi identique — un levier d'economie majeur sur une app a fort trafic.
Pieges courants
- Utiliser un modele de raisonnement pour du chat simple (lent et cher)
- Forcer le chain-of-thought dans le prompt (deja interne)
- Empiler des exemples few-shot (peut degrader le raisonnement)
- Ignorer les reasoning tokens dans le calcul de cout
- Attendre une latence faible (la reflexion prend du temps)
- Compter sur
temperature(souvent inoperant)
L'erreur la plus frequente reste le sur-usage : par enthousiasme, on route tout vers le modele de raisonnement, la facture explose et la latence devient insupportable. La discipline consiste a reserver ces modeles aux 10 a 20 % de requetes qui le justifient vraiment.
Conclusion
Les modeles de raisonnement — OpenAI o3 et Claude extended thinking — representent une nouvelle dimension de l'IA : echanger du calcul contre de la justesse sur les taches difficiles. Ils ne remplacent pas les modeles standard, ils les completent. La cle est de router intelligemment : modele rapide par defaut, raisonnement pour les problemes complexes (algorithmes, debug, planification, maths).
Adaptez votre prompting : objectif et contraintes, pas de methode imposee. Surveillez les reasoning tokens, qui gonflent silencieusement la facture. Avec une strategie d'escalade et un budget maitrise, vous obtenez le meilleur des deux mondes : reactivite au quotidien, puissance de raisonnement quand ca compte.
- Reasoning tokens = reflexion interne facturee mais invisible
- o3 :
reasoning_effortlow/medium/high - Claude :
thinkingavecbudget_tokens - Prompts concis, objectif clair, pas de CoT force
- Router selon la complexite pour maitriser cout et latence