Image for post Programmatic Tool Calling en Claude: Menos Tokens, Más Agentes

Programmatic Tool Calling en Claude: Menos Tokens, Más Agentes


TL;DR: Programmatic Tool Calling (PTC) permite que Claude escriba código Python que orquesta múltiples herramientas en un solo paso de inferencia, en lugar de hacer un round-trip por cada llamada. El resultado: hasta un 37% menos de tokens en workflows multi-herramienta, latencia reducida y un control de flujo determinístico que elimina los errores de orquestación por lenguaje natural. A febrero de 2026, PTC está en disponibilidad general (GA) junto con Tool Search Tool y Dynamic Filtering.

El problema real: cada tool call te cuesta un round-trip

Si has construido un agente con la API de Claude (o cualquier LLM), conoces el patrón: defines herramientas como JSON, el modelo decide cuál llamar, emite una respuesta estructurada, tu runtime ejecuta la herramienta y devuelve el resultado al contexto. Para la siguiente herramienta, se repite todo el ciclo. Cada paso intermedio, cada resultado, cada error, se acumula en la ventana de contexto.

Con 3 herramientas, son 3 ciclos de inferencia. Con 10, son 10. Y cada resultado intermedio entra al contexto aunque no sea relevante para la respuesta final. En un agente que gestiona gastos de equipo, por ejemplo, los metadatos de cada recibo (URLs, ubicaciones, timestamps) terminan contaminando el contexto del modelo sin aportar nada a la pregunta original.

En mi experiencia construyendo pipelines RAG con múltiples fuentes, este patrón se vuelve insostenible en cuanto pasas de 5 herramientas. Los tokens se disparan, la latencia crece linealmente y el modelo empieza a perder el hilo con resultados intermedios irrelevantes.

¿Qué es Programmatic Tool Calling (PTC)?

Programmatic Tool Calling es una funcionalidad de la API de Claude que invierte el patrón tradicional: en lugar de que el modelo emita una llamada JSON por cada herramienta, Claude escribe un script Python completo que orquesta todas las herramientas dentro de un entorno de ejecución sandboxed. El script se ejecuta, las herramientas se invocan desde el código, y solo el resultado final vuelve a la ventana de contexto del modelo.

Dicho de forma directa: Claude pasa de ser un "operador de centralita" que conecta llamadas una a una, a ser un programador que escribe el script completo y te da el resumen.

Cómo funciona: arquitectura tradicional vs PTC

Flujo tradicional (tool calling estándar)

Usuario → Claude → tool_use JSON → Runtime ejecuta → Resultado al contexto
                  → Claude razona → tool_use JSON → Runtime ejecuta → Resultado al contexto
                  → Claude razona → Respuesta final

Cada flecha es un round-trip completo con inferencia del modelo. Tres herramientas = tres ciclos de inferencia + todos los resultados intermedios en contexto.

Flujo con PTC

Usuario → Claude escribe script Python → Sandbox ejecuta script
           ↳ Script llama herramienta 1 → resultado local
           ↳ Script llama herramienta 2 → resultado local
           ↳ Script filtra y procesa → output final
         → Solo el output final vuelve al contexto de Claude

Un solo paso de inferencia. El script Python maneja loops, condicionales, filtrado y transformación de datos. Claude solo ve el resultado procesado.

Implementación paso a paso

1. Instala el SDK de Anthropic

pip install anthropic

2. Define herramientas con allowed_callers

La clave de PTC está en el campo allowed_callers. Este campo indica que una herramienta puede ser invocada desde el entorno de ejecución de código, no solo directamente por el modelo.

import anthropic
import json

client = anthropic.Anthropic()

# Definir herramientas habilitadas para PTC
tools = [
    # Herramienta de ejecución de código (obligatoria para PTC)
    {
        "type": "code_execution_20250825",
        "name": "code_execution",
    },
    # Herramienta de negocio con PTC habilitado
    {
        "name": "obtener_gastos_equipo",
        "description": "Obtiene los gastos de un miembro del equipo por ID",
        "input_schema": {
            "type": "object",
            "properties": {
                "employee_id": {
                    "type": "string",
                    "description": "ID del empleado"
                }
            },
            "required": ["employee_id"]
        },
        # Permite invocación desde code execution
        "allowed_callers": ["code_execution_20250825"]
    },
    {
        "name": "obtener_miembros_equipo",
        "description": "Lista todos los miembros de un equipo",
        "input_schema": {
            "type": "object",
            "properties": {
                "team_id": {
                    "type": "string",
                    "description": "ID del equipo"
                }
            },
            "required": ["team_id"]
        },
        "allowed_callers": ["code_execution_20250825"]
    }
]

3. Envía la petición a la API

response = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=4096,
    tools=tools,
    messages=[
        {
            "role": "user",
            "content": "Analiza los gastos del equipo engineering-01. "
                       "¿Quién supera los 500€ mensuales?"
        }
    ]
)

