For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Navegación principal
Theme

Llamadas programáticas a herramientas

Permite que los modelos escriban y ejecuten código JavaScript para coordinar llamadas a herramientas.

Las llamadas programáticas a herramientas permiten que un modelo escriba y ejecute código JavaScript para coordinar sus herramientas. Un programa puede llamar a herramientas en paralelo, usar bucles y condiciones, y conservar los resultados intermedios en el entorno de ejecución alojado. Esto resulta útil cuando una tarea requiere una secuencia de llamadas relacionadas o cuando es necesario procesar grandes volúmenes de datos devueltos por las herramientas antes de entregar un resultado.

En la API de Responses, tu aplicación decide si habilita las llamadas programáticas a herramientas y cuáles de las herramientas compatibles puede invocar el modelo directamente, desde un programa o de ambas formas. Tu aplicación sigue ejecutando las llamadas a herramientas que están a cargo del cliente. La Agents API habilita las llamadas programáticas a herramientas de forma predeterminada y gestiona el bucle del agente por ti.

Consulta la página de modelos antes de habilitar las llamadas programáticas a herramientas.

Cómo funciona el entorno de ejecución

OpenAI ejecuta cada programa generado en un entorno V8 nuevo y aislado. El entorno admite JavaScript con await en el nivel superior, pero no ofrece Node.js, instalación de paquetes, acceso directo a la red, un sistema de archivos de propósito general, ejecución de subprocesos ni una consola. Tampoco conserva el estado de JavaScript entre ejecuciones. Los programas solo pueden interactuar con sistemas externos a través de las herramientas habilitadas en la solicitud y pueden emitir resultados con text(...) o image(...).

En las solicitudes a la API de Responses, las llamadas programáticas a herramientas admiten flujos de trabajo con retención cero de datos (ZDR) sin necesidad de un contenedor persistente para ejecutar código. La organización o el proyecto debe tener habilitada la ZDR. Configurar store: false permite continuar sin estado, pero por sí solo no habilita la ZDR. Tanto la posibilidad de aplicar la ZDR como la retención de datos dependen de la solicitud completa, incluidos el modelo, las herramientas y los servicios de terceros. Consulta los controles de datos.

Cuándo usar llamadas programáticas a herramientas

Usa llamadas programáticas a herramientas cuando una etapa tenga un flujo de control predecible y el código pueda devolver un resultado estructurado más compacto. Usa llamadas directas cuando baste con una sola llamada, cuando el modelo deba evaluar cada resultado para tomar una nueva decisión o cuando el trabajo requiera aprobación o exija conservar citas o artefactos nativos.

Tipo de tarea Modo recomendado
Una sola consulta o acción Usa una llamada directa a la herramienta.
Varios resultados que el código puede filtrar, combinar, clasificar, deduplicar, agregar o validar Usa llamadas programáticas a herramientas cuando el programa pueda devolver un resultado estructurado más compacto.
Llamadas que dependen unas de otras y tienen un flujo de datos predecible Usa llamadas programáticas a herramientas cuando el código pueda calcular los argumentos de las llamadas posteriores y estén definidos explícitamente tanto los límites como el comportamiento en caso de error.
Búsqueda adaptativa o evaluación semántica Usa llamadas directas a herramientas cuando cada resultado deba influir en la siguiente decisión del modelo.
Operaciones de escritura o acciones para las que la aprobación es importante Usa llamadas directas a herramientas de forma predeterminada para que quede claro qué acciones están autorizadas.
Validación final de citas o artefactos nativos Usa llamadas directas a herramientas a menos que el programa conserve la salida nativa y valide cada elemento requerido.

Configurar las llamadas programáticas a herramientas

En la API de Responses, agrega la herramienta alojada programmatic_tool_calling a la solicitud. Luego configura allowed_callers en cada herramienta compatible que el programa pueda invocar.

