Programa
Con el lanzamiento de GPT-5, OpenAI amplió las llamadas a herramientas/funciones en la API para incluir llamadas a herramientas de formato libre (texto sin formato, sin JSON), restricciones gramaticales a través de Lark/CFG, listas de herramientas permitidas y un razonamiento mejorado sobre el uso de las herramientas. En conjunto, todo ello convierte a GPT-5 en un modelo verdaderamente agente: puedes conectar API, bases de datos y herramientas personalizadas a la API de respuestas y generar respuestas fundamentadas o incluso automatizar flujos de trabajo.
En este tutorial, voy a explicar herramientas de funciones, herramientas personalizadas, restricciones gramaticales, listas de herramientas permitidasy preámbulos, con ejemplos de código y explicaciones claras sobre cómo funcionan y cuándo utilizarlos.
Llamada a funciones en GPT-5: Qué y por qué
La llamada a funciones en GPT-5 te permite mejorar el modelo con los datos y las acciones de tu aplicación. El modelo puede determinar cuándo llamar a una herramienta, mientras tú te encargas de la lógica y devuelves los resultados para obtener una respuesta final y fundamentada.
Tipos de llamadas a funciones:
- Herramientas funcionales (esquema JSON): Estos ofrecen entradas y salidas estructuradas que el modelo puede invocar con precisión.
- Herramientas personalizadas (forma libre): Proporcionan entradas y salidas de texto flexibles para integraciones no estructuradas.
¿Qué es una llamada a función?
GPT-5 admite tanto herramientas de funciones estructuradas (que utilizan JSON Schema) como herramientas personalizadas que aceptan cargas útiles de texto de formato libre (como SQL, scripts o configuraciones) para una integración perfecta con entornos de ejecución externos.
Las herramientas funcionales se definen mediante JSON Schema, lo que garantiza que el modelo comprenda exactamente qué argumentos pasar y permite una validación estricta de los datos introducidos. Puedes obtener más información en nuestro tutorial sobre llamadas a funciones de OpenAI.
¿Por qué utilizar llamadas a funciones?
- Flexibilidad: Las herramientas de formato libre permiten que el modelo genere el texto exacto que requiere tu sistema, sin las limitaciones del rígido JSON, lo que las hace ideales para código, consultas o configuraciones.
- Fiabilidad y control: Las herramientas funcionales imponen argumentos estructurados, lo que mejora la previsibilidad y reduce los errores de análisis sintáctico.
- Flujos de trabajo agenticos: GPT-5 está diseñado para tareas complejas de codificación y uso de herramientas de varios pasos, por lo que la activación de herramientas es una de sus características principales.
¿Cómo funciona la llamada a funciones?
- Envía un mensaje que incluya todas las herramientas disponibles.
- El modelo emite una llamada a la herramienta (ya sea con argumentos o con texto libre).
- Tu aplicación ejecuta la herramienta (ejecuta la función Python).
- Devuelve el resultado de la herramienta al modelo.
- A continuación, el modelo responde o puede recurrir a herramientas adicionales.