# Claude genera un script Python en lugar de tool_use individuales
for block in response.content:
    print(f"Tipo: {block.type}")
    if hasattr(block, 'text'):
        print(block.text)

4. Procesa las llamadas del sandbox

Cuando el script de Claude necesita resultados de tus herramientas, el sandbox pausa la ejecución y emite un bloque tool_use con el campo caller indicando que viene del entorno de ejecución. Tu código debe procesarlo y devolver el resultado.

def procesar_tool_calls(response, messages):
    """Procesa tool calls del sandbox PTC."""
    while response.stop_reason == "tool_use":
        tool_results = []
        for block in response.content:
            if block.type == "tool_use":
                # Ejecutar la herramienta localmente
                resultado = ejecutar_herramienta(block.name, block.input)
                tool_results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": json.dumps(resultado)
                })

        # Devolver resultados al sandbox (NO al modelo)
        messages.append({"role": "assistant", "content": response.content})
        messages.append({"role": "user", "content": tool_results})

        response = client.messages.create(
            model="claude-sonnet-4-5-20250929",
            max_tokens=4096,
            tools=tools,
            messages=messages
        )

    return response

El detalle importante: los resultados de herramientas invocadas por PTC van al sandbox, no al contexto del modelo. Solo el output final del script es lo que Claude "ve".

5. Modo dual: directo + programático

No tienes que elegir uno u otro. Puedes permitir que una herramienta sea invocable tanto directamente como desde código:

{
    "name": "buscar_documentos",
    "description": "Busca documentos por query semántica",
    "input_schema": { ... },
    # Ambos modos habilitados
    "allowed_callers": ["direct", "code_execution_20250825"]
}

Claude decide automáticamente si la tarea requiere orquestación (PTC) o una llamada simple (directa).

Números reales: cuánto ahorra PTC

Según los benchmarks publicados por Anthropic en su post de ingeniería sobre advanced tool use:

MétricaTool calling tradicionalCon PTCDiferencia
Tokens promedio (tareas complejas)43.58827.297-37%
Tokens totales (benchmark real)110.47315.919-85,6%
Tasa de fallo en datasets grandes10-50%~0% (determinístico)Eliminado
Precisión en GIA benchmark46,5%51,2%+4,7 puntos

El caso extremo (85,6% de reducción) corresponde a workflows donde se procesan cientos de registros intermedios que con PTC nunca llegan al contexto del modelo.

Matiz importante sobre costes

Con Sonnet 4.5/4.6 (3$/MTok input, 15$/MTok output), el ahorro es limpio: menos tokens de entrada y la generación de código no es excesiva. Con Opus 4.6 (5$/MTok input, 25$/MTok output), el modelo genera scripts más elaborados, lo que incrementa los tokens de salida. Para un desarrollador individual que paga de su bolsillo (pensemos en 10-30€/mes de API), la diferencia entre PTC y traditional puede suponer ahorrarse un par de cafés o medio mes de uso según la complejidad del agente.

Tool Search Tool: el complemento que reduce un 85% los tokens de definición

PTC no viene solo. Junto con él, Anthropic lanzó Tool Search Tool, que resuelve otro problema de tokens: las definiciones de herramientas.

Si conectas 5 servidores MCP, acumulas unas 58 herramientas que consumen aproximadamente 55.000 tokens antes de que la conversación empiece. Con Tool Search, marcas herramientas como defer_loading: true y Claude solo carga las definiciones cuando las necesita.

# Sin Tool Search: todas las herramientas se cargan siempre
# ~77.000 tokens de overhead con 50+ herramientas

# Con Tool Search: carga bajo demanda
tools_con_search = [
    {
        "type": "tool_search_20250115",
        "name": "tool_search",
        "tool_library": mis_herramientas_mcp  # Se cargan solo cuando se necesitan
    },
    # Solo herramientas críticas cargadas por defecto
    {
        "name": "buscar_documentos",
        "description": "Búsqueda semántica en base de conocimiento",
        "input_schema": { ... }
    }
]
# ~8.700 tokens de overhead → 85% de reducción

Los datos internos de Anthropic muestran que la precisión en selección de herramientas también mejora: Opus 4 pasó de 49% a 74%, y Opus 4.5 de 79,5% a 88,1%.

Caso práctico: agente de análisis financiero

Un caso donde aplico PTC en mi trabajo: un agente que analiza gastos de departamentos para generar reportes mensuales. Antes de PTC, el flujo era:

  1. Llamar a la API para obtener lista de empleados (1 round-trip)
  2. Para cada empleado, obtener sus gastos (N round-trips)
  3. Para cada gasto fuera de rango, verificar presupuesto personalizado (M round-trips)
  4. Generar resumen

