Agent Mentor Learn
Gestión de estado y persistencia: que las tareas largas sobrevivan a una interrupción · Lección 2 de 6

Lección 2: Puntos de control: escribir la escena de ejecución en disco

Objetivos de aprendizaje:

  • Nombrar los seis campos que corresponden a checkpoint.json y, para cada uno, decir con qué se topa la reanudación cuando falta
  • Distinguir los dos puntos de guardado dentro de un mismo turno del bucle (después de que el modelo nombra una herramienta, después de que el resultado de la herramienta queda registrado) y explicar a qué te expone escribir solo uno de ellos
  • Escribir un saveCheckpoint que no pueda corromper el propio archivo de punto de control: escribir un archivo temporal y después renombrar de forma atómica, en vez de sobrescribir en el lugar

Requisitos: Leíste la Lección 1 y sabes distinguir memoria de estado de ejecución; te manejas con el arreglo messages y el esqueleto de bucle guiado por stop_reason de «Fundamentos del arnés de agente: bucles y control» | Anterior: Lección 1 << | Siguiente: Lección 3 >>

La escena de ejecución vive en memoria por omisión

La Lección 1 separó memoria y estado de ejecución: la memoria es lo que le das al modelo, el estado de ejecución es la escena en curso que sostiene el propio arnés, el arreglo messages, el contador de turnos, la llamada a herramienta cuyo resultado todavía no quedó registrado. Por omisión esa escena existe solo en la memoria del proceso. Cuando el proceso muere se va con él, y aun con todos los demás archivos intactos en disco, la tarea solo puede arrancar de nuevo desde cero.

Escribir esa escena en disco, convertirla en algo que un proceso reiniciado pueda leer de vuelta, es lo que es un punto de control. Lo que sostiene de verdad la confiabilidad de las tareas largas en la práctica no suele ser pedirle al modelo que absorba cada falla por su cuenta; es combinar "the adaptability of AI agents built on Claude with deterministic safeguards like retry logic and regular checkpoints"1 (la adaptabilidad de los agentes de IA construidos sobre Claude con salvaguardas deterministas como lógica de reintento y puntos de control regulares). Esta lección cubre la mitad del punto de control: qué corresponde poner en uno, en qué lugar del bucle escribirlo y cómo realizar la escritura misma, porque un punto de control mal escrito puede dejarte peor que no tener ninguno.

Qué guardar: los seis campos de checkpoint.json

Un punto de control no es «volcar a un archivo todo lo que hay en memoria». Es «registrar lo que necesita la reanudación del bucle, ni más ni menos». Todas las lecciones posteriores de este curso funcionan con el mismo protocolo:

  • version: el número de versión del protocolo. Este formato va a cambiar en algún momento (compresión para messages, una forma nueva para pendingToolUse), y version le permite a la ruta de reanudación preguntar «¿reconozco este punto de control?» antes que nada; ante una versión que no conoce, habría que negarse a cargar y fallar ruidosamente en vez de apretar los dientes y seguir parseando.
  • task: la tarea original del usuario, en palabras. Tras un reinicio, el código del arnés no recuerda qué estaba haciendo; todo lo que puede leer es este archivo en disco. Sin task, el arnés no puede ni decir a qué tarea pertenece el punto de control, mucho menos reportarle al usuario el progreso de la reanudación.
  • turns: cuántos turnos se ejecutaron ya. Es lo que decide si se disparan las condiciones de parada de «Fundamentos del arnés de agente: bucles y control» (un tope máximo de turnos, digamos), y es el número desde el que la reanudación sigue contando en lugar de arrancar de cero.
  • tokensUsed: el gasto acumulado de tokens. El umbral de compactación de «Ingeniería de contexto: gastar una atención finita donde más rinde» se dispara a partir de este número. Déjalo afuera del punto de control y la reanudación o bien finge que la cuenta arranca en cero —dejando desfasada cada decisión de compactación— o bien tiene que volver a estimar el consumo de cada mensaje de messages, y en la mayoría de las configuraciones las cifras históricas de consumo sencillamente ya no están disponibles.
  • messages: la escena de conversación entera, cada mensaje user / assistant / tool_result que el modelo vio. Es lo más grande del punto de control y lo único que no puedes saltear: el modelo no tiene memoria propia, y todo lo que sabe sobre lo que pasó antes es este arreglo que le pasas en la solicitud siguiente. Elimínalo y lo que reanudas no es «seguir adelante»: es una tarea nueva que arranca de cero mientras arrastra cada efecto secundario que la ejecución vieja ya produjo.
  • pendingToolUse: o bien null, o bien un registro con forma { id, name, input }, una herramienta que el modelo nombró y cuyo resultado todavía no está registrado. Qué hacer con este campo es asunto de la Lección 3, donde la reanudación concilia contra él; aquí solo necesitas saber que es la ranura designada del punto de control para marcar un estado a medio terminar. Para mantener su forma simple, todos los ejemplos de esta lección suponen un bloque tool_use por turno; cuando un turno emite varias llamadas concurrentes a herramientas, conviértelo en un arreglo, que el razonamiento es el mismo.