Fuente: Llamada a funciones - API de OpenAI
Cuándo utilizar la función frente a Herramientas personalizadas
- Utiliza herramientas funcionales cuando desees una validación estricta y argumentos predecibles y tipificados a través de JSON Schema.
- Utiliza herramientas personalizadas (forma libre) cuando tu tiempo de ejecución requiera texto sin formato (como scripts, SQL o configuraciones) o cuando necesites iteraciones rápidas sin esquemas.
Herramientas funcionales (esquema JSON): Enviar datos estructurados
El uso de herramientas de función con JSON Schema te permite obtener resultados predecibles y estructurados del modelo. El modelo evalúa las herramientas que has declarado, determina cuándo utilizar una, propone argumentos validados por JSON y, a continuación, ejecuta la función correspondiente en tu código.
Después, puedes pedirle al modelo que genere una respuesta basada únicamente en los datos devueltos por la herramienta, asegurándote de que el resultado sea sólido, legible por máquina y fácil de integrar.
Este ejemplo ilustra varios conceptos clave:
- Descubrimiento de herramientas y generación de argumentos: El modelo selecciona la herramienta adecuada y rellena automáticamente sus argumentos de tipo JSON.
- Bucle de ejecución de la herramienta: Tu aplicación ejecuta las herramientas solicitadas y envía los resultados al modelo.
- Respuesta final en forma de esquema: La respuesta final se basa estrictamente en los resultados de las herramientas, lo que minimiza las imprecisiones y garantiza la fiabilidad.
1. Configuración
- Crea una cuenta de OpenAI y genera una clave API en el panel de control de la plataforma. En el panel de control, abre la sección API, luego «Ver claves API» y haz clic en «Crear nueva clave secreta».
- Añade un método de pago o créditos a tu cuenta para que las llamadas API puedan ejecutarse; el uso se deduce de tu saldo prepagado a medida que realizas solicitudes.
- Guarda tu clave API como una variable de entorno denominada OPENAI_API_KEY antes de iniciar tu aplicación.
- Instala el SDK oficial de OpenAI para Python con
pip install openai.
2. Definir herramientas
Proporcionas una lista de herramientas con un nombre, una descripción y un esquema JSON para los parámetros. El esquema ayuda al modelo a proporcionar argumentos bien formados.
make_coffeeEspera un parámetro de cadena:coffee_type.random_coffee_factNo toma ningún parámetro (objeto vacío). Estas definiciones se pasan a través de un argumentotoolsen la llamada a la API para que el modelo sepa qué está disponible.
import os
from openai import OpenAI
import json
client = OpenAI(api_key = os.environ["OPENAI_API_KEY"])
tools = [
{
"type": "function",
"name": "make_coffee",
"description": "Gives a simple recipe for making a coffee drink.",
"parameters": {
"type": "object",
"properties": {
"coffee_type": {
"type": "string",
"description": "The coffee drink, e.g. espresso, cappuccino, latte"
}
},
"required": ["coffee_type"],
},
},
{
"type": "function",
"name": "random_coffee_fact",
"description": "Returns a fun fact about coffee.",
"parameters": {"type": "object","properties":{}}
}
]
3. Implementar herramientas
Implementas las funciones de Python que realmente hacen el trabajo:
make_coffee(coffee_type)devuelve una cadena concisa con la receta correspondiente a la bebida solicitada.random_coffee_fact()devuelve una pequeña carga útil de datos.
Ambos devuelven diccionarios serializables en JSON, ideales para retroalimentar al modelo.
def make_coffee(coffee_type):
recipes = {
"espresso": "Grind fine, 18g coffee → 36g espresso in ~28s.",
"cappuccino": "Brew 1 espresso shot, steam 150ml milk, pour and top with foam.",
"latte": "Brew 1 espresso shot, steam 250ml milk, pour for silky texture.",
}
return {"coffee_type": coffee_type, "recipe": recipes.get(coffee_type.lower(), "Unknown coffee type!")}
def random_coffee_fact():
return {"fact": "Coffee is the second most traded commodity in the world, after oil."}
4. Iniciar una conversación
Inicia la conversación con la pregunta del usuario: {"role": "user", "content": "How do I make a latte?"}
El modelo puede devolver mensajes que incluyan un elemento function_call, como make_coffee con {"coffee_type":"latte"}. A continuación, debes volver a añadir los mensajes del modelo en input_list: input_list += response.output. Esto ayuda a mantener el estado de la conversación para el siguiente turno.
# Track used tools
used_tools = []
input_list = [{"role": "user", "content": "How do I make a latte?"}]
response = client.responses.create(
model="gpt-5",
tools=tools,
input=input_list,
)
input_list += response.output
5. Ejecutar llamadas a herramientas y adjuntar resultados
Debes iterar sobre response.output e identificar los elementos en los que item.type es igual a "function_call". Para estos elementos, analiza item.arguments y envía las solicitudes a tus funciones de Python.
Para la función make_coffee, llámala utilizando make_coffee(args["coffee_type"]). Para la función « random_coffee_fact », simplemente llama a « random_coffee_fact() ».
Después de ejecutar las funciones, añade un mensaje « function_call_output » (Añadido correctamente) que incluya lo siguiente:
call_id(que vincula esta salida con la solicitud del modelo)output(una cadena JSON con el resultado de tu función).
for item in response.output:
if getattr(item, "type", "") == "function_call":
used_tools.append(item.name)
args = json.loads(item.arguments or "{}")
if item.name == "make_coffee":
result = make_coffee(args["coffee_type"])
elif item.name == "random_coffee_fact":
result = random_coffee_fact()
else:
result = {"error": f"Unknown tool {item.name}"}
input_list.append({
"type": "function_call_output",
"call_id": item.call_id,
"output": json.dumps(result)
})
6. Genera la respuesta final.
Realizas una segunda llamada a client.responses.create, pasando el objeto input_list actualizado, que ahora incluye los resultados de la herramienta.
La variable used_tools captura los nombres de las herramientas que aparecieron en las llamadas a funciones del modelo. Lo utilizaremos para mostrar qué herramientas se utilizaron.
final = client.responses.create(
model="gpt-5",
tools=tools,
input=input_list,
instructions="Answer using only the tool results."
)
print("Final output:\n", final.output_text)
print("\n--- Tool Usage ---")
for t in tools:
status = "USED ✅" if t["name"] in used_tools else "NOT USED ❌"
print(f"{t['name']}: {status}")
Como el usuario preguntó por un café con leche, el modelo seleccionó make_coffee con coffee_type = "latte", tu código lo ejecutó y la respuesta final se construyó únicamente a partir del resultado de esa herramienta.
Final output:
{"coffee_type":"latte","recipe":"Brew 1 espresso shot, steam 250ml milk, pour for silky texture."}
--- Tool Usage ---
make_coffee: USED ✅
random_coffee_fact: NOT USED ❌
Herramientas personalizadas (forma libre): Enviar texto sin formato
Utiliza las herramientas personalizadas de formato libre de GPT-5 para permitir que el modelo envíe texto sin procesar directamente a tu herramienta, como código, SQL, comandos de terminal o CSV simple, sin necesidad de JSON Schema.
Esta capacidad va más allá de las antiguas llamadas a funciones solo JSON, lo que te proporciona una mayor flexibilidad para la integración con ejecutores, motores de consulta o intérpretes de lenguajes específicos de dominio (DSL).
En el modo de formato libre, el modelo genera una llamada a una herramienta personalizada con una carga útil de texto no estructurado que puedes dirigir a tu tiempo de ejecución. A continuación, devuelves el resultado para que el modelo lo utilice en la finalización de la respuesta dirigida al usuario.
Ahora escribiremos el código que permite al modelo seleccionar las herramientas adecuadas y devolver texto sin estructurar como resultado. A continuación, este resultado se pasará a una función de Python para generar un resultado. De esta manera, el usuario puede indicar los ingredientes que tienes, y el modelo generará recetas que se adapten a tus necesidades.
En este código de ejemplo, tenemos:
- Inicialicé el cliente OpenAI y definí una única herramienta personalizada llamada
meal_plannerque acepta entradas de texto sin formato. - Creé el Python
plan_meal, que toma una cadena de ingredientes separados por comas y devuelve una idea para una comida. - Inicié la conversación con un mensaje de usuario en el que enumeraba los ingredientes disponibles.
- Realicé una llamada inicial al modelo indicando a GPT-5 que invocara la herramienta utilizando únicamente una lista limpia de ingredientes, y añadí el resultado del modelo al historial de conversaciones.
- Localizaste la llamada a la herramienta personalizada emitida y extrajiste la cadena de entrada sin procesar separada por comas.
- Ejecuté la herramienta pasando la lista a
plan_mealy, a continuación, envié el resultado al modelo como unfunction_call_outputvinculado a través decall_id. - Realicé una llamada de modelo final para convertir la idea inicial de la herramienta en una receta concisa y paso a paso, e imprimí tanto los detalles de la llamada a la herramienta como el resultado final.
from openai import OpenAI
import json
import random
client = OpenAI()
# --- Custom tool ---
tools = [
{
"type": "custom",
"name": "meal_planner",
"description": "Takes ONLY a comma-separated list of ingredients and suggests a meal idea."
}
]
# --- Fake meal planner ---
def plan_meal(ingredients: str) -> str:
ideas = [
f"Stir-fry: {ingredients} with garlic & soy sauce.",
f"One-pot rice: cook {ingredients} together in broth until fluffy.",
f"Soup: simmer {ingredients} in stock with herbs.",
f"Sheet-pan bake: roast {ingredients} at 200°C for ~20 min."
]
return random.choice(ideas)
# --- Start conversation ---
messages = [
{"role": "user", "content": "I only have chicken, rice, and broccoli. Any dinner ideas?"}
]
# 1) Ask model with clear instruction
resp = client.responses.create(
model="gpt-5",
tools=tools,
input=messages,
instructions="If the user mentions ingredients, call the meal_planner tool with ONLY a comma-separated list like 'chicken, rice, broccoli'."
)
messages += resp.output
# 2) Find the tool call
tool_call = next((x for x in resp.output if getattr(x, "type", "") == "custom_tool_call"), None)
assert tool_call, "No tool call found!"
# Get clean CSV input
ingredients_csv = tool_call.input.strip()
# 3) Run the tool
meal_result = plan_meal(ingredients_csv)
# 4) Send tool output back
messages.append({
"type": "function_call_output",
"call_id": tool_call.call_id,
"output": meal_result
})
# 5) Final model response
final = client.responses.create(
model="gpt-5",
tools=tools,
input=messages,
instructions="Turn the meal idea into a short recipe with 3-4 steps."
)
print("\n--- Tool Call ---")
print("Name:", tool_call.name)
print("Input:", ingredients_csv)
print("Output:", meal_result)
print("\n--- Final Output ---\n", final.output_text)
Como resultado, recibimos estadísticas sobre las herramientas utilizadas, incluyendo la instalación, la entrada y la salida. Además, el resultado final proporciona una receta completa sobre cómo preparar la comida.
--- Tool Call ---
Name: meal_planner
Input: chicken, rice, broccoli
Output: One-pot rice: cook chicken, rice, broccoli together in broth until fluffy.
--- Final Output ---
One-Pot Chicken, Rice & Broccoli
- Season bite-size chicken pieces with salt and pepper; sear in a little oil in a pot until lightly browned.
- Add 1 cup rinsed rice and 2 cups broth (or water + salt). Bring to a boil, then cover and simmer on low for 12 minutes.
- Scatter 2 cups small broccoli florets on top, cover, and cook 5-7 more minutes until rice is fluffy and broccoli is tender.
- Rest 5 minutes off heat, fluff, and adjust seasoning. Optional: stir in a knob of butter or a splash of soy.
Restricciones gramaticales (Lark): Restringir las salidas de la herramienta
GPT-5 ahora admite gramática libre de contexto (CFG) para garantizar que los formatos de salida estén estrictamente controlados.
Al aplicar una gramática, como SQL o un lenguaje específico de dominio (DSL), a sus respuestas, GPT-5 garantiza que los resultados sigan de forma coherente la estructura requerida. CFG es especialmente importante para los procesos automatizados y los flujos de trabajo de alto riesgo.
GPT-5 puede utilizar gramáticas definidas en formatos como Lark para restringir los resultados de la herramienta durante la generación. Este enfoque de decodificación restringida mejora la fiabilidad al evitar la deriva de formato y garantizar la coherencia estructural.
Ahora escribiremos el código en el que el modelo selecciona una herramienta y genera ÚNICAMENTE una expresión aritmética gramaticalmente válida; a continuación, esta expresión se evalúa en Python, el resultado se devuelve a la conversación y la respuesta final se presenta de forma clara en lenguaje natural.
En este código de ejemplo, tenemos:
- Inicialicé el cliente OpenAI y definí una herramienta personalizada
math_solverque debe generar ÚNICAMENTE una expresión aritmética gramaticalmente válida (Lark CFG). - Inició la conversación con una pregunta matemática en lenguaje natural del usuario.
- Realicé una primera llamada de modelo indicando a GPT-5 que llamara a
math_solvercon una expresión que se ajustara a la gramática. - Localizó la llamada a la herramienta emitida y extrajo la cadena de expresión sin procesar de la carga útil de la herramienta.
- Evaluaste la expresión localmente en un entorno restringido para producir un resultado concreto.
- Devolvió el resultado de la ejecución de la herramienta a la conversación, vinculado a través del enlace original
call_id. - Realizaste una llamada final al modelo para presentar el resultado evaluado de forma clara en lenguaje natural.
from openai import OpenAI
import json
client = OpenAI()
# --- Local fake evaluator ---
def eval_expression(expr: str) -> str:
try:
# Evaluate safely using Python's eval on restricted globals
result = eval(expr, {"__builtins__": {}}, {})
return f"{expr} = {result}"
except Exception as e:
return f"Error evaluating expression: {e}"
# --- Custom tool with grammar constraint ---
tools = [
{
"type": "custom",
"name": "math_solver",
"description": "Solve a math problem by outputting ONLY a valid arithmetic expression.",
"format": {
"type": "grammar",
"syntax": "lark",
"definition": r"""
start: expr
?expr: term
| expr "+" term -> add
| expr "-" term -> sub
?term: factor
| term "*" factor -> mul
| term "/" factor -> div
?factor: NUMBER
| "(" expr ")"
%import common.NUMBER
%ignore " "
"""
},
}
]
# --- User asks ---
msgs = [
{"role": "user", "content": "What is (12 + 8) * 3 minus 5 divided by 5?"}
]
# 1) First model call: GPT-5 must emit a grammar-valid expression
resp = client.responses.create(
model="gpt-5",
tools=tools,
input=msgs,
instructions="Always call the math_solver tool with a grammar-valid arithmetic expression like '(12 + 8) * 3 - 5 / 5'."
)
msgs += resp.output
tool_call = next(
x for x in resp.output
if getattr(x, "type", "") in ("custom_tool_call", "tool_call", "function_call")
)
expr = getattr(tool_call, "input", "") or getattr(tool_call, "arguments", "")
print("\n=== Grammar-Constrained Expression ===")
print(expr)
# 2) Run the local evaluator
tool_result = eval_expression(expr)
print("\n=== Tool Execution Result ===")
print(tool_result)
# 3) Return tool output
msgs.append({
"type": "function_call_output",
"call_id": tool_call.call_id,
"output": tool_result
})
# 4) Final pass: GPT-5 presents answer nicely
final = client.responses.create(
model="gpt-5",
input=msgs,
tools=tools,
instructions="Present the evaluated result clearly in natural language."
)
print("\n=== Final Output ===")
print(final.output_text)
Como puedes ver, el modelo ha seleccionado la herramienta y, a continuación, ha generado una expresión con restricciones gramaticales. Después, se pasa a través de la función Python para generar la respuesta. Al final, tenemos una respuesta adecuada en lenguaje natural.
=== Grammar-Constrained Expression ===
(12 + 8) * 3 - 5 / 5
=== Tool Execution Result ===
(12 + 8) * 3 - 5 / 5 = 59.0
=== Final Output ===
59
Listas de herramientas permitidas: Limita de forma segura lo que puede utilizar el modelo
La configuración « allowed_tools » (Selección de herramientas) te permite restringir el modelo a una selección segura de herramientas de tu kit de herramientas completo. Esto mejora la previsibilidad y evita llamadas a herramientas no deseadas, al tiempo que proporciona al modelo flexibilidad dentro del conjunto permitido.
Puedes permitir que el modelo elija entre las herramientas permitidas o exigirle que utilice una, reflejando los comportamientos de «herramienta forzada» que se observan en otras pilas y alineándote con las mejores prácticas generales para la coordinación de llamadas a herramientas.
Ahora escribiremos el código en el que permitimos una sola herramienta, hacemos que el modelo llame solo a esa herramienta, la ejecutamos, retroalimentamos los resultados y, a continuación, generamos un resumen conciso dirigido al usuario.
Nota: Crea una cuenta gratuita cuenta gratuita en Firecrawl, genera una clave API, guárdala como variable de entorno FIRECRAWL_API_KEY e instala el SDK de Python de Firecrawl utilizando pip install firecrawl-py.
En este código de ejemplo, tenemos:
- Se ha definido un conjunto completo de herramientas con
dummy_web_searchyfirecrawl_search. - Restringí el modelo a
firecrawl_searchsolo a través detool_choice = { type: "allowed_tools", mode: "required", tools: [...] }. - Emitió la primera llamada al modelo, capturó el nombre y los argumentos de la llamada a la herramienta y los imprimió para que fueran visibles.
- Cuando se invoca
firecrawl_search, los argumentos deserializados ejecutan Firecrawl, convierten su respuesta en un diccionario serializable JSON y extraen la carga útil de datos seguros. - Introducí los resultados de la herramienta en la conversación utilizando
function_call_outputvinculado porcall_idy, a continuación, realicé una llamada final al modelo para resumirlo en 3-4 puntos con enlaces Markdown. - Se incluyó una rama alternativa que ejecutaría la herramienta ficticia (aunque la lista de permitidos lo impide en esta ejecución).
- Imprimiste la respuesta final en lenguaje natural.
from openai import OpenAI
from firecrawl import Firecrawl
import json
import os
client = OpenAI()
firecrawl = Firecrawl(api_key=os.environ["FIRECRAWL_API_KEY"])
# --- Full toolset ---
tools = [
{
"type": "function",
"name": "dummy_web_search",
"description": "A fake web search that always returns static dummy results.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"},
"limit": {"type": "integer"}
},
"required": ["query"]
},
},
{
"type": "function",
"name": "firecrawl_search",
"description": "Perform a real web search using Firecrawl.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"},
"limit": {"type": "integer"}
},
"required": ["query"]
},
},
]
# --- Dummy implementation ---
def dummy_web_search(query, limit=3):
return {
"query": query,
"results": [f"[Dummy] Result {i+1} for '{query}'" for i in range(limit)]
}
# --- User asks ---
messages = [
{"role": "user", "content": "Find me the latest info about the stock market."}
]
# --- Restrict to Firecrawl only ---
resp = client.responses.create(
model="gpt-5",
tools=tools,
input=messages,
instructions="Only the firecrawl_search tool is allowed. Do not use dummy_web_search.",
tool_choice={
"type": "allowed_tools",
"mode": "required", # force Firecrawl
"tools": [{"type": "function", "name": "firecrawl_search"}],
},
)
for item in resp.output:
if getattr(item, "type", "") in ("function_call", "tool_call"):
print("\n--- Tool Call ---")
print("Tool name:", item.name)
print("Arguments:", item.arguments)
if item.name == "firecrawl_search":
args = json.loads(item.arguments)
# Firecrawl returns a SearchData object → convert it
results_obj = firecrawl.search(
query=args["query"],
limit=args.get("limit", 3),
)
# 🔥 Convert to JSON-serializable dict
if hasattr(results_obj, "to_dict"):
results = results_obj.to_dict()
elif hasattr(results_obj, "dict"):
results = results_obj.dict()
else:
results = json.loads(results_obj.json()) if hasattr(results_obj, "json") else results_obj
print("\n--- Firecrawl Raw Results ---")
print(json.dumps(results, indent=2)[:500])
# ✅ Extract only the data portion for summarization
safe_results = results.get("data", results)
# Feed back to GPT
messages += resp.output
messages.append({
"type": "function_call_output",
"call_id": item.call_id,
"output": json.dumps(safe_results) # now safe
})
# Final pass
final = client.responses.create(
model="gpt-5",
tools=tools,
input=messages,
instructions="Summarize the Firecrawl search results into 3-4 bullet points with clickable [Title](URL) links."
)
print("\n--- Final Natural Language Answer ---")
print(final.output_text)
elif item.name == "dummy_web_search":
args = json.loads(item.arguments)
results = dummy_web_search(args["query"], args.get("limit", 3))
print("\n--- Dummy Web Search Results ---")
print(json.dumps(results, indent=2))
Ha seleccionado la búsqueda Firecrawl y, utilizando esa búsqueda, ha generado la respuesta final en formato Markdown.

