Thinking siempre activo y modos de display

Resumen

El día que lanzaron Fable 5, varios desarrolladores con código funcional en Opus 4.8 empezaron a recibir errores 400 sin explicación. Mismo request, mismo endpoint, distinto resultado. ¿La causa? El thinking dejó de ser un interruptor y pasó a estar siempre encendido. Aquí te explico qué cambió, cómo migrar sin romper tu API y dónde se esconden los costos.

En Opus 4.8 tú decidías cuándo arrancar el motor del razonamiento. En Fable 5 ese motor ya está andando cuando llegas, y lo único que puedes hacer es decidir cuántas revoluciones le das con el parámetro effort y si quieres ver el humo que sale con el display mode [00:45].

¿Por qué Fable 5 devuelve error 400 si pides desactivar thinking?

La diferencia central con Opus 4.8 está en que el razonamiento interno dejó de ser opcional. No hay switch, no hay flag, no hay forma de apagarlo. El modelo razona antes de cada respuesta, sin excepción.

Si tu código intenta decirle desactiva thinking o le pasa un budget manual de tokens, Fable 5 te devuelve un 400 inmediato [00:36]. Piénsalo como un motor que nunca se apaga: solo puedes regular su intensidad.

¿Cómo migro mi código de Opus 4.8 a Fable 5 sin romperlo? Tienes dos caminos seguros: omitir el campo thinking por completo o enviarlo con type: adaptive de forma explícita. Ambos funcionan.

¿Cuál es la trampa silenciosa al migrar desde Opus?

Si tenías rutas en Opus que corrían sin thinking, gastaban cero tokens en razonamiento. Ese mismo request en Fable 5 ahora consume parte de tu max_tokens en pensamiento interno antes de escribir una palabra de respuesta.

El escenario peligroso: si tenías max_tokens en 256 para una tarea simple de clasificación, el modelo puede agotar el límite mientras piensa y devolverte cero output útil [01:30]. Diagnostícalo revisando el campo thinking_tokens dentro de usage.

¿Qué hace el parámetro display y cómo afecta latencia y costo?

El display mode decide qué ves tú del razonamiento, no cuánto pagas. Tiene dos valores con comportamientos muy distintos en streaming.

  • Omitted es el default. El modelo piensa, pero el campo thinking llega vacío. Lo que sí viaja es una signature encriptada necesaria para continuidad en conversaciones multi-turn. En streaming no se envían thinking deltas, así que el texto de respuesta empieza a llegar antes.
  • Summarized te devuelve una versión condensada y legible del razonamiento. En streaming, el summary llega primero y solo después arranca el texto.

Y aquí viene lo contraintuitivo: la facturación es idéntica en ambos modos. El display controla visibilidad, no costo. Generar el summary es gratuito, y omitted reduce latencia, no gasto [02:23].

¿Cuándo uso omitted y cuándo summarized? Usa omitted en producción por el menor time-to-first-text-token. Usa summarized solo para debugging o para UIs con un drawer de razonamiento expandible.

¿Cómo leo el campo usage para entender mi factura?

Puedes recibir una respuesta con casi cero tokens visibles y que te cobren 300 tokens de output. El campo usage te da el desglose real:

  • output_tokens es el total facturado.
  • Dentro de output_tokens_details encuentras thinking_tokens, los tokens de razonamiento interno.
  • La diferencia entre ambos es tu texto real.

Con Fable 5 a 50 dólares por millón de tokens de output, saber qué rutas gastan fuerte en razonamiento te permite bajar el effort selectivamente. Y un punto que confunde a mucha gente: el raw chain of thought nunca se devuelve, bajo ninguna configuración. Solo recibes un string vacío o un summary, más la signature encriptada [03:15].

¿Cómo manejo thinking en flujos multi-turn y con herramientas?

Cuando el modelo usa herramientas, puede razonar entre tool calls. Esos thinking blocks aparecen mezclados con text blocks y tool use blocks en un solo array, en el orden que el modelo los produjo. Si el request es simple, el modelo se salta el bloque por completo.

¿Cuáles son los tres errores más comunes al integrar Fable 5?

  1. Direccionar content blocks por índice. Las posiciones se mueven cuando thinking se omite, así que vas a romper tu lógica.
  2. Filtrar o modificar thinking blocks antes de mandarlos de vuelta al modelo. Eso produce un 400.
  3. Tratar un thinking field vacío como un bug. Es omitted mode funcionando correctamente.

Para multi-turn, si sigues con el mismo modelo, devuelve todo intocado. Si cambias de modelo, elimina los thinking blocks de turnos anteriores, porque cuentan como input tokens aunque se ignoren.

¿Por qué mi prompt recibe un refusal silencioso al pedir razonamiento?

Si tu prompt dice algo como muestra tu razonamiento paso a paso, se activa el clasificador reasoning_extraction, que te devuelve un refusal silencioso: HTTP 200 con stop_reason: refusal [04:33].

La solución correcta no es pedirlo en el prompt. Es configurar display en summarized y auditar tus system prompts buscando lenguaje de reflexión antes de migrar. Ese pequeño ajuste evita rechazos que no aparecen como error y que pueden pasar inadvertidos en producción.

En la siguiente clase vamos a tomar este mecanismo siempre activo y ponerle un control de profundidad real con output_effort, modulando niveles desde low hasta max. Vas a aprender a construir workflows donde el triaje corre en low y la implementación en max, sin quemar presupuesto. ¿Ya migraste alguna ruta a Fable 5? Cuéntame qué errores te aparecieron primero.