Extended Thinking en Claude 3.7 Sonnet es una herramienta poderosa que es fácil usar mal. Después de implementarlo en aplicaciones reales, estos son los patrones que producen buenos resultados y los antipatrones que cuestan dinero sin mejorar la calidad.
Patrón 1: Presupuesto adaptativo según complejidad
No uses el mismo presupuesto de tokens para todas las queries. Define niveles según la complejidad esperada:
def get_thinking_budget(query_type: str) -> dict:
budgets = {
"simple": {"type": "disabled"},
"medium": {"type": "enabled", "budget_tokens": 2000},
"complex": {"type": "enabled", "budget_tokens": 8000},
"critical": {"type": "enabled", "budget_tokens": 16000},
}
return budgets.get(query_type, budgets["simple"])
# Clasificar queries antes de llamar al modelo
async def classify_and_respond(query: str):
complexity = await classify_complexity(query) # modelo pequeño y rápido
thinking = get_thinking_budget(complexity)
return await claude.messages.create(
model="claude-sonnet-4-5",
thinking=thinking,
messages=[{"role": "user", "content": query}]
)
Usa un modelo pequeño (Haiku) para clasificar la complejidad y así no pagas el coste completo de Extended Thinking en queries sencillas.
Patrón 2: Streaming para mejorar la UX
Extended Thinking añade latencia. Si el usuario espera la respuesta completa, 10-15 segundos se sienten eternos. Usa streaming para mostrar la respuesta mientras se genera:
async def stream_with_thinking(query: str):
with client.messages.stream(
model="claude-sonnet-4-5",
max_tokens=8000,
thinking={"type": "enabled", "budget_tokens": 5000},
messages=[{"role": "user", "content": query}]
) as stream:
thinking_done = False
for event in stream:
if hasattr(event, 'type'):
if event.type == 'content_block_start':
if event.content_block.type == 'thinking':
yield {"type": "status", "text": "Analizando..."}
elif event.content_block.type == 'text':
thinking_done = True
yield {"type": "status", "text": "Preparando respuesta..."}
elif event.type == 'content_block_delta':
if thinking_done and hasattr(event.delta, 'text'):
yield {"type": "text", "content": event.delta.text}
Muestra un indicador de “pensando…” mientras el modelo razona, y empieza a mostrar la respuesta en streaming cuando comienza la parte de texto.
Patrón 3: Caché de respuestas para queries similares
Extended Thinking es caro. Si las queries se repiten (o son variaciones de lo mismo), cachea los resultados:
import hashlib
import json
from functools import lru_cache
def query_key(query: str) -> str:
return hashlib.sha256(query.encode()).hexdigest()[:16]
# Usa Redis en producción
response_cache = {}
async def cached_thinking_response(query: str, budget: int = 5000):
key = query_key(query)
if key in response_cache:
return response_cache[key]
response = await client.messages.create(
model="claude-sonnet-4-5",
thinking={"type": "enabled", "budget_tokens": budget},
messages=[{"role": "user", "content": query}]
)
response_cache[key] = response
return response
Patrón 4: Separar razonamiento de respuesta
A veces quieres el razonamiento para auditarlo o mostrárselo al usuario:
def extract_thinking_and_response(response) -> tuple[str, str]:
thinking = ""
answer = ""
for block in response.content:
if block.type == "thinking":
thinking = block.thinking
elif block.type == "text":
answer = block.text
return thinking, answer
# Uso para debugging o transparencia
thinking, answer = extract_thinking_and_response(response)
print(f"El modelo razonó así:\n{thinking[:500]}...")
print(f"\nRespuesta final:\n{answer}")
Antipatrón 1: Activar Extended Thinking para todo
El error más común y caro. Extended Thinking no mejora la generación de contenido, clasificación simple, extracción de datos estructurados, o resúmenes de texto.
No hagas esto:
# Cada request tiene Extended Thinking aunque no lo necesite
response = client.messages.create(
thinking={"type": "enabled", "budget_tokens": 10000}, # ❌
messages=[{"role": "user", "content": "Resume este email en 3 puntos"}]
)
Haz esto:
response = client.messages.create(
thinking={"type": "disabled"}, # ✓ para tareas simples
messages=[{"role": "user", "content": "Resume este email en 3 puntos"}]
)
Antipatrón 2: Budget demasiado alto por defecto
budget_tokens=16000 no siempre produce mejor resultado que budget_tokens=5000. La calidad se aplana rápidamente. Empieza con 2000-5000 y sube solo si los resultados no son suficientes.
Antipatrón 3: Mostrar el razonamiento sin filtrar
Si expones el bloque de pensamiento al usuario, puede contener razonamiento que parece incorrecto aunque la conclusión final sea correcta. El proceso de razonamiento interno puede explorar hipótesis falsas antes de descartarlas. No asumas que el pensamiento es siempre “limpio”.
Antipatrón 4: No medir si ayuda
Implementa métricas para saber si Extended Thinking mejora la calidad en tu caso de uso específico. En algunos dominios, la diferencia es marginal y no justifica el coste.
# Evalúa con y sin thinking en tu dataset de test
results_with_thinking = evaluate_model(queries, thinking_enabled=True)
results_without_thinking = evaluate_model(queries, thinking_enabled=False)
improvement = results_with_thinking.accuracy - results_without_thinking.accuracy
cost_ratio = results_with_thinking.cost / results_without_thinking.cost
print(f"Mejora de calidad: {improvement:.1%}")
print(f"Factor de coste: {cost_ratio:.1f}x")
# Decide si vale la pena
Patrones derivados de implementaciones en producción durante Q1 2026.