Preámbulos: Indica al modelo cómo llamar a las herramientas
Los preámbulos son breves explicaciones que el modelo genera antes de invocar una herramienta, aclarando el motivo de la llamada. Mejoran la transparencia, generan confianza en los usuarios y aumentan la claridad en la depuración de errores en flujos de trabajo complejos. Puedes habilitarlos utilizando una instrucción sencilla como «explicar antes de llamar a una herramienta», normalmente sin añadir una latencia apreciable.
Ahora escribiremos el código en el que el modelo primero genera una breve línea «Preámbulo:» que explica por qué llama a una herramienta, luego llama a la herramienta, tú la ejecutas localmente, devuelve el resultado y el modelo produce una respuesta final clara.
En este código de ejemplo, tenemos:
- Inicialicé el cliente OpenAI y definí una herramienta de función de tipo estricto (
medical_advice) con JSON Schema. - Se ha añadido una instrucción del sistema que indica al modelo que genere un mensaje de «
“Preamble:”» (Aviso de llamada a la herramienta) de una línea antes de cualquier llamada a la herramienta. - Inicia la conversación con una pregunta sobre los síntomas del usuario.
- Realizó la primera llamada al modelo para obtener tanto el preámbulo como la llamada a la herramienta con sus argumentos.
- Extraje y ejecuté la herramienta localmente para generar recomendaciones.
- Devolvió el resultado de la herramienta al modelo, vinculado a través de
call_id. - Se realizó una llamada al modelo final para que GPT-5 presentara el resultado como una respuesta concisa y fácil de usar.
from openai import OpenAI
import json
import random
client = OpenAI()
# --- Fake tool implementation ---
def medical_advice(symptom: str):
remedies = {
"headache": "You can take acetaminophen (paracetamol) or ibuprofen, rest in a quiet room, and stay hydrated.",
"cough": "Drink warm fluids, use honey in tea, and consider over-the-counter cough syrup.",
"fever": "Use acetaminophen to reduce fever, stay hydrated, and rest. See a doctor if >39°C.",
}
return {"advice": remedies.get(symptom.lower(), "Please consult a healthcare provider for guidance.")}
# --- Tool definition ---
tools = [{
"type": "function",
"name": "medical_advice",
"description": "Provide safe, general over-the-counter advice for common symptoms.",
"parameters": {
"type": "object",
"properties": {"symptom": {"type": "string"}},
"required": ["symptom"],
"additionalProperties": False
},
"strict": True,
}]
# --- Messages (system preamble instruction) ---
messages = [
{"role": "system", "content": "Before you call a tool, explain why you are calling it in ONE short sentence prefixed with 'Preamble:'."},
{"role": "user", "content": "What should I take for a headache?"}
]
# 1) First call: expect preamble + tool call
resp = client.responses.create(model="gpt-5", input=messages, tools=tools)
print("=== First Response ===")
for item in resp.output:
t = getattr(item, "type", None)
if t == "message":
# Extract just the model's text
content = getattr(item, "content", None)
text = None
if isinstance(content, list):
text = "".join([c.text for c in content if hasattr(c, "text")])
elif content:
text = str(content)
if text:
# ✅ Only print once
print(text)
if t in ("function_call", "tool_call", "custom_tool_call"):
print("Tool:", getattr(item, "name", None))
print("Args:", getattr(item, "arguments", None))
# Extract tool call
tool_call = next(x for x in resp.output if getattr(x, "type", None) in ("function_call","tool_call","custom_tool_call"))
messages += resp.output
# 2) Execute tool locally
args = json.loads(getattr(tool_call, "arguments", "{}"))
symptom = args.get("symptom", "")
tool_result = medical_advice(symptom)
# 3) Return tool result
messages.append({
"type": "function_call_output",
"call_id": tool_call.call_id,
"output": json.dumps(tool_result)
})
# 4) Final model call → natural answer
final = client.responses.create(model="gpt-5", input=messages, tools=tools)
print("\n=== Final Answer ===")
print(final.output_text)
Puedes ver que, antes de llamar a la herramienta, se proporciona una explicación de por qué se llama a la herramienta. Esto es bueno para la observabilidad y la depuración.