Con un equipo de 15 personas, eran potencialmente 30+ round-trips. Cada resultado intermedio (con metadatos de recibos, URLs, ubicaciones) entraba en el contexto.

Con PTC, Claude escribe un script que hace todo esto en un loop, filtra los datos irrelevantes, suma por categoría y devuelve solo el resumen. De 30+ round-trips a 15 llamadas a herramienta dentro del sandbox + un único resultado al contexto.

En Producción

La diferencia entre el tutorial y producción real con PTC tiene matices que conviene conocer:

Timeout del sandbox: los contenedores expiran tras ~4,5 minutos de inactividad. Si tu herramienta tarda más en responder (una consulta pesada a base de datos, por ejemplo), el container muere y pierdes el estado. La solución es implementar timeouts agresivos en tus herramientas y dividir consultas grandes en lotes.

Debugging es más opaco: con tool calling tradicional, cada paso es visible como un bloque tool_use en la conversación. Con PTC, la lógica de orquestación está dentro de un script generado. Si algo falla, estás depurando código que tú no escribiste. Registra los logs del sandbox (stdout/stderr) en tu sistema de observabilidad.

Zero Data Retention (ZDR): a febrero de 2026, PTC no está cubierto por acuerdos ZDR. Si trabajas con datos sensibles bajo regulaciones como GDPR, ten esto en cuenta antes de enviar datos de producción al sandbox.

Costes en Opus vs Sonnet: Opus 4.6 genera scripts más elaborados, lo que incrementa tokens de salida. Para tareas de orquestación pura, Sonnet 4.5/4.6 ofrece mejor relación coste-eficiencia. Reserva Opus para cuando la calidad del razonamiento lo justifique.

No paralelismo garantizado: aunque el script use asyncio.gather(), la ejecución real depende de cómo tu host procesa las peticiones. PTC reduce tokens y contexto, pero la paralelización de herramientas depende de tu implementación.

Reuso de containers: puedes pasar un container_id entre peticiones para mantener estado. Esto es clave para workflows multi-turno donde quieres que el sandbox recuerde variables de pasos anteriores.

Errores comunes y depuración

Error: La herramienta no se invoca desde PTC, solo funciona en modo directo.
Causa: Falta el campo allowed_callers o no incluye "code_execution_20250825".
Solución: Añadir "allowed_callers": ["code_execution_20250825"] a la definición de la herramienta. Para modo dual, usar ["direct", "code_execution_20250825"].

Error: El sandbox expira antes de completar el workflow.
Causa: Una herramienta tarda más de 4,5 minutos en responder.
Solución: Implementar timeouts en tus herramientas. Dividir operaciones largas en llamadas más pequeñas. Considerar procesamiento en lotes.

Error: PTC genera más tokens de salida que el ahorro en tokens de entrada.
Causa: Opus genera scripts extensos para tareas simples donde una llamada directa bastaba.
Solución: Usar modo dual (["direct", "code_execution_20250825"]) y dejar que Claude elija. Para herramientas simples que rara vez se encadenan, considera dejarlas solo en modo directo.

Preguntas frecuentes

¿PTC funciona con Claude Code (terminal/desktop)?

A febrero de 2026, Programmatic Tool Calling no está disponible en Claude Code. Hay un feature request abierto (issue #12836) con apoyo significativo de la comunidad, pero de momento solo funciona a través de la API directamente.

¿Puedo usar PTC con proveedores como AWS Bedrock o Azure?

Sí. LiteLLM soporta PTC en Anthropic API directa y Amazon Bedrock. Google Cloud Vertex AI no lo soporta todavía. El SDK de LiteLLM añade automáticamente los headers beta necesarios cuando detecta herramientas con allowed_callers.

¿PTC reemplaza completamente al tool calling tradicional?

No. Para llamadas simples a una sola herramienta, el modo directo sigue siendo más eficiente (menos overhead de generación de código). PTC brilla cuando tienes 3+ herramientas encadenadas, necesitas filtrar resultados grandes o requieres lógica condicional entre llamadas. El modo dual es la configuración recomendada para producción.

Hemos visto cómo Programmatic Tool Calling cambia la forma de construir agentes con Claude. La clave no es solo el ahorro de tokens, sino que la orquestación pase de lenguaje natural (frágil, acumulativo) a código Python (determinístico, filtrable). Combinado con Tool Search Tool para reducir el overhead de definiciones, el stack completo permite construir agentes con decenas de herramientas sin que el contexto explote.

Si estás construyendo agentes que usan más de 3-4 herramientas, PTC debería ser tu configuración por defecto. Empieza con modo dual en todas tus herramientas y deja que Claude decida cuándo orquestar por código.

¿Ya estás usando PTC en tus agentes? Cuéntame cómo te va en Twitter @sergiomarquezp_. En el próximo artículo exploraremos cómo combinar PTC con Agent SDK para construir agentes autónomos completos.