Coges un script de hace un año que llama a Claude con temperature=0.2, termina los mensajes con un { para forzar JSON y lee la respuesta con content[0].text. Cambias el modelo a claude-opus-5-5 y la API te devuelve un 400. Y cuando arreglas eso, el texto sale vacío.
No es mala suerte: son cambios documentados de los modelos actuales, y el examen los pregunta dentro del dominio de selección de modelos («cambios de comportamiento que rompen entre versiones»). Esta lección cubre la parte más pesada del examen: la mecánica de la API (dominio 2, el 33,1 %) y los fundamentos de LLM que la sostienen (dominio 5).
La petición mínima, pieza a pieza
Todo pasa por un endpoint: POST https://api.anthropic.com/v1/messages. Tres cabeceras obligatorias (x-api-key, anthropic-version: 2023-06-01 y content-type: application/json) y un cuerpo JSON. Los SDK oficiales (Python, TypeScript, Java, Go, C#, Ruby y PHP) ponen las cabeceras por ti.
import anthropic
client = anthropic.Anthropic() # lee ANTHROPIC_API_KEY del entorno
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
system="Eres un analista de compras. Responde en español, en tres frases como máximo.",
messages=[
{"role": "user", "content": "Resume este pedido: 40 unidades del material 100-200, entrega el 15 de octubre."}
],
output_config={"effort": "low"},
)
# Lee por tipo de bloque, nunca por posición: puede haber bloques de thinking delante
texto = "".join(b.text for b in response.content if b.type == "text")
print(texto)
print(response.stop_reason, response.usage.input_tokens, response.usage.output_tokens)
Pulsa cada campo para ver qué hace y dónde suele fallar la gente:
model · Qué modelo responde
Un ID exacto: claude-fable-5-1, claude-opus-5-5, claude-sonnet-5-5 o claude-haiku-4-5-20251001. Desde la generación 4.6, los IDs sin fecha también son instantáneas fijas, así que tu versión no cambia sola.
Obligatorios: model, max_tokens y messages. El resto, según el caso.
Los fundamentos que el examen da por sabidos
El dominio 5 empieza por lo básico, y conviene tenerlo fino porque aparece camuflado en escenarios:
- Tokens. El modelo lee y escribe tokens, no palabras. Se cobra por token de entrada y de salida, y los límites se miden en tokens. Para saber cuánto ocupa una petición antes de enviarla existe
client.messages.count_tokens(...). - Ventana de contexto. Todo lo que el modelo ve en una llamada: system, herramientas, historial y la respuesta que genera. Fable 5.1, Opus 5.5 y Sonnet 5.5 tienen 1M de tokens; Haiku 4.5, 200K. La salida máxima síncrona es de 128K en los tres primeros y 64K en Haiku.
- Generación token a token y no determinismo. El modelo predice el siguiente token con una distribución de probabilidad y muestrea. La misma petición puede dar respuestas distintas. Si tu aplicación necesita consistencia, no la busques en un parámetro mágico: usa instrucciones claras, ejemplos, salidas estructuradas y validación en código.
- Muestreo en los modelos nuevos. Opus 5.5 y Sonnet 5.5 rechazan valores de
temperature,top_potop_kdistintos del de por defecto: sus guías de migración piden quitarlos. Haiku 4.5 sí los acepta. - SDK frente a REST. Los SDK envuelven la misma API REST y añaden reintentos, tipos, streaming cómodo y helpers. La API de mensajes hace streaming con SSE sobre HTTP, no con websockets.
Thinking adaptativo y effort
En los modelos actuales ya no reservas un presupuesto de pensamiento a mano. El modelo decide cuánto pensar (thinking adaptativo) y tú lo orientas con effort:
| Modelo | Thinking | Effort por defecto |
|---|---|---|
| Claude Fable 5.1 | Adaptativo, siempre activo | high |
| Claude Opus 5.5 | Adaptativo, siempre activo | medium |
| Claude Sonnet 5.5 | Adaptativo | high |
| Claude Haiku 4.5 | Extendido (budget_tokens) | No admite effort |
Detalles que caen en examen:
- En Opus 5.5 y Fable 5.1 el thinking no se puede desactivar:
thinking: {"type": "disabled"}devuelve 400. En Sonnet 5.5 el ajuste mínimo es{"type": "between_tools"}. max_tokenscubre pensamiento y texto, y los tokens de thinking se facturan como salida. Al subir axhighomax, sube tambiénmax_tokens.- En Opus 5.5 el texto del thinking viene vacío por defecto (
display: "omitted"). Si tu interfaz enseña el razonamiento, pidethinking={"type": "adaptive", "display": "summarized"}. - En bucles con herramientas, devuelve los bloques de thinking tal cual los recibiste. Si los editas, reordenas o filtras, la API responde 400.
- Existe un fast mode (vista previa de investigación) para Opus 5.5 con
speed: "fast": más rápido a precio superior y solo en la API directa de Anthropic.
Lo que rompe al migrar código antiguo
Este cuadro resume las guías oficiales de migración a Opus 5.5 y Sonnet 5.5. Es material de examen puro:
Código escrito para modelos antiguos
Devuelve 400 o se comporta raro en Opus 5.5
- `temperature=0.2` para respuestas estables
- Último mensaje `assistant` con `{` para forzar JSON (prefill)
- `thinking: {type: disabled}` para ahorrar
- `tool_choice: {type: tool}` para obligar a usar una herramienta
- `response.content[0].text` para leer la respuesta
Código para los modelos actuales
Lo que piden las guías de migración
- Sin parámetros de muestreo: consistencia con prompt, ejemplos y validación
- **Salidas estructuradas** (`output_config.format`) o instrucciones en el system
- Controlar el gasto bajando **effort**
- `tool_choice` en `auto` con **strict tool use**, y decir en el prompt cuándo usarla
- Leer bloques por `type`, porque el thinking puede ir primero
El prefill dejó de admitirse a partir de los modelos 4.6. El tool_choice forzado (any o tool) no lo admiten Opus 5.5, Sonnet 5.5 ni Fable 5.1.
Tras cambiar el modelo a claude-opus-5-5, una petición falla con 400 «This model does not support assistant message prefill». ¿Cuál es la corrección recomendada?
Streaming: qué llega y en qué orden
Con streaming la respuesta llega como una secuencia de eventos SSE. Recórrela:
Un objeto Message con content vacío y el uso inicial de tokens.
Con el SDK no tienes que montar el parser:
with client.messages.stream(
model="claude-sonnet-5-5",
max_tokens=8192,
messages=[{"role": "user", "content": "Explica el flujo de un pedido de venta en SAP S/4HANA."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
final = stream.get_final_message() # el Message completo, igual que sin streaming
print("\n", final.stop_reason, final.usage.output_tokens)
Cuándo usarlo: respuestas largas, interfaces donde alguien mira la pantalla y cualquier petición que pueda superar los diez minutos. Los SDK, de hecho, avisan si una petición sin streaming se espera que pase de ese tiempo.
Errores y reintentos
La API devuelve errores JSON con type, message y un request_id. Los que tienes que reconocer:
| Código | Tipo | Qué hacer |
|---|---|---|
| 400 | invalid_request_error | Corregir la petición. Reintentar no sirve. |
| 401 / 403 | authentication_error / permission_error | Clave inválida o sin permisos para ese recurso. |
| 413 | request_too_large | Petición por encima del límite (32 MB en Messages). |
| 429 | rate_limit_error | Esperar lo que diga la cabecera retry-after y reintentar. |
| 500 | api_error | Reintentar con backoff exponencial. |
| 529 | overloaded_error | Sobrecarga temporal: backoff y reintento. |
Los SDK ya reintentan dos veces por defecto con backoff exponencial los errores de conexión, los 429 y los 5xx, respetando retry-after. Lo ajustas con max_retries:
client = anthropic.Anthropic(max_retries=4, timeout=120.0)
try:
response = client.messages.create(model="claude-opus-5-5", max_tokens=1024,
messages=[{"role": "user", "content": "Hola"}])
except anthropic.RateLimitError:
... # sigue fallando tras los reintentos: encola y vuelve más tarde
except anthropic.APIStatusError as e:
print(e.status_code, e.response.headers.get("request-id")) # guárdalo para soporte
Una trampa fina: cuando tu organización llega a su tope de gasto mensual, también recibes un 429, pero sin retry-after, con el código enforced_spend_limit_reached. Ahí reintentar no arregla nada.
Visión, documentos y dónde corre Claude
La misma API acepta entrada multimodal: bloques image (en base64 o por URL, hasta 8000x8000 píxeles) y bloques document para PDF, mezclados con texto en el mismo mensaje. Así se lee un albarán escaneado o una factura en PDF sin OCR aparte.
Y la misma API se consume desde varios sitios: la API de Anthropic, Amazon Bedrock, Google Cloud (Vertex AI), Microsoft Foundry y Claude Platform on AWS. Dos matices de examen: los IDs cambian en Bedrock (por ejemplo anthropic.claude-opus-5-5) y no todas las funciones están en todas partes (el fast mode, por ejemplo, solo existe en la API directa). Si tu empresa ya consume modelos desde SAP, el Generative AI Hub de SAP AI Core es otra vía gobernada; lo contamos en Claude y SAP.
Para el examen
Dominio · D2 Applications and Integration (Claude API Mechanics) · D5 Model Selection and Optimization (LLM y Technical Fundamentals)
Lo que tienes que dominar
- La API no guarda estado: reenvías el historial;
systemes un parámetro, no un rol. - Thinking adaptativo controlado con
output_config.effort; en Opus 5.5 y Fable 5.1 no se puede apagar ymax_tokenscubre thinking más texto. - Opus 5.5 y Sonnet 5.5 rechazan prefill, muestreo no por defecto y
tool_choiceforzado: la alternativa es salidas estructuradas, prompting y strict tool use. - Streaming SSE:
message_start, bloques concontent_block_*,message_deltacon elstop_reason,message_stop; puede llegar unerrorcon HTTP 200. - Errores: 400 no se reintenta; 429, 500 y 529 sí, con backoff; los SDK reintentan 2 veces por defecto.
Donde se suele fallar
- Leer
content[0].text: con thinking el primer bloque puede no ser texto. - Pensar que bajar
temperaturees la forma de hacer consistente a Opus 5.5. - Reintentar un 400 o un 429 por tope de gasto como si fuera un límite de tasa.
- Creer que el streaming de la API usa websockets.
Checklist para el examen
0 de 7 dominadosMarca lo que ya sabrías responder en el examen.
Ponte a prueba
Tipo test
6 preguntas sobre esta lección. Responde una a una; verás las soluciones al terminar.
Siguiente parada
Próxima lección: prompt y context engineering para desarrolladores. Instrucciones, ejemplos, etiquetas XML, salidas estructuradas y cómo evitar que el contexto se llene de ruido.