Lección 04
Chain-of-thought: cómo hacer que el modelo razone
Cuatro palabras que duplican la precisión en problemas de lógica, matemáticas y planificación. Y cómo combinarlas con JSON prefill.
El truco que vale para todo
Hay un descubrimiento famoso (paper de Google, 2022) que dice algo casi tonto pero brutalmente útil:
Si le añades “Razona paso a paso” a tu prompt, el modelo razona mejor.
Suena a chiste. No lo es. Pasa esto:
- Sin chain-of-thought: el modelo genera la respuesta directa.
- Con chain-of-thought: el modelo genera primero el razonamiento, después la respuesta.
Como los tokens posteriores dependen de los anteriores, escribir el razonamiento mejora la respuesta final. El modelo “se apoya” en su propio texto.
Ejemplo: problema de lógica
Sin chain-of-thought:
const res = await client.messages.create({
model: "claude-haiku-4-5",
max_tokens: 50,
messages: [
{
role: "user",
content:
"En una caja hay 3 pelotas rojas y 5 azules. Saco 2 sin mirar. ¿Probabilidad de que ambas sean rojas?",
},
],
});
// → Suele fallar o dar una respuesta corta sin justificar.
Con chain-of-thought:
const res = await client.messages.create({
model: "claude-haiku-4-5",
max_tokens: 400,
messages: [
{
role: "user",
content:
"En una caja hay 3 pelotas rojas y 5 azules. Saco 2 sin mirar. ¿Probabilidad de que ambas sean rojas?\n\nRazona paso a paso antes de dar la respuesta final.",
},
],
});
// → Calcula 3/8 × 2/7 = 6/56 = 3/28 ≈ 10.7%
El patrón profesional: pensar dentro de etiquetas
En producción, no quieres devolver al usuario todo el razonamiento. Truco: pídele que piense dentro de <thinking> y luego dé la respuesta final.
const res = await client.messages.create({
model: "claude-opus-4-7",
max_tokens: 800,
system: `Eres un asistente que razona dentro de etiquetas <thinking>...</thinking> antes de responder.
La respuesta final SIEMPRE va dentro de <answer>...</answer>.`,
messages: [
{ role: "user", content: "¿Cuánto vale 23 × 47?" },
],
});
const text = res.content[0].text;
const answer = text.match(/<answer>(.*?)<\/answer>/s)?.[1].trim();
console.log(answer); // → "1081"
Ahora al usuario sólo le enseñas <answer> y al modelo le has dado un sitio donde pensar.
Combinación letal: chain-of-thought + JSON prefill
Cuando necesitas JSON estructurado pero también razonamiento, mezcla los dos patrones:
const res = await client.messages.create({
model: "claude-opus-4-7",
max_tokens: 1000,
system: `Eres un clasificador de tickets.
Primero razona dentro de <thinking>. Después devuelve JSON con campos "categoria" y "prioridad".`,
messages: [
{
role: "user",
content: "Email: 'La web está caída para todos nuestros usuarios desde hace 20 minutos.'",
},
{
role: "assistant",
content: "<thinking>",
},
],
});
const raw = "<thinking>" + res.content[0].text;
const json = JSON.parse(raw.split("</thinking>")[1].match(/\{.*\}/s)?.[0] ?? "{}");
console.log(json);
// → { categoria: "bug", prioridad: "alta" }
Cuándo NO usar chain-of-thought
- Latencia importa: añade segundos a la respuesta.
- Coste importa: paga el doble o triple de tokens.
- Tarea trivial: para traducir o resumir no aporta nada.
Regla de oro: si el problema requiere más de un paso lógico, paga el chain-of-thought. Si no, ahórrate los tokens.
Reto
Diseña un prompt que reciba un problema de programación dinámica (por ejemplo “encuentra la subsecuencia común más larga entre dos strings”) y devuelva:
- Un razonamiento sobre cómo abordarlo.
- El algoritmo paso a paso.
- El código TypeScript final.
Todo dentro de etiquetas distintas para que puedas parsearlo después.
En la siguiente y última lección montamos el proyecto final: un extractor de datos estructurados con tests automáticos.
Reto Pro
Reto Pro de esta lección
Misma idea, sin pistas, evaluada por tests automáticos.
Hard Mode
Hard Mode
Variante extrema del reto. Tiempo límite y restricciones adicionales.