Al final de esta guía tendrás un flujo implementable para usar llamadas a funciones con OpenAI: definirás una herramienta, la enviarás al modelo, leerás la llamada devuelta, parsearás sus argumentos y ejecutarás tu propia función. Después activarás modo estricto, controlarás llamadas paralelas y validarás el contrato con Apidog antes de producción. Mantén abierta la documentación de llamadas a funciones de OpenAI y, si necesitas una visión más amplia, revisa esta guía sobre cómo construir agentes con el SDK de Agentes de OpenAI.
Lo que necesitas antes de empezar
La llamada a funciones, también llamada llamada a herramientas, permite que un modelo conecte una intención del usuario con código de tu aplicación o con sistemas externos.
El modelo no ejecuta la función. Solo devuelve una solicitud estructurada:
get_weather({ location: "Paris, France" })
Tu aplicación sigue siendo responsable de:
- Definir qué funciones existen.
- Enviar esas funciones al modelo como herramientas.
- Leer la llamada devuelta.
- Parsear y validar los argumentos.
- Ejecutar tu función real.
- Devolver el resultado al modelo.
Para seguir esta guía necesitas:
- Una clave API de OpenAI.
- Una función propia que quieras exponer al modelo.
- Decidir si usarás Chat Completions o la API de Responses.
Ambos endpoints soportan llamadas a funciones. La diferencia principal es la forma del payload: Chat Completions usa una estructura anidada con function, mientras que Responses usa una definición más plana.
Paso 1: Define tu herramienta
Una herramienta es la descripción de una función que el modelo puede llamar. Debe incluir:
-
name: nombre estable de la función. -
description: cuándo debe usarse. -
parameters: esquema JSON de los argumentos. - Opcionalmente,
strict: para forzar que los argumentos coincidan con el esquema.
Ejemplo para Chat Completions:
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obtiene el clima actual de una ciudad. Úsalo cuando el usuario pregunte por la temperatura o las condiciones.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "Ciudad y país, p. ej. Bogotá, Colombia"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"],
"additionalProperties": false
}
}
}
La descripción no es decorativa. Escríbela como una instrucción operativa para que el modelo sepa cuándo seleccionar la herramienta.
En la API de Responses, la misma herramienta se define sin el contenedor function:
{
"type": "function",
"name": "get_weather",
"description": "Obtiene el clima actual de una ciudad. Úsalo cuando el usuario pregunte por la temperatura o las condiciones.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "Ciudad y país, p. ej. Bogotá, Colombia"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"],
"additionalProperties": false
}
}
Si ya tienes una especificación OpenAPI, puedes reutilizar gran parte del trabajo de modelado de parámetros. Esta guía sobre generación de colecciones de pruebas a partir de especificaciones OpenAPI muestra cómo aprovechar esos esquemas para pruebas.
Paso 2: Envía la herramienta al modelo
Envía el mensaje del usuario junto con el array tools.
Ejemplo con Chat Completions:
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4.1",
"messages": [
{
"role": "user",
"content": "¿Cuál es el clima en París ahora mismo?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obtiene el clima actual de una ciudad.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string"
}
},
"required": ["location"],
"additionalProperties": false
}
}
}
]
}'
El modelo evaluará el mensaje y decidirá si debe llamar a una herramienta. Si la herramienta encaja, la respuesta no será texto final, sino una llamada estructurada.
Paso 3: Lee la llamada a la herramienta
En Chat Completions, la respuesta del asistente incluye tool_calls:
{
"id": "call_12345xyz",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Paris, France\"}"
}
}
En la API de Responses, la llamada aparece dentro del array output:
{
"type": "function_call",
"call_id": "call_12345xyz",
"name": "get_weather",
"arguments": "{\"location\":\"Paris, France\"}"
}
Punto importante: arguments es una cadena JSON, no un objeto. Debes parsearla antes de usarla.
Ejemplo en JavaScript:
const toolCall = response.choices[0].message.tool_calls[0];
const functionName = toolCall.function.name;
const args = JSON.parse(toolCall.function.arguments);
console.log(functionName);
// get_weather
console.log(args);
// { location: "Paris, France" }
No ejecutes la función directamente sin validar. Aunque uses modo estricto, tu aplicación debe seguir comprobando valores de negocio, permisos y errores de dependencias externas.
Paso 4: Ejecuta tu función
Una vez parseados los argumentos, enruta la llamada hacia tu implementación real.
async function getWeather({ location, unit = "celsius" }) {
// Aquí llamarías a tu proveedor real de clima
return {
location,
unit,
temperature: 18,
condition: "cloudy"
};
}
const availableFunctions = {
get_weather: getWeather
};
const fn = availableFunctions[functionName];
if (!fn) {
throw new Error(`Función no soportada: ${functionName}`);
}
const result = await fn(args);
Este patrón mantiene una separación clara:
- El modelo decide qué herramienta llamar.
- Tu código decide qué funciones existen realmente.
- Tu aplicación ejecuta la lógica.
Paso 5: Devuelve el resultado al modelo
Después de ejecutar la función, devuelve el resultado para que el modelo genere la respuesta final al usuario.
En Chat Completions, envías un mensaje con rol tool y el tool_call_id correspondiente:
{
"role": "tool",
"tool_call_id": "call_12345xyz",
"content": "{\"location\":\"Paris, France\",\"temperature\":18,\"unit\":\"celsius\",\"condition\":\"cloudy\"}"
}
El flujo completo queda así:
- Usuario pregunta.
- Modelo devuelve
tool_calls. - Tu aplicación ejecuta la función.
- Tu aplicación devuelve el resultado como mensaje
tool. - Modelo redacta la respuesta final.
En la API de Responses, devuelves un elemento function_call_output asociado al call_id.
Paso 6: Activa llamadas paralelas y modo estricto
Cuando el flujo básico funcione, ajusta estas configuraciones.
| Configuración | Qué controla | Por defecto | Cuándo cambiarlo |
|---|---|---|---|
parallel_tool_calls |
Si el modelo puede devolver múltiples llamadas en un mismo turno | true |
Usa false si las llamadas dependen entre sí o deben ejecutarse en orden |
strict |
Si los argumentos deben coincidir con el esquema | Mejor esfuerzo si no se establece | Actívalo cuando vayas a parsear los argumentos de forma automatizada |
tool_choice |
Si el modelo puede llamar herramientas y cuál | auto |
Usa required para forzar una llamada, none para deshabilitar o fija una herramienta concreta |
Llamadas paralelas
Por defecto, el modelo puede devolver varias llamadas a herramientas en una sola respuesta. Por ejemplo, si el usuario pregunta por el clima en tres ciudades, podrías recibir tres llamadas:
[
{
"id": "call_paris",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Paris, France\"}"
}
},
{
"id": "call_madrid",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Madrid, Spain\"}"
}
}
]
Puedes ejecutarlas en paralelo si son independientes. Si deben ejecutarse en orden, establece:
{
"parallel_tool_calls": false
}
Modo estricto
OpenAI recomienda habilitar el modo estricto para que los argumentos coincidan con tu Esquema JSON.
Ejemplo:
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obtiene el clima actual de una ciudad.",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string"
},
"unit": {
"type": ["string", "null"],
"enum": ["celsius", "fahrenheit", null]
}
},
"required": ["location", "unit"],
"additionalProperties": false
}
}
}
Reglas prácticas para modo estricto:
- Cada objeto debe incluir
additionalProperties: false. - Todos los campos de
propertiesdeben aparecer enrequired. - Para campos opcionales, usa
nullcomo tipo permitido. - No asumas que el modo estricto valida lógica de negocio.
Por ejemplo, location puede ser una cadena válida según el esquema, pero representar una ciudad que tu proveedor no soporta. Esa validación sigue siendo responsabilidad de tu código.
Cómo probarlo en Apidog
El modelo produce una llamada a herramienta. Antes de conectarla a una función en producción, necesitas comprobar dos cosas:
- Que los argumentos tienen la forma esperada.
- Que la API descendente que usará tu función responde como esperas.
Apidog ayuda a validar y simular ese contrato. No ejecuta tus funciones internas; valida el lado de la API y permite simular dependencias.
1. Valida la estructura de arguments
Toma la cadena arguments devuelta por OpenAI:
"{\"location\":\"Paris, France\",\"unit\":\"celsius\"}"
Parsea o pégala como cuerpo de solicitud en Apidog y valida que cumpla tu contrato:
{
"location": "Paris, France",
"unit": "celsius"
}
Puedes verificar:
- Que
locationexiste. - Que
locationes una cadena. - Que
unitsolo usa valores permitidos. - Que no aparecen campos inesperados.
- Que los campos requeridos están presentes.
Para extraer campos concretos, usa expresiones JSONPath. Para validar la estructura completa, usa validación contra un Esquema JSON.
La idea es usar el mismo contrato que le diste al modelo. Si la salida del modelo pasa ese esquema, reduces el riesgo antes de ejecutar la función real.
2. Simula la API descendente
Tu función get_weather probablemente llama a un proveedor de clima. Durante desarrollo, ese proveedor puede:
- Tener límites de tarifa.
- Cobrar por solicitud.
- No estar disponible todavía.
- No devolver errores específicos cuando necesitas probarlos.
Configura una API simulada en Apidog con una respuesta realista:
{
"location": "Paris, France",
"temperature": 18,
"unit": "celsius",
"condition": "cloudy"
}
Luego apunta tu función a esa simulación durante pruebas.
Esto te permite probar casos como:
- Respuesta exitosa.
- Timeout.
- Error
429. - Payload incompleto.
- Campos inesperados.
- Error del proveedor externo.
El flujo recomendado queda así:
- Captura una llamada a herramienta de OpenAI.
- Extrae y valida
arguments. - Ejecuta tu función contra una simulación en Apidog.
- Verifica cómo responde tu aplicación ante éxito y error.
- Solo después conecta la dependencia real.
Preguntas frecuentes
¿Funciona la llamada a funciones en Chat Completions y en Responses?
Sí. Ambos endpoints la soportan.
La diferencia principal está en la forma:
- Chat Completions anida la función bajo
functiony devuelvetool_calls. - Responses usa una definición de herramienta plana y devuelve elementos
function_callenoutput.
¿Por qué arguments llega como cadena?
Porque OpenAI devuelve los argumentos como texto codificado en JSON.
Siempre debes hacer:
const args = JSON.parse(toolCall.function.arguments);
Después valida el resultado antes de ejecutarlo. La validación de Esquema JSON ayuda a detectar payloads mal formados antes de que lleguen a tu función.
¿El modo estricto garantiza que la función tendrá éxito?
No.
El modo estricto garantiza que los argumentos coincidan con tu esquema. No garantiza que:
- La ubicación exista.
- El usuario tenga permisos.
- La API descendente esté disponible.
- La lógica de negocio acepte esos valores.
- Tu función no falle.
Sigue validando y manejando errores en tu aplicación.
¿Puede Apidog ejecutar mi función real?
No. Apidog no ejecuta las funciones internas de tu aplicación.
Lo que sí puede hacer es:
- Validar los argumentos generados por el modelo.
- Probar el contrato de entrada.
- Simular la API externa de la que depende tu función.
- Ayudarte a reproducir respuestas exitosas y errores.
Tu aplicación sigue ejecutando la función real.
Conclusión
Ya tienes el ciclo completo para implementar llamadas a funciones con OpenAI:
- Define tus herramientas con nombres, descripciones y esquemas claros.
- Envíalas al modelo con la solicitud del usuario.
- Lee
tool_callsofunction_call. - Parsea
arguments. - Ejecuta tu función.
- Devuelve el resultado al modelo.
- Activa
stricty configuraparallel_tool_callssegún tu caso. - Valida argumentos y simula dependencias antes de producción.
Si quieres probar el lado de validación y simulación, descarga Apidog para verificar argumentos de llamadas a herramientas contra tu esquema y simular las APIs de las que dependen tus funciones.

Top comments (0)