Habilitar las llamadas programáticas a herramientas
[
  {
    "type": "function",
    "name": "get_inventory",
    "description": "Return an object with sku (string) and available_units (number).",
    "parameters": {
      "type": "object",
      "properties": {
        "sku": { "type": "string" }
      },
      "required": ["sku"],
      "additionalProperties": false
    },
    "output_schema": {
      "type": "object",
      "properties": {
        "sku": { "type": "string" },
        "available_units": { "type": "number" }
      },
      "required": ["sku", "available_units"],
      "additionalProperties": false
    },
    "allowed_callers": ["programmatic"]
  },
  {
    "type": "programmatic_tool_calling"
  }
]

allowed_callers controla cómo puede invocar el modelo una herramienta:

Valor Comportamiento
Sin especificar o ["direct"] El modelo puede llamar a la herramienta directamente.
["programmatic"] Solo el código de un elemento program puede llamar a la herramienta.
["direct", "programmatic"] El modelo puede llamar a la herramienta directamente o desde un programa.

parameters describe los argumentos de la función. Cuando una función devuelve datos con una estructura predecible, output_schema describe el objeto JSON codificado en la cadena function_call_output.output de la función. Define ambos para que el código JavaScript generado pueda usar los campos devueltos de forma confiable.

Herramientas compatibles

Los siguientes tipos de herramientas admiten allowed_callers: ["programmatic"]:

  • function y custom
  • mcp
  • apply_patch
  • shell local y alojado
  • code_interpreter

En las herramientas MCP, la política require_approval de la herramienta puede pausar el programa hasta que apruebes la llamada.

Antes de habilitar en un programa una herramienta alojada por OpenAI, revisa sus pautas de retención de datos y seguridad.

Combinar las llamadas con la búsqueda de herramientas

La búsqueda de herramientas se ejecuta como una herramienta de nivel superior de la API de Responses, fuera del código JavaScript generado. Al principio, el programa no tiene acceso a las herramientas de función, personalizadas o MCP que tienen defer_loading: true. Una vez que el modelo carga una herramienta que coincide con la búsqueda, un programa posterior puede invocarla mediante tools.* si su configuración de allowed_callers incluye "programmatic". Un programa que ya está en ejecución no puede invocar la búsqueda de herramientas, así que el modelo debe cargar las herramientas de carga diferida antes de iniciar un programa que las necesite.

Indicar qué modo usar cuando ambos están disponibles

Cuando tu aplicación permite que el modelo llame a una función directamente o desde un programa, asigna cada modo a una etapa específica del flujo de trabajo. Las instrucciones genéricas como “usa las llamadas programáticas a herramientas de forma eficiente” no indican en qué etapa corresponde usar cada modo. Por ejemplo:

<tool_orchestration>
Usa llamadas programáticas a herramientas para [bounded stage] y emplea solo [eligible tools].
Ejecuta las llamadas independientes de manera concurrente cuando sea seguro hacerlo.
Usa solo los campos de entrada y salida documentados de las herramientas.

Procesa y reduce los resultados intermedios. Luego devuelve el resultado con la estructura
exacta [program result shape] e incluye la evidencia necesaria para la respuesta final.

Detente cuando se cumpla [condition]. Si una llamada falla por un error transitorio,
reinténtala como máximo [R] veces. No repitas llamadas ya completadas ni realices
acciones con efectos secundarios. Si aún falta un resultado requerido, devuelve un error
estructurado que indique claramente qué falló.

Usa llamadas directas a herramientas para [semantic judgment, approval, or final validation].
</tool_orchestration>

Este ejemplo muestra cómo usar la plantilla:

<tool_orchestration>
Usa llamadas programáticas a herramientas para comparar el inventario de sku_123 con su demanda.
Usa únicamente get_inventory y get_demand. Ejecuta ambas llamadas de manera concurrente.
Usa solo los campos de entrada y salida documentados de las herramientas.

Procesa y reduce los resultados intermedios. Luego devuelve exactamente un objeto JSON
con los campos sku, available_units, requested_units y shortage_units. Calcula
shortage_units con la fórmula max(requested_units - available_units, 0). Incluye
available_units y requested_units para que se pueda verificar el cálculo.

Detente cuando los resultados de ambas herramientas contengan los campos requeridos.
Si una llamada falla por un error transitorio, reinténtala como máximo 1 vez. No repitas
llamadas ya completadas ni realices acciones con efectos secundarios. Si aún falta un
resultado requerido, devuelve un error estructurado que indique claramente qué falló.

