Constructor de Herramientas para Agentes
Las herramientas son como los agentes de IA interactúan con el mundo. Una herramienta bien diseñada marca la diferencia entre un agente que funciona y uno que alucina, falla silenciosamente o cuesta 10 veces más tokens de lo necesario.
Esta habilidad cubre el diseño de herramientas desde el esquema hasta el manejo de errores. Mejores prácticas de JSON Schema, redacción de descripciones que realmente ayuden al LLM, validación y el estándar MCP emergente que se está convirtiendo en la lengua franca para las herramientas de IA.
Perspectiva clave: Las descripciones de las herramientas son más importantes que las implementaciones de las herramientas. El LLM nunca ve tu código, solo ve el esquema y la descripción.
Principios
- La calidad de la descripción > la calidad de la implementación para la precisión del LLM
- Apunta a menos de 20 herramientas, más causa confusión
- Cada herramienta necesita manejo explícito de errores: los fallos silenciosos envenenan a los agentes
- Devuelve cadenas de texto, no objetos: los LLM procesan texto
- Puertas de validación antes de la ejecución: rechazar, corregir o escalar, nunca fallar silenciosamente
- Prueba las herramientas con el LLM, no solo con pruebas unitarias
Capacidades
- herramientas-para-agentes
- llamada-a-funciones
- diseño-de-esquemas-de-herramientas
- herramientas-mcp
- validación-de-herramientas
- manejo-de-errores-de-herramientas
Alcance
- coordinación-multi-agente → orquestación-multi-agente
- memoria-del-agente → sistemas-de-memoria-del-agente
- diseño-de-api → diseñador-de-api
- generación-de-consultas-llm → ingeniería-de-consultas
Herramientas
Estándares
- JSON Schema - Cuándo: En todas las definiciones de herramientas Nota: El formato universal para esquemas de herramientas
- MCP (Model Context Protocol) - Cuándo: Al construir herramientas reutilizables y multiplataforma Nota: El estándar abierto de Anthropic, ampliamente adoptado
Frameworks
- SDK de Anthropic - Cuándo: Agentes basados en Claude Nota: El ejecutor beta de herramientas maneja la mayor parte de la complejidad
- Funciones de OpenAI - Cuándo: Agentes basados en OpenAI Nota: Usa el modo estricto para garantizar el cumplimiento del esquema
- SDK de Vercel AI - Cuándo: Manejo de herramientas con múltiples proveedores Nota: Abstrae las diferencias entre proveedores
- Herramientas de LangChain - Cuándo: Agentes basados en LangChain Nota: Convierte herramientas MCP al formato LangChain
Patrones
Diseño de Esquemas de Herramientas
Crear esquemas JSON Schema claros y sin ambigüedades para herramientas
Cuándo usarlo: Al definir cualquier herramienta nueva para un agente
MEJORES PRÁCTICAS DE ESQUEMAS DE HERRAMIENTAS:
1. Descripciones Detalladas (Lo Más Importante)
MAL - Demasiado vago:
{
"name": "obtener_precio_accion",
"description": "Obtiene el precio de una acción",
"input_schema": {
"type": "object",
"properties": {
"ticker": {"type": "string"}
}
}
}
BIEN - Completo:
{
"name": "obtener_precio_accion",
"description": "Recupera el precio actual de la acción para un símbolo de ticker dado. El símbolo de ticker debe ser un símbolo válido para una empresa que cotiza en bolsa en una bolsa de valores importante de EE. UU. como NYSE o NASDAQ. Devuelve el último precio de negociación en USD. Úsalo cuando el usuario pregunte sobre precios de acciones actuales o recientes. NO proporciona datos históricos, información de la empresa ni predicciones.",
"input_schema": {
"type": "object",
"properties": {
"ticker": {
"type": "string",
"description": "El símbolo de ticker de la acción, por ejemplo, AAPL para Apple Inc."
}
},
"required": ["ticker"]
}
}
2. Descripciones de Parámetros
Cada parámetro necesita:
- Qué es
- Formato esperado
- Valor de ejemplo
- Casos límite/limitaciones
{
"ubicacion": {
"type": "string",
"description": "Ciudad y estado/país. Formato: 'Ciudad, Estado' para EE. UU. (por ejemplo, 'San Francisco, CA') o 'Ciudad, País' para internacional (por ejemplo, 'Tokio, Japón'). No uses códigos postales ni coordenadas."
},
"unidad": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Unidad de temperatura. Por defecto, se usa la configuración regional del usuario si no se especifica. Usa 'fahrenheit' para usuarios de EE. UU., 'celsius' para otros."
}
}
3. Usa Enumeraciones Cuando Sea Posible
Las enumeraciones restringen al LLM a valores válidos:
"prioridad": {
"type": "string",
"enum": ["baja", "media", "alta", "crítica"],
"description": "Nivel de prioridad de la tarea"
}
"accion": {
"type": "string",
"enum": ["crear", "leer", "actualizar", "eliminar"],
"description": "La operación CRUD a realizar"
}
4. Requerido vs. Opcional
Sé explícito sobre lo que se requiere:
{
"type": "object",
"properties": {
"consulta": {...}, // Requerido
"limite": {...}, // Opcional con valor por defecto
"desplazamiento": {...} // Opcional
},
"required": ["consulta"],
"additionalProperties": false // Modo estricto
}
Herramienta con Ejemplos de Entrada
Usar ejemplos para guiar el uso de herramientas por parte del LLM
Cuándo usarlo: Herramientas complejas con objetos anidados o entradas sensibles al formato
EJEMPLOS DE USO DE HERRAMIENTAS (Característica Beta de Anthropic):
Los ejemplos muestran a Claude patrones concretos que los esquemas no pueden expresar.
Mejora la precisión del 72% al 90% en operaciones complejas.
{ "name": "crear_evento_calendario", "description": "Crea un evento de calendario con asistentes y recordatorios opcionales", "input_schema": { "type": "object", "properties": { "titulo": {"type": "string", "description": "Título del evento"}, "hora_inicio": { "type": "string", "description": "Fecha y hora en formato ISO 8601, por ejemplo, 2024-03-15T14:00:00Z" }, "duracion_minutos": {"type": "integer", "description": "Duración del evento"}, "asistentes": { "type": "array", "items": {"type": "string"}, "description": "Direcciones de correo electrónico de los asistentes" } }, "required": ["titulo", "hora_inicio", "duracion_minutos"] }, "input_examples": [ { "titulo": "Reunión de Equipo", "hora_inicio": "2024-03-15T09:00:00Z", "duracion_minutos": 30, "asistentes": ["[email protected]", "[email protected]"] }, { "titulo": "Charla Rápida", "hora_inicio": "2024-03-15T14:00:00Z", "duracion_minutos": 15 }, { "titulo": "Revisión de Proyecto", "hora_inicio": "2024-03-15T16:00:00-05:00", "duracion_minutos": 60, "asistentes": ["[email protected]"] } ] }
PRINCIPIOS DE DISEÑO DE EJEMPLOS:
- Usa datos realistas, no marcadores de posición
- Muestra patrones de especificación mínimos, parciales y completos
- Mantén la concisión: 1-5 ejemplos por herramienta
- Enfócate en casos ambiguos
Manejo de Errores de Herramientas
Devolver errores que ayuden al LLM a recuperarse
Cuándo usarlo: Cualquier herramienta que pueda fallar
MEJORES PRÁCTICAS DE MANEJO DE ERRORES:
Devuelve Errores Informativos
MAL:
{"error": "Falló"}
{"error": true}
BIEN:
{
"error": true,
"error_type": "no_encontrado",
"message": "La ubicación 'Atlantis' no se encontró en la base de datos meteorológica. Proporcione un nombre de ciudad real como 'San Francisco, CA'.",
"suggestions": ["San Francisco, CA", "Los Angeles, CA"]
}
Resultado de Herramienta de Anthropic con Error
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "Error: La ubicación 'Atlantis' no se encontró en la base de datos meteorológica. Proporcione un nombre de ciudad real como 'San Francisco, CA'.",
"is_error": true
}
Categorías de Errores a Manejar
1. Errores de Validación de Entrada
- Parámetros requeridos faltantes
- Formato inválido
- Valores fuera de rango
2. Errores de Servicio Externo
- API no disponible
- Límite de tasa excedido
- Tiempo de espera agotado
3. Errores de Lógica de Negocio
- Recurso no encontrado
- Permiso denegado
- Conflicto/duplicado
4. Errores Internos
- Excepciones inesperadas
- Corrupción de datos
Patrón de Implementación
from dataclasses import dataclass
from typing import Union
@dataclass
class ResultadoHerramienta:
exito: bool
contenido: str
tipo_error: str = None
sugerencias: list[str] = None
def a_respuesta(self) -> dict:
if self.exito:
return {"content": self.contenido}
return {
"content": f"Error ({self.tipo_error}): {self.contenido}",
"is_error": True
}
def obtener_clima(ubicacion: str) -> ResultadoHerramienta:
# Validar entrada
if not ubicacion or len(ubicacion) < 2:
return ResultadoHerramienta(
exito=False,
contenido="La ubicación debe tener al menos 2 caracteres",
tipo_error="error_validacion"
)
try:
datos = api_clima.obtener(ubicacion)
return ResultadoHerramienta(
exito=True,
contenido=f"Temperatura: {datos.temp}°F, Condiciones: {datos.condiciones}"
)
except UbicacionNoEncontrada:
return ResultadoHerramienta(
exito=False,
contenido=f"Ubicación '{ubicacion}' no encontrada",
tipo_error="no_encontrado",
sugerencias=api_clima.sugerir_ubicaciones(ubicacion)
)
except ErrorLimiteTasa:
return ResultadoHerramienta(
exito=False,
contenido="Límite de tasa del servicio meteorológico excedido. Inténtalo de nuevo en 60 segundos.",
tipo_error="limite_tasa"
)
except Exception as e:
return ResultadoHerramienta(
exito=False,
contenido=f"Error inesperado: {str(e)}",
tipo_error="error_interno"
)
Patrón de Herramienta MCP
Construir herramientas usando el Protocolo de Contexto de Modelo
Cuándo usarlo: Crear herramientas reutilizables y multiplataforma
IMPLEMENTACIÓN DE HERRAMIENTA MCP:
MCP (Model Context Protocol) es el estándar abierto de Anthropic para
conectar agentes de IA a sistemas externos. Construye una vez, úsalo en todas partes.
Servidor MCP Básico (TypeScript)
import { Server } from "@modelcontextprotocol/sdk/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
const server = new Server({
name: "servidor-clima",
version: "1.0.0"
});
// Definir herramientas
server.setRequestHandler("tools/list", async () => ({
tools: [
{
name: "obtener_clima",
description: "Obtiene el clima actual para una ubicación. Devuelve temperatura, condiciones y humedad. Úsalo para consultas meteorológicas sobre ciudades específicas.",
inputSchema: {
type: "object",
properties: {
ubicacion: {
type: "string",
description: "Ciudad y estado, por ejemplo, 'San Francisco, CA'"
},
unidad: {
type: "string",
enum: ["celsius", "fahrenheit"],
default: "fahrenheit"
}
},
required: ["ubicacion"]
}
}
]
}));
// Manejar llamadas a herramientas
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;
if (name === "obtener_clima") {
try {
const clima = await obtenerClima(args.ubicacion, args.unidad);
return {
content: [
{
type: "text",
text: JSON.stringify(clima)
}
]
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error.message}`
}
],
isError: true
};
}
}
throw new Error(`Herramienta desconocida: ${name}`);
});
// Iniciar servidor
const transport = new StdioServerTransport();
await server.connect(transport);
Beneficios de MCP
- Compatibilidad universal entre proveedores de LLM
- Bibliotecas de herramientas reutilizables
- Soporte de transmisión y transporte SSE
- Observabilidad incorporada
- Controles de acceso a herramientas
Patrón de Ejecutor de Herramientas
Usar ejecutores de herramientas SDK para manejo automático
Cuándo usarlo: Construir bucles de herramientas sin gestión manual
EJECUTOR DE HERRAMIENTAS (SDK Beta de Anthropic):
El ejecutor de herramientas maneja el bucle de llamadas a herramientas automáticamente:
- Ejecuta herramientas cuando Claude las llama
- Gestiona el estado de la conversación
- Maneja reintentos de errores
- Proporciona soporte de transmisión
Ejemplo en Python
import anthropic
from anthropic import beta_tool
client = anthropic.Anthropic()
@beta_tool
def obtener_clima(ubicacion: str, unidad: str = "fahrenheit") -> str:
'''Obtiene el clima actual en una ubicación determinada.
Args:
ubicacion: La ciudad y el estado, por ejemplo, San Francisco, CA
unidad: Unidad de temperatura, ya sea 'celsius' o 'fahrenheit'
'''
# Implementación
return json.dumps({"temperatura": "72°F", "condiciones": "Soleado"})
@beta_tool
def buscar_en_web(consulta: str) -> str:
'''Busca información en la web.
Args:
consulta: La consulta de búsqueda
'''
# Implementación
return json.dumps({"resultados": [...]})
# El ejecutor de herramientas maneja el bucle
runner = client.beta.messages.tool_runner(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[obtener_clima, buscar_en_web],
messages=[
{"role": "user", "content": "¿Cómo está el clima en París?"}
]
)
# Procesar cada mensaje
for message in runner:
print(message.content[0].text)
# O simplemente obtener el resultado final
final = runner.until_done()
TypeScript con Zod
import { Anthropic } from '@anthropic-ai/sdk';
import { betaZodTool } from '@anthropic-ai/sdk/helpers/beta/zod';
import { z } from 'zod';
const anthropic = new Anthropic();
const herramientaClima = betaZodTool({
name: 'obtener_clima',
description: 'Obtiene el clima actual en una ubicación determinada',
inputSchema: z.object({
ubicacion: z.string().describe('Ciudad y estado, por ejemplo, San Francisco, CA'),
unidad: z.enum(['celsius', 'fahrenheit']).default('fahrenheit')
}),
run: async (input) => {
// Entrada con seguridad de tipos
return JSON.stringify({temperatura: '72°F'});
}
});
const runner = anthropic.beta.messages.toolRunner({
model: 'claude-sonnet-4-5',
max_tokens: 1024,
tools: [herramientaClima],
messages: [{ role: 'user', content: '¿Cómo está el clima en París?' }]
});
for await (const message of runner) {
console.log(message.content[0].text);
}
Ejecución Paralela de Herramientas
Ejecutar múltiples herramientas simultáneamente
Cuándo usarlo: Llamadas a herramientas independientes que pueden ejecutarse en paralelo
EJECUCIÓN PARALELA DE HERRAMIENTAS:
Por defecto, Claude puede llamar a múltiples herramientas en una sola respuesta.
Esto reduce drásticamente la latencia para operaciones independientes.
Manejo de Resultados Paralelos
# Claude devuelve múltiples bloques tool_use:
response.content = [
{"type": "text", "text": "Revisaré ambas ubicaciones..."},
{"type": "tool_use", "id": "toolu_01", "name": "obtener_clima",
"input": {"ubicacion": "San Francisco, CA"}},
{"type": "tool_use", "id": "toolu_02", "name": "obtener_clima",
"input": {"ubicacion": "New York, NY"}},
{"type": "tool_use", "id": "toolu_03", "name": "obtener_hora",
"input": {"zona_horaria": "America/Los_Angeles"}},
{"type": "tool_use", "id": "toolu_04", "name": "obtener_hora",
"input": {"zona_horaria": "America/New_York"}},
]
Buenas Prácticas
1. Identifica dependencias: ¿Las herramientas pueden ejecutarse en paralelo?
2. Establece límites: Claude ejecutará hasta ~10 herramientas por turno
3. Agrupa resultados: Procesa las respuestas en el orden de las tool_use
4. Maneja errores parciales: Algunas herramientas fallan, otras tienen éxito