Procesamiento de llamadas a herramientas en su aplicación
Detecte finish_reason tool_calls en la respuesta de la API, extraiga los nombres y argumentos de las funciones, ejecute la función de Python correspondiente y envíe el resultado de vuelta al modelo.
Procesamiento de llamadas a herramientas en su aplicación es una lección gratuita de AI Engineering Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AI Engineering Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AI Engineering Academy incluye 4 lecciones en total.
Partes de esta lección aún no han sido traducidas y se muestran en inglés.
The Tool Call Response Object
When the model decides to call a function, the API response contains a tool_calls list on the message object. Each tool call has a unique id, the function.name to call, and function.arguments — a JSON string of the arguments the model wants to pass. Your application code is responsible for parsing this and executing the function.
from openai import OpenAI
import json
client = OpenAI()
response = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': 'What is the weather in Paris?'}],
tools=tools # defined previously
)
message = response.choices[0].message
if response.choices[0].finish_reason == 'tool_calls':
for tool_call in message.tool_calls:
print('Call ID:', tool_call.id)
print('Function name:', tool_call.function.name)
print('Arguments (JSON string):', tool_call.function.arguments)Parsing Function Arguments
The function.arguments field is a JSON-encoded string, not a Python dict. You must parse it with json.loads(). Always wrap this in a try/except — the model occasionally produces malformed JSON despite schema guidance, and you need to handle that gracefully.
import json
def parse_tool_call(tool_call) -> dict:
'''Parse a tool call's arguments from JSON string to dict.'''
try:
args = json.loads(tool_call.function.arguments)
return args
except json.JSONDecodeError as e:
print(f'Failed to parse arguments for {tool_call.function.name}: {e}')
print(f'Raw arguments: {tool_call.function.arguments}')
return {}
# Usage
tool_call = message.tool_calls[0]
args = parse_tool_call(tool_call)
print('Parsed args:', args) # {'location': 'Paris', 'unit': 'celsius'}Dispatching to the Right Function
Use the function.name to dispatch to the correct Python function. A clean pattern is to keep your functions in a dictionary mapping name to callable. This avoids brittle if/elif chains and makes it easy to add new tools later.
def get_current_weather(location: str, unit: str = 'celsius') -> str:
# Real implementation calls a weather API
return f'{location}: 18{chr(176)}C, partly cloudy'
def create_calendar_event(title: str, start_time: str, duration_minutes: int, **kwargs) -> str:
return f'Event created: {title} at {start_time} for {duration_minutes} minutes'
# Tool registry: maps function names to callables
TOOL_REGISTRY = {
'get_current_weather': get_current_weather,
'create_calendar_event': create_calendar_event
}
def execute_tool_call(tool_call) -> str:
name = tool_call.function.name
args = parse_tool_call(tool_call)
if name not in TOOL_REGISTRY:
return f'Unknown function: {name}'
try:
result = TOOL_REGISTRY[name](**args)
return str(result)
except Exception as e:
return f'Function {name} raised an error: {str(e)}'Sending Results Back to the Model
After executing the function, you must send the result back to the model in a follow-up API call. Add the assistant's message (which contains the tool_calls) to the conversation, then add a new message with role='tool', the tool_call_id, and the function result as content. Then call the API again.
def run_tool_call_loop(messages: list, tools: list) -> str:
response = client.chat.completions.create(
model='gpt-4o',
messages=messages,
tools=tools
)
message = response.choices[0].message
messages.append(message) # Add assistant's tool_calls message
# Execute all tool calls and collect results
for tool_call in (message.tool_calls or []):
result = execute_tool_call(tool_call)
# Add each tool result as a 'tool' role message
messages.append({
'role': 'tool',
'tool_call_id': tool_call.id,
'content': result
})
# Second API call with results appended
final_response = client.chat.completions.create(
model='gpt-4o',
messages=messages,
tools=tools
)
return final_response.choices[0].message.contentThe Full Conversation Turn
A complete tool call interaction involves four messages in the conversation history: the user's message, the assistant's message requesting a tool call, the tool result message, and the assistant's final response incorporating the result. Understanding this structure is essential for building multi-turn tool-using assistants.
# The full message history for a tool-calling conversation:
conversation = [
{'role': 'user', 'content': 'What is the weather in Tokyo?'},
# Model requests a tool call (added by run_tool_call_loop)
# {'role': 'assistant', 'content': None, 'tool_calls': [...]},
# Application sends tool result back
# {'role': 'tool', 'tool_call_id': 'call_abc123', 'content': 'Tokyo: 22C, sunny'},
# Model produces final human-readable response
# {'role': 'assistant', 'content': 'The weather in Tokyo is 22 degrees Celsius and sunny.'}
]
final_answer = run_tool_call_loop(
[{'role': 'user', 'content': 'What is the weather in Tokyo?'}],
tools
)
print(final_answer)Handling the Case Where No Tool Is Called
Sometimes the model answers directly without calling any tool — finish_reason will be 'stop' rather than 'tool_calls'. Always check for this case before trying to process tool calls. A robust implementation handles both branches cleanly.
def smart_complete(user_message: str) -> str:
messages = [{'role': 'user', 'content': user_message}]
response = client.chat.completions.create(
model='gpt-4o',
messages=messages,
tools=tools
)
choice = response.choices[0]
if choice.finish_reason == 'stop':
# Model answered directly without calling a tool
return choice.message.content
elif choice.finish_reason == 'tool_calls':
# Process tool calls
messages.append(choice.message)
for tc in choice.message.tool_calls:
result = execute_tool_call(tc)
messages.append({'role': 'tool', 'tool_call_id': tc.id, 'content': result})
# Get final answer
final = client.chat.completions.create(model='gpt-4o', messages=messages)
return final.choices[0].message.content
return 'Unexpected finish reason: ' + choice.finish_reasonValidating Arguments Before Execution
The model may occasionally pass arguments that fail business logic validation — a negative duration, an invalid email, or a date in the past. Validate arguments before calling the real function and return a descriptive error string if validation fails. The model can then correct its arguments in the next turn.
from pydantic import BaseModel, ValidationError
from datetime import datetime
class CreateEventArgs(BaseModel):
title: str
start_time: str # ISO 8601
duration_minutes: int
def safe_create_event(tool_call) -> str:
try:
raw_args = json.loads(tool_call.function.arguments)
validated = CreateEventArgs(**raw_args)
# Additional business rule
event_time = datetime.fromisoformat(validated.start_time)
if event_time < datetime.now():
return 'Error: start_time must be in the future.'
return create_calendar_event(**validated.dict())
except ValidationError as e:
return f'Invalid arguments: {e}'Logging Tool Call Interactions
Always log tool call interactions for debugging and analytics. Log the function name, arguments, result, and execution time. This data helps you identify which tools are called most frequently, which fail, and what argument patterns the model produces — invaluable for improving your schemas and function implementations.
import time
import logging
logger = logging.getLogger('tool_calls')
def logged_execute(tool_call) -> str:
name = tool_call.function.name
args_str = tool_call.function.arguments
start = time.time()
result = execute_tool_call(tool_call)
elapsed = time.time() - start
logger.info(
'Tool call executed',
extra={
'function': name,
'arguments': args_str,
'result_length': len(result),
'elapsed_ms': round(elapsed * 1000)
}
)
return resultTool Call Security Considerations
Never execute arbitrary functions based on model output without validation. Always whitelist the exact function names in your TOOL_REGISTRY, validate all arguments, and check authorization before executing actions. The model is an untrusted caller — a malicious prompt could try to invoke destructive functions if your dispatch logic is too permissive.
- Only allow functions explicitly listed in TOOL_REGISTRY
- Validate inputs with Pydantic before execution
- Require authorization for write/delete operations
Returning Rich Structured Results
Tool results don't have to be plain strings. You can return JSON-formatted data, tables, or summaries. Returning structured data as JSON lets the model parse and reference specific fields in its final answer. For large results, return a summary with key facts rather than dumping all raw data into the context.
def get_order_status(order_id: str) -> str:
# Fetch from real database
order = {'id': order_id, 'status': 'shipped', 'estimated_delivery': '2024-03-15', 'carrier': 'FedEx', 'tracking': 'FX123456'}
# Return concise summary, not raw DB record
return (
f'Order {order_id}: Status={order["status"]}, '
f'Estimated delivery: {order["estimated_delivery"]}, '
f'Carrier: {order["carrier"]}, Tracking: {order["tracking"]}'
)Multi-Turn Tool-Using Conversations
A powerful pattern is a multi-turn conversation where the model calls tools across multiple user messages, building up context. Always maintain the full conversation history including past tool calls and results so the model can reference previous answers without re-calling tools unnecessarily.
Quick Check
Test your understanding of processing tool calls in your application.
Lesson Recap
In this lesson you learned: tool call arguments arrive as a JSON string that must be parsed with json.loads(), a TOOL_REGISTRY dictionary maps function names to callables for clean dispatch, and results go back to the model as role='tool' messages with matching tool_call_ids. Next up we handle the case where the model calls multiple functions simultaneously with parallel function calling.
Preguntas frecuentes
¿La lección «Procesamiento de llamadas a herramientas en su aplicación» es gratis?
Sí — el texto completo de «Procesamiento de llamadas a herramientas en su aplicación» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AI Engineering Academy, actualiza a CoddyKit PRO. El curso de AI Engineering Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Procesamiento de llamadas a herramientas en su aplicación»?
Detecte finish_reason tool_calls en la respuesta de la API, extraiga los nombres y argumentos de las funciones, ejecute la función de Python correspondiente y envíe el resultado de vuelta al modelo. Practicas AI Engineering Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar AI Engineering Academy?
No se requiere experiencia previa. AI Engineering Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Procesamiento de llamadas a herramientas en su aplicación»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de AI Engineering Academy?
Sí. Cada lección de AI Engineering Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Definición de esquemas de funciones para la API
- Procesamiento de llamadas a herramientas en su aplicación
- Llamadas paralelas a funciones
- Creación de una interfaz de bases de datos en lenguaje natural