Antes de realizar cualquier acción que modifique el inventario, obtén la aprobación
mediante una llamada directa a una herramienta. Usa las llamadas directas solo con ese fin.
</tool_orchestration>

En los flujos de trabajo que requieren ambos modos, define un único punto de transición y evita alternar entre modos o repetir trabajo. Si hay una alternativa segura en caso de error, defínela una sola vez y limita los reintentos.

Elementos del programa en la respuesta

Cada llamada a la API sigue devolviendo el objeto estándar de la API de Responses. Las llamadas programáticas a herramientas no introducen un contenedor de respuesta independiente. Cuando el modelo usa llamadas programáticas a herramientas, el arreglo output de la respuesta puede contener:

  • Un elemento program que contiene el código JavaScript generado, un call_id y un valor opaco fingerprint que se usa para reanudar o reproducir la ejecución del programa.
  • Un elemento function_call que representa una llamada realizada por el programa. Tiene su propio call_id, que tu aplicación usa para devolver el resultado de la función. Su caller.caller_id coincide con el call_id del programa.
  • Un elemento program_output que contiene el resultado final y el estado del programa. Su call_id coincide con el call_id del programa y su status es completed o incomplete.

Estos elementos aparecen por separado en el nivel superior de response.output. El campo caller registra cómo se relacionan durante la ejecución.

Por ejemplo, un programa puede quedar en pausa mientras tu aplicación ejecuta get_inventory y get_demand:

Programa y llamadas anidadas a funciones
[
  {
    "type": "program",
    "id": "prog_123",
    "call_id": "call_prog_123",
    "code": "const [stock, demand] = await Promise.all([tools.get_inventory({ sku: 'sku_123' }), tools.get_demand({ sku: 'sku_123' })]); text(JSON.stringify({ sku: stock.sku, available_units: stock.available_units, requested_units: demand.requested_units, shortage_units: Math.max(demand.requested_units - stock.available_units, 0) }));",
    "fingerprint": "opaque_replay_state"
  },
  {
    "type": "function_call",
    "id": "fc_123",
    "call_id": "call_inventory_123",
    "name": "get_inventory",
    "arguments": "{\"sku\":\"sku_123\"}",
    "caller": {
      "type": "program",
      "caller_id": "call_prog_123"
    }
  },
  {
    "type": "function_call",
    "id": "fc_456",
    "call_id": "call_demand_123",
    "name": "get_demand",
    "arguments": "{\"sku\":\"sku_123\"}",
    "caller": {
      "type": "program",
      "caller_id": "call_prog_123"
    }
  }
]

Estos ejemplos muestran solo los elementos pertinentes de response.output y omiten el objeto estándar de Responses que los contiene. Después de que tu aplicación devuelva los resultados de las llamadas anidadas, una respuesta posterior puede contener el elemento program_output completo:

Salida del programa
{
  "type": "program_output",
  "id": "prog_out_123",
  "call_id": "call_prog_123",
  "result": "{\"sku\":\"sku_123\",\"available_units\":42,\"requested_units\":31,\"shortage_units\":0}",
  "status": "completed"
}

La cadena JSON de program_output.result tiene la estructura que especificaste en tus instrucciones para el resultado del programa. El elemento program_output que la contiene sigue el contrato de la API que se muestra arriba. Son dos contratos distintos. El elemento message final puede llegar junto con la salida del programa o en una respuesta posterior. Continúa hasta recibir ese mensaje.

OpenAI ejecuta el código JavaScript generado por el modelo en el entorno de ejecución alojado. Tu aplicación ejecuta las llamadas a funciones a cargo del cliente que recibe en la respuesta. No ejecuta el código JavaScript generado.

Devuelve el resultado de la función como un elemento function_call_output. Copia el valor de caller de la llamada a la función sin modificarlo. El servicio usa ese valor para reanudar el programa correspondiente.

Continuar después de las llamadas a funciones a cargo del cliente

