Cap 1: Agentic Loops y el Ciclo tool_use

Por: Artiko
claudeagentictool-useapiloops

Agentic Loops y el Ciclo tool_use

Un agentic loop es el patrón fundamental para construir agentes con Claude. El modelo no solo genera texto: inspecciona resultados, decide qué herramientas usar y repite hasta completar la tarea.


El lifecycle del agentic loop

El flujo básico tiene 4 fases que se repiten:

1. Enviar request a la API (messages + tools disponibles)
2. Inspeccionar stop_reason de la respuesta
3. Si stop_reason === "tool_use" → ejecutar tools → agregar results → volver a 1
4. Si stop_reason === "end_turn" → el agente terminó, entregar respuesta

La clave es que el modelo decide cuándo ha terminado. No es el desarrollador quien programa condiciones de salida — es Claude quien evalúa si la tarea está completa.

stop_reason: la señal de control

stop_reasonSignificadoAcción
"tool_use"Claude quiere ejecutar una o más toolsEjecutar, agregar results, continuar loop
"end_turn"Claude considera la tarea completaSalir del loop, entregar respuesta al usuario
"max_tokens"Se alcanzó el límite de tokensManejar como caso especial (truncamiento)

El stop_reason es la única señal confiable para controlar el flujo. Intentar detectar la terminación por otros medios es un anti-pattern.

Tool results en el historial

Cuando Claude solicita una herramienta, la respuesta incluye un tool_use content block con:

El desarrollador ejecuta la herramienta y devuelve el resultado como un mensaje con role "user" que contiene un tool_result content block:

{
  role: "user",
  content: [{
    type: "tool_result",
    tool_use_id: "toolu_abc123",
    content: "El archivo tiene 42 líneas"
  }]
}

Este resultado se agrega al array messages completo y se envía de vuelta a la API. Claude ve todo el historial — incluyendo sus llamadas previas y los resultados — para decidir el siguiente paso.

Ejemplo: agentic loop básico en TypeScript

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

function agenticLoop(tools: Tool[], messages: Message[]) {
  let response = await client.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 4096,
    tools,
    messages,
  });

  while (response.stop_reason === "tool_use") {
    const toolBlocks = response.content.filter(
      (b) => b.type === "tool_use"
    );

    const results = await Promise.all(
      toolBlocks.map((block) => executeTool(block.name, block.input))
    );

    messages.push({ role: "assistant", content: response.content });
    messages.push({
      role: "user",
      content: toolBlocks.map((block, i) => ({
        type: "tool_result",
        tool_use_id: block.id,
        content: JSON.stringify(results[i]),
      })),
    });

    response = await client.messages.create({
      model: "claude-sonnet-4-20250514",
      max_tokens: 4096,
      tools,
      messages,
    });
  }

  return response;
}

Puntos clave del ejemplo:

Model-driven decision-making

En un sistema agentic bien diseñado, Claude decide:

Esto contrasta con los pre-configured decision trees donde el desarrollador programa la secuencia de pasos. El modelo es más flexible: puede adaptarse a situaciones inesperadas, reintentar de formas diferentes y razonar sobre el estado actual.

Anti-patterns del agentic loop

1. Parsear lenguaje natural para terminar

// MAL: frágil y no confiable
if (response.content[0].text.includes("tarea completada")) {
  break;
}

El texto del modelo puede variar. Usar stop_reason es determinístico.

2. Caps arbitrarios de iteraciones

// MAL: corta el razonamiento prematuramente
const MAX_ITERATIONS = 3;
for (let i = 0; i < MAX_ITERATIONS; i++) { ... }

Si Claude necesita 5 iteraciones para completar una tarea, cortarlo en 3 produce resultados incompletos. Si necesitas un safety net, ponlo alto (ej: 50) y loguéalo como anomalía.

3. Buscar texto del asistente como indicador

// MAL: el modelo puede generar texto Y tool calls juntos
if (response.content.some(b => b.type === "text")) {
  return response; // podría haber tool_use blocks también
}

Una respuesta puede contener tanto text blocks como tool_use blocks simultáneamente. Solo stop_reason indica la intención real.

4. Ignorar tool_use blocks múltiples

Claude puede solicitar varias herramientas en un solo turno. Ejecutar solo la primera y descartar las demás produce información incompleta para el siguiente razonamiento.

Resumen

ConceptoDetalle
Control de flujostop_reason es la única señal confiable
HistorialSe envía completo en cada iteración
DecisionesEl modelo decide, no el desarrollador
Tool resultsSe agregan como mensajes del usuario con tool_result
Terminación"end_turn" — no parsing de texto

Anterior: Índice | Siguiente: Patrones Coordinator-Subagent