Resumen
GPT-5 es el modelo más avanzado de OpenAI hasta la fecha, que destaca especialmente en codificación y flujos de trabajo basados en agentes. Sus últimas funciones API permiten el desarrollo sencillo de sistemas de nivel de producción de principio a fin.
En este tutorial, has aprendido a:
- Devuelve resultados estructurados utilizando herramientas de funciones y esquemas JSON para una automatización descendente fiable.
- Habilita la ejecución de formato libre con herramientas personalizadas (texto sin formato), lo que permite que el modelo genere código, SQL, scripts de terminal y archivos CSV más allá de las simples llamadas JSON.
- Formatos restringidos que utilizan restricciones gramaticales de Lark cuando la precisión es crucial, como en matemáticas, SQL o lenguajes específicos de dominio (DSL).
- Restringe el acceso a las herramientas con listas de permitidos (o imponiendo el uso de una única herramienta) para mejorar la seguridad, el control y el determinismo.
- Mejora la transparencia con breves preámbulos, de modo que el modelo explique por qué está llamando a una herramienta específica, lo que facilita la observabilidad y la depuración.
Para obtener más información sobre lo que puedes hacer con las diversas herramientas de OpenAI, te recomiendo que realices nuestro programa de formación OpenAI Fundamentals y cursos Trabajar con la API de OpenAI.

Soy un científico de datos certificado que disfruta creando aplicaciones de aprendizaje automático y escribiendo blogs sobre ciencia de datos. Actualmente me centro en la creación de contenidos, la edición y el trabajo con grandes modelos lingüísticos.