Un programa puede pausarse más de una vez al invocar herramientas a cargo del cliente. Continúa hasta que la respuesta contenga un mensaje final del asistente:

  1. Envía la solicitud con la herramienta alojada y las funciones que admiten llamadas programáticas.
  2. Ejecuta todas las llamadas a funciones a cargo del cliente que recibas en la respuesta.
  3. Devuelve el resultado de cada función con los valores originales de call_id y caller.
  4. Si la respuesta está incompleta, maneja ese caso antes de continuar.
  5. Si la respuesta no contiene elementos function_call pendientes ni un elemento message final, continúa a partir de esa respuesta. Con store: false, vuelve a enviar sus elementos de salida. Si la respuesta está almacenada, usa previous_response_id.
  6. Detente cuando la respuesta contenga un elemento message final. Lee response.output_text o el contenido del mensaje que indica el rechazo.

El siguiente ejemplo usa store: false, conserva todos los elementos de cada respuesta y devuelve al programa el resultado de cada función:

Ejecutar un bucle de llamadas programáticas a herramientas
import json

from openai import OpenAI

client = OpenAI()
model = "gpt-6-astra"


def get_inventory(sku):
    return {"sku": sku, "available_units": 42}


def get_demand(sku):
    return {"sku": sku, "requested_units": 31}


implementations = {
    "get_inventory": get_inventory,
    "get_demand": get_demand,
}

tools = [
    {
        "type": "function",
        "name": "get_inventory",
        "description": "Return an object with sku (string) and available_units (number).",
        "parameters": {
            "type": "object",
            "properties": {"sku": {"type": "string"}},
            "required": ["sku"],
            "additionalProperties": False,
        },
        "output_schema": {
            "type": "object",
            "properties": {
                "sku": {"type": "string"},
                "available_units": {"type": "number"},
            },
            "required": ["sku", "available_units"],
            "additionalProperties": False,
        },
        "allowed_callers": ["programmatic"],
    },
    {
        "type": "function",
        "name": "get_demand",
        "description": "Return an object with sku (string) and requested_units (number).",
        "parameters": {
            "type": "object",
            "properties": {"sku": {"type": "string"}},
            "required": ["sku"],
            "additionalProperties": False,
        },
        "output_schema": {
            "type": "object",
            "properties": {
                "sku": {"type": "string"},
                "requested_units": {"type": "number"},
            },
            "required": ["sku", "requested_units"],
            "additionalProperties": False,
        },
        "allowed_callers": ["programmatic"],
    },
    {"type": "programmatic_tool_calling"},
]

input_items = [
    {
        "role": "user",
        "content": "Compare inventory with demand for sku_123.",
    }
]

while True:
    response = client.responses.create(
        model=model,
        store=False,
        input=input_items,
        tools=tools,
    )

    if response.status != "completed":
        raise RuntimeError(f"Response ended with status {response.status}")

    # Preserve every output item, including program and reasoning items.
    input_items.extend(item.model_dump(exclude_none=True) for item in response.output)

    calls = [item for item in response.output if item.type == "function_call"]
    if not calls:
        message = next(
            (item for item in response.output if item.type == "message"), None
        )
        if message:
            refusal = next(
                (part.refusal for part in message.content if part.type == "refusal"),
                "",
            )
            print(response.output_text or refusal)
            break
        continue

    for call in calls:
        run = implementations.get(call.name)
        if run is None:
            raise ValueError(f"Unknown tool: {call.name}")

        result = run(**json.loads(call.arguments))
        input_items.append(
            {
                "type": "function_call_output",
                "call_id": call.call_id,
                "output": json.dumps(result),
                # Preserve caller so the runtime can resume the correct program.
                "caller": call.caller.model_dump() if call.caller else None,
            }
        )

Cuando almacenas las respuestas, puedes continuar a partir de previous_response_id sin tener que volver a enviar todos los elementos de las respuestas anteriores. Envía los nuevos elementos function_call_output como la siguiente entrada. Con store: false, vuelve a enviar la secuencia completa en orden, incluidos todos los elementos program, de razonamiento, de llamada a funciones, de salida de llamadas a funciones y program_output.

En las solicitudes sin estado a modelos de razonamiento, vuelve a enviar todos los elementos de razonamiento devueltos. Cada elemento incluye encrypted_content de forma predeterminada. Consulta el estado de la conversación para ver el procedimiento general para solicitudes sin estado.

