Cap 26: API Fundamentals para Arquitectos
Este tutorial cubre los conceptos de la API de Claude que el examen Claude Certified Architect – Foundations evalúa directamente y que los tutoriales anteriores no han cubierto en detalle.
1. Thinking adaptativo — razonamiento interno
El thinking permite que Claude genere tokens de razonamiento internos antes de producir su respuesta. En la generación vigente de modelos ese razonamiento se activa con thinking: { type: "adaptive" }: el modelo decide cuánto razonar según la dificultad de la tarea, sin que tú dimensiones un presupuesto fijo.
Regla de identificadores de modelo
Desde la generación 4.6 los IDs no llevan sufijo de fecha aunque siguen siendo snapshots pinneados. Nunca escribas fechas en claude-opus-4-8, claude-sonnet-5 ni claude-fable-5. Los alias de la API son opus → Opus 4.8 y sonnet → Sonnet 5.
budget_tokens está eliminado
thinking: { type: "enabled", budget_tokens: N } devuelve 400 en Fable 5, Opus 4.8, Opus 4.7 y Sonnet 5.
| Modelo | Cómo se activa el razonamiento |
|---|---|
claude-fable-5 | Thinking siempre activo; { type: "disabled" } devuelve 400 |
claude-opus-4-8, claude-opus-4-7 | { type: "adaptive" }; aceptan { type: "disabled" } y, si se omite el campo, corren sin thinking |
claude-sonnet-5 | { type: "adaptive" } (thinking adaptativo por defecto) |
claude-haiku-4-5 | Único de la tabla actual con extended thinking clásico (budget_tokens); no soporta adaptive |
claude-opus-4-6, claude-sonnet-4-6 | budget_tokens sigue funcionando, pero deprecado |
Thinking tokens vs Output tokens
| Tipo | Visible al usuario | Se cobra como |
|---|---|---|
thinking | No por defecto (display: "omitted") | Output tokens |
text (output) | Sí | Output tokens |
Los thinking tokens se cobran igual que los output tokens. Subir el nivel de razonamiento sin necesidad sube el costo sin beneficio.
Árbol de decisión: razonamiento y esfuerzo
flowchart TD
A[¿La tarea requiere razonamiento?] -->|No| B["Opus 4.8/4.7: omitir 'thinking'<br/>(corren sin thinking)"]
A -->|Sí| C["thinking type adaptive"]
C --> D{"¿Cuánta profundidad?"}
D -->|"Extracción, clasificación,<br/>respuestas cortas"| E["output_config.effort: 'low' o 'medium'"]
D -->|"Uso general"| F["output_config.effort: 'high' (default)"]
D -->|"Coding y agentes"| G["output_config.effort: 'xhigh' (recomendado)"]
D -->|"Problemas abiertos<br/>de máxima dificultad"| H["output_config.effort: 'max'"]
C --> I{"¿Necesito ver el razonamiento?"}
I -->|No| J["display: 'omitted' (default,<br/>bloques vacíos)"]
I -->|Sí| K["display: 'summarized'"]
Cuándo subir el esfuerzo y cuándo no
Subir: análisis de trade-offs arquitectónicos, debugging de comportamiento inesperado, planificación de sistemas complejos, bucles agénticos de coding.
No subir: extracción de campos de un JSON, clasificación de texto, generación de código repetitivo, cualquier tarea donde la respuesta directa es suficiente.
Implementación
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
// Caso de uso: analizar trade-offs de diseño
const response = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 16000,
thinking: { type: "adaptive" },
output_config: { effort: "xhigh" }, // GA, sin cabecera beta
messages: [
{
role: "user",
content:
"Analiza los trade-offs entre PostgreSQL y DynamoDB para un sistema " +
"de e-commerce con 10M usuarios, picos de 50k req/s en Black Friday " +
"y necesidad de transacciones ACID en pedidos.",
},
],
});
// Los bloques "thinking" llegan VACÍOS salvo que pidas display: "summarized"
for (const block of response.content) {
if (block.type === "text") {
console.log(block.text); // Esta es la respuesta final
}
}
Ver el razonamiento: display
thinking.display vale "omitted" por defecto en Fable 5, Mythos 5, Opus 4.8/4.7 y Sonnet 5: los bloques thinking llegan vacíos. Para obtener razonamiento visible hay que pedirlo explícitamente:
const response = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 4096,
thinking: { type: "adaptive", display: "summarized" },
messages: [{ role: "user", content: "…" }],
});
Nota del examen:
summarizeddevuelve un resumen del razonamiento. La cadena de pensamiento cruda nunca se devuelve por la API.
1b. output_config.effort — la palanca de razonamiento vs costo
El parámetro de esfuerzo es hoy el control principal de profundidad de razonamiento frente a costo, y sustituye funcionalmente tanto a budget_tokens como al viejo ajuste por temperature.
- Va anidado en
output_config, nunca como campo top-level. - Es GA: no requiere cabecera beta.
- Valores:
low | medium | high | xhigh | max. - Default
highen Opus 4.8 (todas las superficies) y en Sonnet 5 (Claude API y Claude Code). xhighes el nivel recomendado para coding y agentes.- Opus 4.6 y Sonnet 4.6 no tienen
xhigh.
const response = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 8192,
thinking: { type: "adaptive" },
output_config: { effort: "xhigh" },
messages: [{ role: "user", content: "Refactoriza este módulo…" }],
});
2. Prompt Caching — reducir latencia y costo
Prompt caching permite que el servidor reutilice el procesamiento de un prefix del prompt entre llamadas consecutivas.
Cómo funciona
sequenceDiagram
participant App
participant API as Anthropic API
participant Cache
App->>API: Request 1 (system prompt largo + query)
Note over API: Procesa todo el prefix
API->>Cache: Guarda prefix en caché (TTL: ~5 min)
API-->>App: Response 1 (latencia normal)
App->>API: Request 2 (mismo system prompt + nueva query)
API->>Cache: ¿Existe el prefix?
Cache-->>API: HIT — recupera prefix procesado
Note over API: Solo procesa la nueva query
API-->>App: Response 2 (~90% menos latencia en prefix)
Marcado con cache_control
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
// CLAUDE.md del proyecto (3000+ tokens, se repite en cada llamada de CI)
const projectContext = await Bun.file("CLAUDE.md").text();
const response = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 2048,
system: [
{
type: "text",
text: projectContext,
cache_control: { type: "ephemeral" }, // cachear este prefix
},
],
messages: [
{
role: "user",
content: "¿Qué comando uso para iniciar el servidor de desarrollo?",
},
],
});
Dónde colocar cache_control
Siempre en el último bloque estático antes de la parte dinámica. Si el caché se marca en el medio de una cadena que cambia, se invalida.
| Posición correcta | Resultado |
|---|---|
| System prompt completo (estático) | Cachea todo el system prompt |
| Documento grande en primer user message | Cachea system + documento |
| Historial de conversación hasta N-1 | Cachea contexto acumulado |
Advertencia: si el texto que marcas con cache_control cambia entre llamadas (aunque sea un carácter), el caché se invalida y vuelve a procesar completo.
Casos de uso ideales
CLAUDE.mdlargo en pipelines de CI que se ejecutan muchas veces- Base de conocimiento que se consulta en múltiples queries del mismo usuario
- Contexto de proyecto estático en agentic loops largos
Impacto en métricas
- Latencia: ~90% de reducción en el procesamiento del prefix cacheado
- Costo de input: ~30–50% de reducción (los tokens cacheados tienen precio menor)
- Costo de output: sin cambio
3. Sampling eliminado y salida estructurada
temperature, top_p y top_k ya no se aceptan
Los tres parámetros de sampling devuelven 400 en Fable 5, Opus 4.8 y Opus 4.7; en Sonnet 5 se rechaza cualquier valor que no sea el default. El comportamiento del modelo se dirige hoy por prompting, no por sampling.
| Parámetro | Qué era | Estado en la generación vigente |
|---|---|---|
temperature | Aleatoriedad de la distribución de tokens | 400 en Fable 5, Opus 4.8 y Opus 4.7; valores no-default rechazados en Sonnet 5 |
top_p | Nucleus sampling: tokens hasta probabilidad acumulada p | Igual que temperature |
top_k | Solo los k tokens más probables. Sí era un parámetro de la API de Messages | Igual que temperature |
Corrección frecuente:
top_kno era un parámetro “no expuesto” en la API de Claude. Existía como parámetro de sampling; lo que ocurre hoy es que fue eliminado en los modelos vigentes.
Nota histórica: en modelos legacy (Opus 4.5, Sonnet 4.5 y anteriores) sí se usaba temperature: 0 para acercarse al determinismo, sin garantía total por el paralelismo de punto flotante en hardware.
Qué se usa en su lugar
flowchart LR
A1["temperature: 0<br/>para forzar JSON"] --> B1["output_config.format<br/>structured outputs"]
A2["temperature baja<br/>para menos divagación"] --> B2["output_config.effort<br/>low o medium"]
A3["budget_tokens alto<br/>para más razonamiento"] --> B3["output_config.effort<br/>xhigh o max"]
A4["Prefill del turno assistant<br/>para forzar formato"] --> B4["structured outputs o<br/>instrucciones en el system prompt"]
Structured outputs (GA)
La API de structured outputs es GA y es el sustituto oficial tanto del prefill del turno assistant como del uso de temperature: 0 para forzar formato. Se configura con output_config.format:
const response = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 512,
output_config: {
format: {
type: "json_schema",
schema: {
type: "object",
properties: {
numero_factura: { type: "string" },
total: { type: "number" },
moneda: { type: "string" },
},
required: ["numero_factura", "total", "moneda"],
additionalProperties: false,
},
},
},
messages: [{ role: "user", content: invoiceText }],
});
output_format(nombre antiguo) y la cabecera betastructured-outputs-2025-11-13solo funcionan durante el periodo de transición. Lo vigente esoutput_config.format.- Para tools, el campo complementario es
strict: truecomo campo top-level de la definición de la tool, que exigeadditionalProperties: falseyrequireden el schema:
const extractInvoiceFieldsTool = {
name: "extract_invoice_fields",
description: "Extrae los campos estructurados de una factura",
strict: true, // top-level, no dentro de input_schema
input_schema: {
type: "object",
properties: {
numero_factura: { type: "string" },
total: { type: "number" },
},
required: ["numero_factura", "total"],
additionalProperties: false,
},
};
Clave para el examen: el prefill del turno assistant final está eliminado (devuelve
400) en Fable 5, Opus 4.6/4.7/4.8 y Sonnet 4.6/5. Si el material de estudio te propone prellenar{"en un mensajeassistantpara forzar JSON, esa técnica ya no aplica: usa structured outputs o instrucciones en el system prompt.
4. tool_choice — control completo sobre ejecución de tools
Esta sección es crítica para el examen. El parámetro tool_choice controla si Claude puede, debe o no debe usar tools.
Los 4 modos
flowchart TD
Q[¿Necesito que Claude use tools?] --> A{¿Cuánta certeza?}
A -->|"No sé si la query\nnecesita tools"| M1["auto\nClaude decide"]
A -->|"Debe usar alguna tool\npero no sé cuál"| M2["any\nAl menos una tool"]
A -->|"Debe usar\nUNA tool específica"| M3["tool + name\nExactamente esa tool"]
A -->|"No debe usar tools\nen este turno"| M4["none\nSolo texto"]
Tabla comparativa
| Modo | Claude puede responder sin tool | Claude elige la tool | Error si no hay tools | Uso típico |
|---|---|---|---|---|
auto | Sí | Sí | No | Conversación general |
any | No | Sí (cualquiera) | Sí | Forzar extracción |
tool + name | No | No (fija) | Sí si no existe | Schema específico |
none | Sí (siempre texto) | N/A | No | Análisis sin acción |
Modificador disable_parallel_tool_use
Además del modo, tool_choice admite disable_parallel_tool_use: true, que fuerza a Claude a emitir como máximo un bloque tool_use por turno:
const response = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
tool_choice: { type: "any", disable_parallel_tool_use: true },
tools: [extractContactTool, extractDateTool],
messages: [{ role: "user", content: emailText }],
});
Restricción de plataforma: en Amazon Bedrock con Sonnet 5, un
tool_choiceforzado (anyotool) requiere enviar ademásthinking: { type: "disabled" }.
Implementaciones
// AUTO: Claude decide si usar tools o responder en texto
const autoResponse = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
tool_choice: { type: "auto" }, // default, puede omitirse
tools: [searchTool, calculatorTool],
messages: [{ role: "user", content: "¿Cuánto es 2+2?" }],
// Claude puede responder "4" sin usar ninguna tool
});
// ANY: Claude DEBE usar al menos una tool
const anyResponse = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
tool_choice: { type: "any" },
tools: [extractContactTool, extractDateTool],
messages: [{ role: "user", content: emailText }],
// Claude elegirá al menos una de las tools disponibles
});
// TOOL específica: Claude DEBE usar exactamente esta tool
const toolResponse = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
tool_choice: { type: "tool", name: "extract_invoice_fields" },
tools: [extractInvoiceFieldsTool],
messages: [{ role: "user", content: invoiceText }],
// Claude usará extract_invoice_fields o error
});
// NONE: Deshabilita todos los tools aunque estén definidos
const noneResponse = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
tool_choice: { type: "none" },
tools: [deleteDatabaseTool], // definidas pero inaccesibles
messages: [{ role: "user", content: "Analiza los riesgos de este plan" }],
// Claude solo puede responder en texto — modo análisis puro
});
Errores comunes
- Usar
tool_choice: { type: "tool", name: "X" }con una tool que no está en la lista → error400 - Usar
anysin tools definidas → error400 - Asumir que
autosiempre llamará tools — puede responder en texto si considera que no necesita tools
5. Múltiples tool calls en un mismo turno
Claude puede emitir varios bloques tool_use en un solo turno. El desarrollador los ejecuta en paralelo y retorna todos los resultados en un único user message.
sequenceDiagram
participant Dev as Desarrollador
participant Claude
Dev->>Claude: User message con query
Claude-->>Dev: content: [tool_use(id=A), tool_use(id=B)]
Note over Dev: Ejecuta tool A y tool B en paralelo
Dev->>Claude: role:user, content: [tool_result(id=A), tool_result(id=B)]
Claude-->>Dev: Respuesta final con ambos resultados
Código completo
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
async function runWithParallelTools(userQuery: string) {
const response = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
tools: [weatherTool, stockPriceTool],
messages: [{ role: "user", content: userQuery }],
});
if (response.stop_reason !== "tool_use") {
return response.content[0];
}
// Recopilar todos los tool_use blocks
const toolUseBlocks = response.content.filter(
(b): b is Anthropic.ToolUseBlock => b.type === "tool_use"
);
// Ejecutar todas en paralelo
const results = await Promise.all(
toolUseBlocks.map(async (block) => {
const output = await dispatchTool(block.name, block.input);
return {
type: "tool_result" as const,
tool_use_id: block.id, // correlación crítica
content: JSON.stringify(output),
};
})
);
// Retornar todos los resultados en un único mensaje
const finalResponse = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
tools: [weatherTool, stockPriceTool],
messages: [
{ role: "user", content: userQuery },
{ role: "assistant", content: response.content },
{ role: "user", content: results }, // todos los resultados juntos
],
});
return finalResponse.content[0];
}
Clave para el examen: cada
tool_resultdebe tener eltool_use_idexacto del bloque correspondiente. Si los IDs no coinciden, la API retorna error400.
6. Streaming responses
Cuándo usar streaming vs buffering
| Situación | Modo recomendado |
|---|---|
| Interfaz de usuario en tiempo real | Streaming |
| CLI con feedback visual | Streaming |
| CI/CD, procesamiento batch | Buffering |
| Cuando necesitas el response completo antes de actuar | Buffering |
Streaming básico con tool_use
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
async function streamWithTools(query: string) {
const stream = await client.messages.stream({
model: "claude-sonnet-5",
max_tokens: 1024,
tools: [searchTool],
messages: [{ role: "user", content: query }],
});
let currentToolInput = "";
let currentToolId = "";
let currentToolName = "";
for await (const event of stream) {
switch (event.type) {
case "content_block_start":
if (event.content_block.type === "tool_use") {
currentToolId = event.content_block.id;
currentToolName = event.content_block.name;
currentToolInput = "";
}
break;
case "content_block_delta":
if (event.delta.type === "text_delta") {
process.stdout.write(event.delta.text); // mostrar al usuario en tiempo real
} else if (event.delta.type === "input_json_delta") {
currentToolInput += event.delta.partial_json; // acumular input de tool
}
break;
case "message_delta":
if (event.delta.stop_reason === "tool_use") {
const toolInput = JSON.parse(currentToolInput);
const result = await dispatchTool(currentToolName, toolInput);
// continuar el loop con el resultado...
}
break;
case "message_stop":
// stream completado
break;
}
}
const finalMessage = await stream.finalMessage();
return finalMessage;
}
Tipos de eventos clave
| Evento | Cuándo ocurre |
|---|---|
content_block_start | Inicio de un bloque (text o tool_use) |
content_block_delta | Fragmento de texto o JSON parcial |
content_block_stop | Fin del bloque actual |
message_delta | Cambio en metadata del mensaje (stop_reason) |
message_stop | Mensaje completado |
7. Vision API — inputs multimodales
Claude puede procesar imágenes junto con texto. Esto es útil en arquitecturas donde el input no es solo texto.
Árbol de decisión
flowchart TD
I[Input del usuario] --> T{¿Contiene imagen?}
T -->|No| P[Request text-only]
T -->|Sí| F{¿Tipo de imagen?}
F -->|"URL pública accesible"| U[image_url]
F -->|"Archivo local / privado"| B[base64]
B --> C{¿Tamaño?}
C -->|"< 5 MB"| OK[Enviar en base64]
C -->|"> 5 MB"| R[Redimensionar o comprimir primero]
Casos de uso en arquitecturas
- Screenshot de UI para debugging automatizado
- PDF o imagen de factura para extracción de campos
- Diagrama de arquitectura para análisis y documentación
- Captura de dashboard para generación de reportes
Implementación con base64
import Anthropic from "@anthropic-ai/sdk";
import { readFileSync } from "fs";
const client = new Anthropic();
async function analyzeScreenshot(imagePath: string, question: string) {
const imageData = readFileSync(imagePath);
const base64Image = imageData.toString("base64");
const response = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
messages: [
{
role: "user",
content: [
{
type: "image",
source: {
type: "base64",
media_type: "image/png", // image/jpeg, image/gif, image/webp
data: base64Image,
},
},
{
type: "text",
text: question,
},
],
},
],
});
return response.content[0];
}
// Uso
const result = await analyzeScreenshot(
"./screenshot.png",
"¿Qué errores aparecen en la consola?"
);
Implementación con URL
const response = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 512,
messages: [
{
role: "user",
content: [
{
type: "image",
source: {
type: "url",
url: "https://example.com/architecture-diagram.png",
},
},
{ type: "text", text: "Identifica los puntos de fallo único en este diagrama." },
],
},
],
});
Limitaciones y costo
- No puede procesar: video, audio nativo, archivos
.zip, ejecutables - Costo estimado por imagen: 1000–4000 tokens adicionales dependiendo del tamaño y detalle
- Formatos soportados: PNG, JPEG, GIF, WebP
- Tamaño máximo recomendado: 5 MB por imagen
8. Token counting y optimización de costos
countTokens antes de enviar
La API expone client.messages.countTokens() para calcular cuántos tokens usará un request antes de enviarlo. Esto es útil para:
- Verificar que el mensaje cabe en el context window
- Planificar el espacio disponible para tool results
- Evitar errores
max_tokensinesperados en producción
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
async function safeRequest(systemPrompt: string, userMessage: string) {
const MODEL = "claude-sonnet-5";
// Ventana nativa de 1M tokens en Opus 4.8, Sonnet 5 y Fable 5.
// Para claude-haiku-4-5 la ventana sigue siendo 200_000.
const CONTEXT_WINDOW = 1_000_000;
const OUTPUT_BUDGET = 4096;
// Contar tokens antes de enviar
const tokenCount = await client.messages.countTokens({
model: MODEL,
system: systemPrompt,
messages: [{ role: "user", content: userMessage }],
});
const availableForOutput = CONTEXT_WINDOW - tokenCount.input_tokens;
if (availableForOutput < OUTPUT_BUDGET) {
throw new Error(
`Contexto insuficiente: ${tokenCount.input_tokens} tokens de input, ` +
`solo quedan ${availableForOutput} para output`
);
}
return client.messages.create({
model: MODEL,
max_tokens: OUTPUT_BUDGET,
system: systemPrompt,
messages: [{ role: "user", content: userMessage }],
});
}
Estimación rápida de tokens
| Idioma | Regla aproximada |
|---|---|
| Inglés | ~4 caracteres = 1 token |
| Español | ~3.5 caracteres = 1 token |
| Código | ~3 caracteres = 1 token |
| JSON estructurado | ~2.5 caracteres = 1 token |
Modelos, context windows y costo (referencia aproximada)
| Modelo | Context window | Max output | Input (por 1M tokens) | Output (por 1M tokens) |
|---|---|---|---|---|
claude-opus-4-8 (default recomendado, cutoff enero 2026) | 1M | 128K | $5 | $25 |
claude-fable-5 (GA 9 jun 2026) | 1M | 128K | $10 | $50 |
claude-sonnet-5 | 1M | 128K | $3 | $15 |
claude-haiku-4-5 (pin claude-haiku-4-5-20251001) | 200K | 64K | $1 | $5 |
claude-sonnet-5tiene precio introductorio de $2/$10 hasta el 31 de agosto de 2026.
Opus 4.5 y Sonnet 4.5 son legacy;
claude-3-5-haikufue retirado el 19 de febrero de 2026 y devuelve404. Los precios cambian: consulta anthropic.com/pricing para valores actualizados.
Estrategia para agentic loops
La aritmética manual sigue sirviendo como control de cordura:
tokens_disponibles_para_tool_results =
context_window
- system_prompt_tokens
- historial_tokens
- output_tokens_estimados
- margen_de_seguridad (10%)
Pero hoy la API ofrece mecanismos de servidor que cubren exactamente ese problema y que conviene preferir sobre la aritmética a mano.
Task Budgets
Beta task-budgets-2026-03-13, disponible en Fable 5, Sonnet 5, Opus 4.8 y Opus 4.7. Es un presupuesto del que el modelo es consciente para todo el bucle agéntico, a diferencia de max_tokens, que es un tope duro por respuesta e invisible al modelo. Mínimo 20.000 tokens. Conviene usarlo con streaming.
const response = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 8192,
output_config: {
effort: "xhigh",
task_budget: { type: "tokens", total: 200_000 },
},
tools: [searchTool, editTool],
messages: [{ role: "user", content: "Migra el módulo de pagos…" }],
}, { headers: { "anthropic-beta": "task-budgets-2026-03-13" } });
Compaction — resumir el historial en servidor
Beta compact-2026-01-12, en Fable 5, Opus 4.8/4.7/4.6, Sonnet 5 y Sonnet 4.6. El servidor resume el historial automáticamente al acercarse al límite.
const response = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 4096,
context_management: { edits: [{ type: "compact_20260112" }] },
messages: conversation,
}, { headers: { "anthropic-beta": "compact-2026-01-12" } });
Hay que reenviar
response.contentcompleto al siguiente turno, no solo el texto.
Context editing — borrar en vez de resumir
Beta context-management-2025-06-27, con los tipos clear_tool_uses_20250919 y clear_thinking_20251015. Borra pares tool_use/tool_result antiguos en lugar de resumirlos.
const response = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 4096,
context_management: {
edits: [
{
type: "clear_tool_uses_20250919",
trigger: { type: "input_tokens", value: 100_000 }, // default 100.000
keep: { type: "tool_uses", value: 3 }, // default 3 pares recientes
exclude_tools: ["memory"],
},
],
},
messages: conversation,
}, { headers: { "anthropic-beta": "context-management-2025-06-27" } });
Se recomienda combinarlo con la memory tool (memory_20250818): Claude recibe aviso antes del borrado y guarda lo importante en archivos persistentes.
No confundir ambos mecanismos: usar
compact_20260112bajo la cabecera decontext-managementda error. Compaction tiene su propia cabecera beta.
Si aun así tokens_disponibles_para_tool_results es negativo, quedan las medidas clásicas:
- Comprimir el historial (summarization o compaction)
- Reducir el system prompt
- Paginar los tool results en lugar de incluirlos todos
Resumen del capítulo
| Concepto | Clave para el examen |
|---|---|
| Thinking | thinking: { type: "adaptive" }; budget_tokens devuelve 400 salvo en Haiku 4.5 |
Bloques thinking | display: "omitted" por defecto (llegan vacíos); pedir display: "summarized" para verlos |
| Esfuerzo | output_config: { effort: … } — GA, sin beta; low|medium|high|xhigh|max; xhigh para coding y agentes |
| Sampling | temperature, top_p y top_k eliminados en los modelos vigentes (400); se dirige por prompting |
| Structured outputs | output_config.format = { type: "json_schema", schema: {…} }; strict: true top-level en la tool |
| Prefill assistant | Eliminado (400) en Fable 5, Opus 4.6/4.7/4.8 y Sonnet 4.6/5 |
| IDs de modelo | Sin sufijo de fecha desde la generación 4.6, pero siguen siendo snapshots pinneados |
| Prompt Caching | cache_control: { type: "ephemeral" } en el último bloque estático |
tool_choice: auto | Claude decide; puede no usar tools |
tool_choice: any | Claude DEBE usar al menos una tool |
tool_choice: tool | Claude DEBE usar exactamente esa tool |
tool_choice: none | Deshabilita tools aunque estén definidas |
disable_parallel_tool_use | Modificador de tool_choice: máximo un tool_use por turno |
| Bedrock + Sonnet 5 | Un tool_choice forzado exige enviar además thinking: { type: "disabled" } |
| Parallel tool calls | Un user message con todos los tool_result usando el tool_use_id correcto |
| Streaming | Acumular input_json_delta para tool inputs; texto en tiempo real |
| Vision | base64 o URL; sin video/audio; ~1000–4000 tokens por imagen |
| Token counting | client.messages.countTokens() antes de enviar; ventana de 1M en Opus 4.8, Sonnet 5 y Fable 5 |
| Presupuesto agéntico | Task Budgets (output_config.task_budget, mínimo 20.000 tokens) frente a max_tokens |
| Gestión de contexto | Compaction (compact_20260112) resume; context editing (clear_tool_uses_20250919) borra. Cabeceras beta distintas |
Siguiente: Preguntas de Práctica