DEV M2 · Production-Grade Prompting, Agents & Tool Use — Resumen de estudio
Curso 2 de 5 · 29 pantallas, 10 secciones, 9 checkpoints, ~209 min
"Escribir código que usa Claude es distinto de usar Claude para escribir código." Cada tema corresponde a un fallo que no aparece en desarrollo y cuesta caro en producción.
1. Prompting craft: diagnostica antes de re-promptear
El tipo de fallo indica qué técnica falta:
| Observas | Falta | Por qué funciona |
|---|---|---|
| Forma incorrecta (frase en vez de etiqueta, prosa en vez de JSON) | Output constraint | Controla la forma independientemente del contenido |
| El contenido deriva, cambia el tono o el alcance crece con los turnos | System prompt (más específico) | Contrato de comportamiento que se mantiene en cada turno |
| Entiende la tarea pero inventa la estructura | Few-shot examples | Muestra el patrón en vez de describirlo |
| Funciona en lo probado y falla en una variante | Constraint (o ejemplo) que cubra esa variante | Cierra el hueco que tus pruebas no expusieron |
Las 4 técnicas:
- System prompt: contrato persistente de rol, formato y reglas.
- XML tags: separan instrucciones de datos (
<my_code>,<docs>). Los nombres pueden ser descriptivos, no hay etiquetas oficiales. - Few-shot: pares
<sample_input>/<ideal_output>. Puedes sacarlos de tus outputs con mejor puntaje en los evals. - Output constraints: nombres de campos, tipos, longitud, si va preámbulo o no, qué hacer si falta un dato.
Regla: nombra el fallo → añade una técnica → vuelve a correr. Si el prompt crece en cada pasada, te estás saltando el diagnóstico. Tras 3 re-prompts fallidos, para y diagnostica.
⚠️ Watch out (6 pasadas): cada versión fue más larga y ninguna añadió el output constraint. En la pasada 5 el prompt verboso producía >2,000 caracteres por llamada (el modelo calibra la longitud de su respuesta según el input) y subió la latencia sin ganar precisión. El arreglo fue un JSON schema + 2 ejemplos →
{"category": "billing"}siempre.
Structured outputs (control desde la API, no desde el prompt)
- Constrained decoding: la API solo permite tokens que mantienen la salida válida contra tu schema.
- JSON outputs:
output_config.formatcontype: json_schema. La respuesta final es JSON válido siempre. - Strict tool use:
strict: trueen la tool. Los argumentos se validan contra elinput_schemaantes de que corra tu código.
Costos y límites:
- La primera llamada con un schema nuevo es más lenta (se compila una gramática que se cachea 24 h desde el último uso).
- Más tokens de input (la API inyecta un system prompt sobre el formato).
- Schema garantizado ≠ éxito garantizado: un
refusalomax_tokenspuede cortar la estructura. Revisa siemprestop_reason. - No se combina con prefilling del mensaje del asistente.
Checkpoint 1 (prompt de extracción): el defecto era la falta de output constraint. Fix: devolver solo un JSON con category (billing|technical|escalation), urgency (low|medium|high|critical) y summary (una oración), sin otro texto.
2. Extended thinking
- El razonamiento llega en un thinking block antes de la respuesta. En los modelos más nuevos su contenido se omite por defecto; usa el display resumido para verlo.
- Adaptive: se activa con el parámetro
thinkingy la profundidad se ajusta con effort.budget_tokensestá deprecado (en los más nuevos da 400). - Los thinking tokens cuestan como output.
| Tarea | Decisión |
|---|---|
| Razonamiento de varios pasos (matemáticas, lógica multi-hop, planear acciones dependientes) | Activarlo, con el effort acorde |
| Clasificación, conversión de formato, extracción, respuestas cortas | Apagado |
| Loops agentic que planean varias tool calls | Activarlo y presupuestar el paso de planeación |
Regla de carry-back: en loops con tools, cada thinking block (y cada redacted thinking block) se devuelve a la API sin cambios. Lleva una firma: si lo editas, resumes o quitas, la API rechaza el request. ¿Te preocupa el contexto acumulado? Usa context engineering, no edites bloques.
Checkpoint 2:
- 50k tickets → apagado.
- Refactor con pasos dependientes → activarlo y presupuestar la planeación.
- Quitar el thinking block para ahorrar contexto → nunca.
3. Tool use y diseño de schemas
El loop (Claude NO ejecuta las tools):
- Defines el schema.
- Envías el mensaje con las tools.
- Claude responde con un bloque
tool_use(nombre, id, input) ystop_reason: tool_use. - Tu código ejecuta la tool. El modelo no tiene estado: haces un request nuevo con el historial + el resultado.
- Devuelves un
tool_resultcon el mismo id. - Claude continúa (otra tool o
end_turn).
Bloques:
- text: si viene junto a un
tool_use, conserva el array de contenido completo en el historial. - tool_use: debe responderse con un
tool_resulten el turno de usuario inmediatamente siguiente, con el mismo id. - tool_result: va en el rol user.
tool_use_idexacto;is_error: trueopcional si la tool falló. El emparejamiento es por id, no por posición. - thinking: se devuelve sin cambios.
Anatomía del schema:
- name: específico (
get_account_balance>get_data). - description: lo que decide la selección. Escríbela en dos partes: cuándo usarla y cuándo NO.
- input_schema: JSON Schema.
| Decisión | Cómo |
|---|---|
| Dependencia entre subtareas | Si una depende de otra → turnos separados. Si son independientes → Claude emite varios tool_use en un turno (los modelos actuales paralelizan por defecto). disable_parallel_tool_use fuerza una por turno |
| Campos required | Solo si la llamada no tiene sentido sin ellos (si marcas todo como required, Claude inventa valores) |
| Campos opcionales | Con defaults; la ausencia también comunica algo |
| Longitud de la descripción | 3–4 oraciones: qué hace, cuándo usarla, qué devuelve, ejemplos si el formato importa |
| Parámetros que se solapan | Lenguaje que distinga el dominio o el trigger. Si nada logra separarlas → fusiónalas en una tool con un parámetro type |
- Las exclusiones dependen del historial completo: si truncas turnos, la lógica de exclusión falla en silencio.
MCP como alternativa a escribir schemas
- El servidor MCP ya trae las tools (p. ej. GitHub). Tu cliente manda
ListToolsRequesty le pasa las definiciones a Claude. El loop es el mismo. - Las definiciones ocupan contexto aunque no se usen. Conecta solo lo necesario.
- API MCP Connector:
mcp_toolsetcondefault_configyconfigspor tool.defer_loading(carga diferida) yenabled(activar o desactivar tools). Requiere el header betamcp-client-2025-11-20. - Transportes: stdio (local, subproceso) y Streamable HTTP (remoto; SSE-only está deprecado). El Connector de la API solo admite servidores remotos HTTP. Los stdio requieren Claude Desktop o Claude Code, o gestionar tú el cliente con el SDK.
- MCP si hay un servidor mantenido que cubre lo que necesitas · schemas manuales si necesitas control fino · ambos: MCP para cobertura + allowlist + afinar las descripciones de las tools que más usas.
⚠️ Watch out:
search_docs("find information about the product") yget_context_summary("retrieve relevant information from the session") son lo mismo para Claude. Fix: una oración de "cuándo NO" en ambas.
Checkpoint 3: B. El tool_result usa toolu_02 y el tool_use era toolu_01; hay que corregir el id. El fallo está después de elegir bien la tool, así que no es la descripción ni el required.
4. Streaming
| Evento | Qué hace tu handler |
|---|---|
message_start | Prepara un array de contenido vacío |
content_block_start | Abre un slot en ese índice (tipo text, tool_use o thinking; el tool_use trae nombre e id, todavía sin input) |
content_block_delta | Añade el fragmento. El input de la tool llega como JSON parcial: no lo parsees todavía |
content_block_stop | Cierra el bloque. Primer momento en que el JSON del tool_use es parseable |
message_delta | Registra stop_reason y el uso final |
message_stop | Mensaje completo; trátalo como una respuesta no-stream |
Reglas:
- No actúes sobre un bloque parcial.
- Añade el turno al historial solo después de
message_stop. - Si el stream se corta: descarta el turno parcial y reintenta desde el último turno completo.
- Revisa
stop_reason: si estool_use, ejecuta las tools; cualquier otro valor es otro camino. - Para respuestas cortas o backend sin nadie esperando → no uses streaming.
⚠️ Watch out: "el read loop terminó" no equivale a "el mensaje está completo". Un corte de red guardó un
tool_usecon JSON truncado y el error apareció en el reintento. Si ves un error de tool use en un retry, revisa si el turno anterior vino de un stream.
Checkpoint 4 (fix): if stop_seen: messages.append(...); si no, raise StreamInterruptedError (descartar y reintentar).
5. Context engineering
- Modelo: empieza con Sonnet y muévete solo con evals (Fable > Opus > Sonnet > Haiku).
- Cada resultado de tool se queda en el contexto el resto de la sesión. En producción los outputs de tools son 3–5× más largos que los fixtures, así que la ventana se llena en el turno 8 y no en el 50.
- No hay truncado silencioso: es error 400 (input demasiado grande) o
model_context_window_exceeded(techo durante la generación).
| Estrategia | Qué hace | Cuándo | Qué pierdes |
|---|---|---|---|
| Pruning (rewind) | Vuelve a un mensaje anterior y descarta lo posterior | Tras un camino improductivo o mucho debugging | Lo aprendido en ese tramo |
Compaction (/compact; server-side en la API, en beta; o un resumen manual) | Resume el historial | Cerca del techo, misma tarea | Detalles que el resumen omita |
Clearing (/clear; sesión nueva) | Contexto vacío | Tarea totalmente distinta | Todo (lo persistente va en CLAUDE.md) |
| Subagent handoff | Contexto aislado y solo devuelve un resumen | Subtarea autocontenida, exploración | Los pasos intermedios |
- Prompt caching:
cache_control: {type: "ephemeral"}en el último bloque a cachear, hasta 4 breakpoints. Úsalo en system prompts largos, sets de tools y documentos de referencia. - Token counting: el endpoint
count_tokens(mismo body, sin inferencia) mide la presión de contexto antes de enviar. - Compaction manual: el prompt del resumen decide qué sobrevive. "Resume la conversación" pierde estado crítico; pide explícitamente archivos modificados, decisiones y errores con su resolución.
- RAG, 3 puntos de falla: chunking (por oración o sección, con overlap), embedding match (semántico; a veces hace falta lexical para identificadores exactos) y ensamblado en el prompt.
- Índice: corpus estable y consultas simples.
- Búsqueda iterativa agentic: corpus cambiante o preguntas de varios pasos (más tokens, pero sin índice que mantener).
⚠️ Watch out: presupuesto de 40k tokens fijado por el equipo. Los tool outputs pasaron de ~800 a ~3,200 tokens y el tope llegó en el turno 8: elegía tools equivocadas. Un desbordamiento de contexto parece un fallo de selección de tools. Mide con los inputs más grandes antes de lanzar; poda y compacta de forma proactiva.
Checkpoint 5: B. Podar los resultados de fetch_policy_document y compactar antes del turno 5 (los turnos 1–4 correctos descartan un problema de schema; max_tokens controla la salida, no la lectura).
6. Construcción de agentes
- Workflow si puedes enumerar los pasos en código, el error tiene costo real, necesitas observabilidad estándar, los inputs son acotados y la secuencia es fija.
- Agent si puedes definir el objetivo y las tools pero no el camino, los inputs varían impredeciblemente y la no-determinación es aceptable.
- Progresión: una llamada → workflow → agent. Sube solo cuando lo simple no alcance.
3 caminos para cablearlo (el patrón es el mismo):
| Camino | Quién corre el loop | Ojo con |
|---|---|---|
| Raw Messages API loop | Tu código, todo | Mantienes contexto, paralelismo, retries y salida |
| Agent SDK | El SDK, en tu proceso (tú ejecutas las tools) | Define settingSources explícitamente (p. ej. ["user","project","local"] como el CLI, o [] aislado); de eso depende que carguen CLAUDE.md y Skills |
Claude Managed Agents (beta pública, header managed-agents-2026-04-01) | Anthropic (loop + sandbox); tú envías eventos y recibes SSE | Sesiones con estado guardadas en el servidor → no elegibles para ZDR ni para BAA de HIPAA |
- Managed Agents conviene para tareas largas (minutos u horas), un sandbox gestionado o no querer construir el loop. El agente es un recurso de API versionado. De Agent SDK a Managed hay que re-expresar la definición; no hay exportación directa.
4 pasos del loop:
- Registrar tools.
- System prompt acotado a la tarea.
- Manejar el loop de tool use (todos los
tool_usede un turno se resuelven juntos). - Exit conditions explícitas, que no dependan de que Claude decida parar.
Checklist: tools registradas · prompt acotado · loop implementado · punto de HITL definido · salida definida.
HITL:
- Antes de una tool destructiva (write, delete, send): riesgo alto, irreversible.
- Después de planear: riesgo medio, un plan equivocado.
- Ante un output inesperado (error, vacío, fuera de rango): riesgo variable.
Over-tooling (lo más común; la selección empeora al crecer el set de tools) vs under-tooling. Empieza con el mínimo.
Restricciones reguladas (definen endpoint, credenciales y logs antes del diseño):
- Privilege: API/SDK dentro de la app de la firma, SSO, gateway con logs (el contenido de la conversación no lo captura Anthropic por defecto; lo registras tú).
- HIPAA: configuración cubierta por BAA (organización HIPAA dedicada) o Bedrock/Vertex. El BAA no cubre Console, Workbench, features beta ni planes consumer.
- GDPR: Bedrock/Vertex con región fijada en el cliente. La API directa no ofrece residencia en la UE. Usar el endpoint global por defecto rompe la residencia.
- FedRAMP: Claude for Government (High, vía Palantir FedStart), Bedrock GovCloud (High, IL4/5), Vertex Assured Workloads. Claude Enterprise en AWS Marketplace no es FedRAMP. Cuidado con los paths de dev/test que apuntan al endpoint comercial.
- Política interna: el cliente SDK del proveedor aprobado por el CIO.
⚠️ Watch out: un agente de configs bajó un rate limit "válido" según
validate_configy la app del cliente se cayó. Faltaba el estado "cambio propuesto" antes de "write confirmado". Pregunta en el diseño: ¿qué es lo peor siwrite_filecorre sin un humano?
Checkpoint 6 (respuesta modelo):
- Descripción de
update_record: "Úsala para actualizar un campo específico de un registro. Solo después de queread_recordconfirmó el valor actual y el cambio fue revisado. No la uses para actualizaciones masivas ni cambios de schema." - HITL: dentro del loop, si
block.name == "update_record", mostrar el cambio y pediryes/no. Si se rechaza →tool_result"Update rejected by operator." ycontinue. Antes deexecute_tool(no basta con una aprobación al inicio, y aprobar después es inútil).
7. Memoria del agente
| Alcance | Qué persiste | Costo | Cuándo | Qué pierdes |
|---|---|---|---|---|
| In-context | Solo dentro de la sesión | Los tokens crecen con cada turno | Sesiones cortas | Todo al terminar |
| External storage | Base de datos, se lee al iniciar | Latencia + lógica de lectura y escritura | Continuidad entre sesiones, usuarios o instancias | Nada (pagas latencia y complejidad) |
| Summarized | Resumen inyectado al inicio | Menos tokens | Agentes conversacionales largos | Lo que el resumen no guardó |
| Stateless | Nada | Cero | Jobs independientes | Todo el contexto previo |
- Decídelo en el diseño (unos 20 minutos) y no como refactor bajo presión en producción.
- Skills (SKILL.md): frontmatter (name + description) + instrucciones. Solo el nombre y la descripción se cargan al inicio; el contenido completo, cuando el request coincide.
- CLAUDE.md se carga siempre en el CLI (en el Agent SDK depende de
settingSources). - Skills en la Messages API: beta, headers
code-execution-2025-08-25+skills-2025-10-02; corren en el contenedor de code execution. - Los subagents NO heredan Skills ni historial (sí heredan el contexto de permisos). Lista los Skills explícitamente en el subagent.
- CLAUDE.md se carga siempre en el CLI (en el Agent SDK depende de
⚠️ Watch out: en la sesión 4 el historial in-context superaba 40k tokens antes de la primera tool call. Desarrollo = una sesión larga; producción = muchas cortas acumuladas.
Checkpoint 7: soporte por 2 semanas = external storage · formateador independiente = stateless · asistente de código de horas sin continuidad = in-context.
8. Tarea acumulativa de debug (4 bugs, 4 capas)
- Schema: descripción
"Gets data."→ Claude no la distingue. Fix: intención + exclusión ("…por customer ID. No usar para historial de pedidos"). - Streaming: commit antes de
message_stopy se quita el thinking block → turno parcial y firma rota. Fix: conservar todos los bloques,if stop_seen→ append; si no, raise. - Contexto: solo se añade el
tool_result, sin el turno del asistente con eltool_use. Fix: se resuelve al arreglar el 2 (el turno completo se añade antes). - Memoria: se concatenan todas las transcripciones previas en contexto. Fix: external storage + inyectar solo un resumen al inicio.
9. Multimodal y batch
- Costo de imagen: ⌈ancho/28⌉ × ⌈alto/28⌉ tokens visuales (1000×1000 ≈ 1,296). Cada tier tiene su límite de resolución; lo que lo excede se reduce. Calcula con el input más grande de producción.
| Envío | Cuándo |
|---|---|
| Inline base64 | Imagen de un solo uso |
| URL | Ya hospedada, pública y estable (nada con auth ni URLs firmadas que expiran) |
| Files API (beta; no disponible en Bedrock ni Vertex) | Se reutiliza entre requests o turnos, o es grande. Subes una vez y usas el file_id |
- PDF: bloque
type: "document"(base64, URL o file_id).titleycontextson opcionales. - Prompts visuales: indica cómo manejar la ambigüedad ("si los objetos se superponen, descríbelos por separado").
- Message Batches API: hasta 100,000 requests o 256 MB. Envías, recibes un
batch_id, haces polling y descargas. Menor costo por token, hasta 24 h. Los resultados llegan en cualquier orden → usacustom_id.
⚠️ Watch out: "dividí la lista en chunks y hago un loop" no es batching: son las mismas llamadas síncronas y los mismos rate limits.
Checkpoint 8: diagrama en cada request = Files API · captura de un solo uso = inline base64 · 5,000 respuestas = Batches API.
Para recordar (8 takeaways)
- El tipo de fallo indica la técnica que falta. Si el prompt no alcanza, usa structured outputs.
- Razonamiento solo donde cambia la respuesta; los thinking blocks vuelven sin cambios.
- Que un stream termine no significa que el mensaje esté completo.
- Una tool equivocada casi siempre se debe a la descripción (añade la cláusula de exclusión). Con MCP, controla el costo de contexto.
- El contexto es un presupuesto fijo; los outputs de tools lo gastan más rápido que nada.
- Workflow vs agent decide el costo; el HITL va en el diseño.
- La memoria depende de la forma de la sesión. Los Skills llevan instrucciones bajo demanda.
- Calcula el costo multimodal antes; un loop síncrono no es batch.