Diseñar herramientas para programas

  • Devuelve datos estructurados y compactos que el código JavaScript pueda examinar sin tener que interpretar texto en prosa.
  • Usa output_schema para definir los campos y tipos de datos que debe devolver cada herramienta, y documenta cómo se comporta en caso de error. Si no conoces de antemano la estructura del resultado, configura la herramienta solo para llamadas directas de modo que el modelo pueda examinarlo.
  • Define la estructura exacta del resultado del programa y la evidencia requerida. Si el programa no puede producir un resultado válido, devuelve un error estructurado que indique claramente qué falló.
  • Siempre que sea posible, haz que las llamadas a funciones sean idempotentes. Un reintento o una repetición de la ejecución no debería volver a producir un efecto secundario inseguro.
  • Verifica en tu aplicación los argumentos y permisos de cada llamada, incluso si proviene de un programa alojado.
  • Asigna nombres y descripciones específicos a las herramientas para que el modelo pueda combinarlas correctamente.
  • Exige aprobación en la aplicación antes de realizar acciones de alto impacto, sin importar quién haga la llamada.

Evaluar las llamadas programáticas a herramientas

Las llamadas programáticas a herramientas pueden reducir el volumen de resultados intermedios que se agregan al contexto del modelo, pero el efecto depende de la tarea y de las respuestas de las herramientas. Empieza con llamadas directas a herramientas como referencia y luego compara ambos modos con tareas representativas.

Antes de medir la eficiencia, define qué nivel de calidad debe alcanzar la respuesta final y qué evidencia debe incluir. Evalúa el consumo de tokens y las llamadas a herramientas junto con la exactitud, la exhaustividad y la cobertura de la evidencia. Indica explícitamente cualquier concesión que aceptes en materia de calidad.

Mide lo siguiente:

  • La exactitud y la exhaustividad de la respuesta final, y la cobertura de la evidencia.
  • La cantidad de tokens de entrada y de tokens totales, la latencia de extremo a extremo y el costo.
  • Los turnos del modelo, las llamadas a herramientas, los reintentos y el comportamiento durante la recuperación de errores.
  • Los resultados en materia de seguridad, en especial en lo que respecta a los efectos secundarios y los requisitos de aprobación.
  • Si el modo que se usó correspondía a la etapa prevista del flujo de trabajo.

Agents API

En la Agents API, las llamadas programáticas a herramientas se ejecutan en el arnés de ejecución del agente que administra OpenAI y están habilitadas de forma predeterminada. El arnés de ejecución proporciona al agente una herramienta exec y le permite usar sus herramientas existentes desde el código JavaScript generado. No necesitas encapsular esas herramientas en programas de línea de comandos ni instalarlas en el sandbox.

Para deshabilitar las llamadas programáticas a herramientas, incluye esta entrada en agent.tools:

{
  "type": "programmatic_tool_calling",
  "enabled": false
}

Si omites la entrada o su campo enabled, las llamadas programáticas a herramientas siguen habilitadas. Una entrada que solo especifica el tipo, { "type": "programmatic_tool_calling" }, también las mantiene habilitadas. La configuración de allowed_callers y el bucle de continuación de Responses descritos arriba corresponden a la integración con la API de Responses.

Las llamadas programáticas a herramientas también funcionan en sesiones que solo incluyen la conversación y tienen environment.type configurado como none. Bash, los MCP del ejecutor y las demás herramientas que se ejecutan en un sandbox siguen necesitando un entorno de ejecución.

Coordinar una herramienta desde JavaScript no cambia el lugar donde se ejecuta. Una llamada al shell ejecuta comandos en el sandbox. El entorno de ejecución de JavaScript no inicia procesos del sistema por sí mismo. Los MCP del ejecutor siguen usando el sandbox y las herramientas de función siguen llamando al servidor de tu aplicación. El agente procesa sus resultados antes de decidir qué información se incorpora al contexto del modelo.

Usa las pautas anteriores para definir en qué etapas del flujo de trabajo se debe usar código. Sigue las guías de funciones y conexiones MCP para configurar la Agents API y gestionar las llamadas.

Guías relacionadas