Cuándo guardar: dos puntos de guardado por turno

Mete esos campos en el bucle y resulta que el momento no es tan simple como «escribir una vez al final de cada turno». Hay dos puntos de guardado:

El punto A va después de que llega la respuesta del modelo y antes de que la herramienta se ejecute: registra el bloque tool_use de la respuesta en pendingToolUse y después escribe. El punto B va después de que el resultado de la herramienta se agregó a messages: devuelve pendingToolUse a null y escribe de nuevo.

¿Alcanza con B solo? La exposición es la ventana entre A y B: el modelo nombró una herramienta y la herramienta se está ejecutando, o terminó pero su resultado no llegó a messages ni se escribió en disco. Si el proceso muere en esa ventana, el último punto de control en disco sigue siendo el que escribió B en el turno anterior, y no sabe nada de la llamada de este turno: no es que se haya perdido algún detalle, es que esta llamada a herramienta no dejó rastro alguno en disco. La Lección 3 concilia al reanudar —si esa herramienta terminó de verdad, si hace falta volver a ejecutarla— y contra lo que concilia es precisamente el pendingToolUse que escribió A. Esta lección solo cava el pozo; los ejercicios de la lección 6 te ponen delante un punto de control de solo B y te hacen diagnosticar qué sale mal al reanudar.

Cómo guardar: no puedes sobrescribir en el lugar

El enfoque obvio es hacer JSON.stringify del objeto state y fs.writeFileSync directo encima del viejo checkpoint.json. Eso está bien cuando el proceso termina normalmente, pero «termina normalmente» es exactamente el caso para el que los puntos de control no son. Los puntos de control existen para que maten el proceso en cualquier momento, para el corte de corriente, para que el contenedor sea desalojado. Escribir un archivo no es una operación atómica. Si el proceso se interrumpe a mitad de la escritura, el checkpoint.json que queda en disco puede estar a medio escribir: ni la versión vieja, ni la nueva, solo JSON truncado. La reanudación siguiente lanza una excepción en JSON.parse, y ese archivo era la única copia de la escena de la tarea: no hay ninguna versión más vieja a la que recurrir.

La jugada es «escribir un archivo temporal y después renombrar de forma atómica». Escribe el contenido completo en checkpoint.json.tmp; si te caes a mitad de ese paso, la única baja es el archivo temporal, y el checkpoint.json de verdad sigue siendo la versión más vieja e intacta de antes de la caída, que la reanudación lee sin problema. Una vez que el archivo .tmp está completo, hazle fs.renameSync sobre el nombre real. En el mismo sistema de archivos, rename es un reemplazo atómico de un solo paso: el sistema operativo o bien apunta la entrada de directorio al archivo nuevo por completo, o bien la deja apuntando al viejo. No hay ningún estado intermedio a medio renombrar.

Referencia de producto: cómo se ve un punto de control en Claude Code

El protocolo que enseña esta lección es para tareas largas desatendidas, con una granularidad de dos puntos de guardado por turno del bucle. Para contrastar, mira dónde pone la palabra «checkpoint» un producto real, Claude Code: "checkpointing automatically captures the state of your code before each user prompt."2 (los puntos de control capturan automáticamente el estado de tu código antes de cada prompt del usuario). "Every user prompt creates a new checkpoint"2 (cada prompt del usuario crea un punto de control nuevo), y "Claude Code saves checkpoints with the conversation, so you can still run /rewind after you resume a session"2 (Claude Code guarda los puntos de control junto con la conversación, así que puedes ejecutar /rewind incluso después de reanudar una sesión).

El escenario al que sirve no es este. Los puntos de control de Claude Code están hechos para una sesión con una persona en el circuito: el usuario puede frenar todo en cualquier momento, probar un enfoque, decidir volver a antes de cierto mensaje y darle otra pasada, así que la unidad natural es «el usuario dijo algo». Lo que estás construyendo aquí es para tareas largas desatendidas: nadie está de guardia para dar el alto, la unidad es «el bucle dio una vuelta», y dentro de un mismo turno se parte otra vez en los puntos de guardado A y B, porque una caída puede producirse entre «el modelo nombró una herramienta» y «el resultado quedó registrado». Los dos no resuelven el mismo problema. Ponerlos uno al lado del otro sirve sobre todo para dejar una cosa clara: cuán fino cortar un punto de control, y cada cuánto escribir uno, depende de a qué sirve el punto de control. No hay una sola respuesta.

Los puntos de control no son gratis

Los puntos de control cuestan algo. Bajo el protocolo de esta lección, un turno del bucle escribe en disco dos veces. Para una tarea corta que termina en tres o cinco turnos, eso es puro sobrecosto: el proceso se ejecuta hasta el final y esos archivos de punto de control nunca se leen. Si conviene meter esta maquinaria en tu propio arnés es algo que vale la pena medir contra la regla de que "you should consider adding complexity only when it demonstrably improves outcomes."3 (habría que considerar agregar complejidad solo cuando mejora los resultados de forma demostrable). Cuanto más larga la tarea y más alto el costo de una caída, mejor se pone ese canje; para algo que termina en unos segundos, probablemente no lo necesites.

💻 Ejercicios

Resumen

  • La escena de ejecución vive en memoria por omisión y muere con el proceso. Los puntos de control existen para ahorrarle a una tarea larga volver a ejecutarse desde cero tras cada caída, y así poder retomar donde se rompió1
  • checkpoint.json sostiene seis campos: version, task, turns, tokensUsed, messages, pendingToolUse. messages es la pieza más grande, y sin él el modelo no tiene nada sobre lo que pasó antes; pendingToolUse es la marca de llamada colgante contra la que concilia la Lección 3
  • Un turno del bucle tiene dos puntos de guardado: A después de que el modelo nombra una herramienta y antes de que la herramienta se ejecute, B después de que el resultado de la herramienta queda totalmente registrado en messages. Guardar solo en B deja un punto ciego en toda la ventana en la que el modelo nombró una herramienta que no terminó
  • Sobrescribir el archivo de punto de control en el lugar no es seguro. Al proceso lo pueden matar en cualquier momento, y una caída a mitad de la escritura convierte la única copia de la escena en medio documento JSON. Escribe primero un archivo .tmp y ponlo en su lugar con fs.renameSync: eso es lo que garantiza que lo que hay en disco en cualquier instante sea una versión completa
  • Los puntos de control de Claude Code trabajan con otra granularidad —capturados automáticamente antes de cada prompt del usuario2—, al servicio de una sesión con una persona en el circuito. Lo que construye esta lección es para tareas largas desatendidas. Los puntos de corte difieren, pero ambos responden a la misma pregunta: cuando algo sale mal, ¿a dónde vuelves?
  • Los puntos de control no son gratis. Dos escrituras a disco por turno son puro sobrecosto en una tarea corta, y si vale la pena agregarlos se reduce a si mejora el resultado de forma demostrable, no a suponer que más es mejor3

>> Lección 3: Reanudar desde un punto de control: reiniciar el bucle

Footnotes

  1. How we built our multi-agent research system — Anthropic Engineering — https://www.anthropic.com/engineering/multi-agent-research-system 2

  2. Checkpointing — Claude Code Docs — https://code.claude.com/docs/en/checkpointing 2 3 4

  3. Building Effective AI Agents — Anthropic Engineering — https://www.anthropic.com/engineering/building-effective-agents 2

Ejercicios

01

Alguien escribió saveCheckpoint así:

Nivel 1: Completar un punto de control incompleto

Frente al protocolo que planteó esta lección, ¿qué campos le faltan todavía a este punto de control? Para cada campo faltante, di específicamente: si intentaras reanudar desde este punto de control incompleto, ¿dónde exactamente se caería?

Criterios de finalización · marcado local
02

Un colega escribió el runAgent de abajo para ejecutar una tarea que llama herramientas dos veces seguidas. Se ve bien en el día a día, pero apenas matan el proceso a mitad de la ejecución, la escena que recuperas o no abre o no cuadra. Encuentra los dos puntos que ceden ante una caída, di a qué lleva cada uno y corrígelos: el código corregido tiene que ejecutarse de verdad.

Nivel 2: Dos fallas latentes, corregidas
Criterios de finalización · marcado local