Decorador @tool para crear herramientas
El decorador @tool representa la forma moderna y recomendada de crear herramientas personalizadas en LangChain 0.3. Este enfoque simplifica significativamente el proceso de desarrollo al permitir que cualquier función Python se convierta automáticamente en una herramienta utilizable por los modelos de lenguaje.
La principal ventaja del decorador @tool
es su capacidad para inferir automáticamente los metadatos necesarios directamente del código Python. Esto incluye el nombre de la herramienta, su descripción y el esquema de argumentos, eliminando la necesidad de definir manualmente estas especificaciones como ocurría con enfoques anteriores.
Importación y uso básico
Para utilizar el decorador, debemos importarlo desde el módulo correcto de LangChain:
from langchain_core.tools import tool
Una vez importado, podemos transformar cualquier función en una herramienta simplemente añadiendo el decorador:
@tool
def calculadora_simple(a: int, b: int, operacion: str) -> int:
"""Realiza operaciones matemáticas básicas entre dos números.
Args:
a: Primer número
b: Segundo número
operacion: Tipo de operación ('suma', 'resta', 'multiplicacion', 'division')
"""
if operacion == "suma":
return a + b
elif operacion == "resta":
return a - b
elif operacion == "multiplicacion":
return a * b
elif operacion == "division":
if b != 0:
return a // b
else:
raise ValueError("No se puede dividir por cero")
else:
raise ValueError("Operación no válida")
Inferencia automática de metadatos
El decorador @tool
utiliza introspección de Python para extraer automáticamente la información necesaria:
- Nombre de la herramienta: Se deriva del nombre de la función (
calculadora_simple
) - Descripción: Se extrae de la primera línea del docstring
- Esquema de argumentos: Se construye a partir de los type hints y la documentación de parámetros
Podemos verificar cómo se han inferido estos metadatos:
print(f"Nombre: {calculadora_simple.name}")
print(f"Descripción: {calculadora_simple.description}")
print(f"Esquema: {calculadora_simple.args_schema.schema()}")
Ejemplo práctico: herramienta de formateo de texto
Veamos otro ejemplo que demuestra el manejo de tipos más complejos:
from typing import List
@tool
def formatear_texto(texto: str, estilo: str, mayusculas: bool = False) -> str:
"""Aplica diferentes estilos de formato a un texto.
Args:
texto: El texto a formatear
estilo: Estilo a aplicar ('titulo', 'snake_case', 'camel_case')
mayusculas: Si convertir todo a mayúsculas
"""
if estilo == "titulo":
resultado = texto.title()
elif estilo == "snake_case":
resultado = texto.lower().replace(" ", "_")
elif estilo == "camel_case":
palabras = texto.split()
resultado = palabras[0].lower() + "".join(word.capitalize() for word in palabras[1:])
else:
resultado = texto
return resultado.upper() if mayusculas else resultado
Integración con modelos de lenguaje
Una vez creadas las herramientas, podemos integrarlas directamente con un modelo de chat:
from langchain_openai import ChatOpenAI
# Inicializar el modelo
llm = ChatOpenAI(model="gpt-4", temperature=0)
# Vincular las herramientas al modelo
llm_con_herramientas = llm.bind_tools([calculadora_simple, formatear_texto])
# Usar las herramientas
respuesta = llm_con_herramientas.invoke("Calcula 15 + 27 y luego formatea el resultado como título")
Ventajas del decorador @tool
El uso del decorador @tool
ofrece múltiples beneficios técnicos:
- Simplicidad: Convierte funciones Python estándar en herramientas sin código adicional
- Mantenibilidad: Los cambios en la función se reflejan automáticamente en la herramienta
- Consistencia: Garantiza que el esquema de la herramienta coincida con la implementación
- Legibilidad: El código es más limpio y fácil de entender
Consideraciones importantes
Al utilizar el decorador @tool
, es fundamental seguir ciertas buenas prácticas:
- Type hints obligatorios: Todos los parámetros deben tener anotaciones de tipo
- Docstrings descriptivos: La documentación debe ser clara y específica
- Manejo de errores: Incluir validaciones y excepciones apropiadas
- Valores por defecto: Utilizar parámetros opcionales cuando sea apropiado
El decorador también maneja automáticamente la conversión entre los tipos de Python y los esquemas JSON que entienden los modelos de lenguaje, eliminando la complejidad de esta traducción manual.
Validación automática de esquemas y tipos
Guarda tu progreso
Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.
Más de 25.000 desarrolladores ya confían en CertiDevs
Una de las características más valiosas del decorador @tool
es su capacidad para realizar validación automática de los datos de entrada antes de que lleguen a la función. Esta validación se basa en los type hints de Python y utiliza Pydantic internamente para garantizar que los argumentos cumplan con los tipos esperados.
Mecanismo de validación
Cuando un modelo de lenguaje invoca una herramienta creada con @tool
, LangChain intercepta automáticamente los argumentos y los valida contra el esquema inferido. Si los datos no coinciden con los tipos esperados, se genera una excepción antes de ejecutar la función:
@tool
def procesar_numeros(numeros: List[int], multiplicador: float) -> List[float]:
"""Multiplica una lista de números enteros por un factor.
Args:
numeros: Lista de números enteros a procesar
multiplicador: Factor por el que multiplicar cada número
"""
return [num * multiplicador for num in numeros]
# Ejemplo de uso correcto
resultado = procesar_numeros.invoke({"numeros": [1, 2, 3], "multiplicador": 2.5})
print(resultado) # [2.5, 5.0, 7.5]
Si intentamos pasar datos incorrectos, la validación detectará el error:
# Esto generará un error de validación
try:
procesar_numeros.invoke({"numeros": ["a", "b", "c"], "multiplicador": 2.5})
except Exception as e:
print(f"Error de validación: {e}")
Validación de tipos complejos
El sistema de validación maneja tipos complejos de Python de forma sofisticada. Veamos un ejemplo con tipos más elaborados:
from typing import Dict, Optional, Union
from datetime import datetime
@tool
def analizar_datos_usuario(
usuario_id: int,
metadatos: Dict[str, Union[str, int]],
fecha_limite: Optional[str] = None
) -> Dict[str, any]:
"""Analiza datos de usuario con validación de tipos complejos.
Args:
usuario_id: Identificador único del usuario
metadatos: Diccionario con información adicional del usuario
fecha_limite: Fecha límite en formato ISO (opcional)
"""
resultado = {
"usuario_id": usuario_id,
"metadatos_procesados": len(metadatos),
"claves_disponibles": list(metadatos.keys())
}
if fecha_limite:
try:
fecha_obj = datetime.fromisoformat(fecha_limite)
resultado["fecha_valida"] = True
resultado["fecha_procesada"] = fecha_obj.strftime("%Y-%m-%d")
except ValueError:
resultado["fecha_valida"] = False
return resultado
Esquemas JSON generados automáticamente
La validación funciona porque el decorador @tool
convierte automáticamente los type hints de Python en esquemas JSON Schema que los modelos de lenguaje pueden interpretar. Podemos examinar este esquema:
import json
# Inspeccionar el esquema generado
esquema = analizar_datos_usuario.args_schema.schema()
print(json.dumps(esquema, indent=2))
Este esquema incluye información detallada sobre:
- Tipos de datos esperados para cada parámetro
- Propiedades requeridas versus opcionales
- Restricciones de formato para tipos específicos
- Descripciones extraídas del docstring
Validación con restricciones personalizadas
Aunque el decorador @tool
no permite validaciones complejas directamente en los type hints, podemos combinar la validación automática con validaciones manuales dentro de la función:
@tool
def crear_usuario(
nombre: str,
edad: int,
email: str,
activo: bool = True
) -> Dict[str, any]:
"""Crea un nuevo usuario con validaciones adicionales.
Args:
nombre: Nombre completo del usuario (mínimo 2 caracteres)
edad: Edad del usuario (debe ser mayor a 0 y menor a 150)
email: Dirección de correo electrónico válida
activo: Estado inicial del usuario
"""
# Validaciones adicionales después de la validación automática de tipos
if len(nombre.strip()) < 2:
raise ValueError("El nombre debe tener al menos 2 caracteres")
if not (0 < edad < 150):
raise ValueError("La edad debe estar entre 1 y 149 años")
if "@" not in email or "." not in email:
raise ValueError("El email debe tener un formato válido")
return {
"nombre": nombre.strip(),
"edad": edad,
"email": email.lower(),
"activo": activo,
"id_generado": hash(f"{nombre}{email}") % 10000
}
Manejo de errores de validación
Cuando la validación automática falla, LangChain proporciona mensajes de error descriptivos que ayudan tanto al desarrollador como al modelo de lenguaje a entender qué salió mal:
@tool
def calcular_estadisticas(datos: List[float], precision: int = 2) -> Dict[str, float]:
"""Calcula estadísticas básicas de una lista de números.
Args:
datos: Lista de números para analizar
precision: Número de decimales en el resultado
"""
if not datos:
raise ValueError("La lista de datos no puede estar vacía")
promedio = sum(datos) / len(datos)
maximo = max(datos)
minimo = min(datos)
return {
"promedio": round(promedio, precision),
"maximo": round(maximo, precision),
"minimo": round(minimo, precision),
"cantidad": len(datos)
}
# Ejemplo de manejo de errores
try:
# Esto fallará en la validación automática (string en lugar de lista)
calcular_estadisticas.invoke({"datos": "no es una lista", "precision": 2})
except Exception as e:
print(f"Error capturado: {type(e).__name__}: {e}")
Beneficios de la validación automática
La validación automática de esquemas y tipos proporciona ventajas significativas:
- Seguridad: Previene errores de runtime por tipos incorrectos
- Consistencia: Garantiza que los datos siempre cumplan el contrato esperado
- Debugging: Facilita la identificación de problemas en la integración
- Documentación: El esquema sirve como documentación viva de la API
Esta validación automática convierte las herramientas creadas con @tool
en interfaces robustas que pueden manejar de forma segura las invocaciones desde modelos de lenguaje, reduciendo significativamente los errores de integración y mejorando la confiabilidad del sistema completo.
Aprendizajes de esta lección
- Comprender el uso del decorador @tool para transformar funciones Python en herramientas.
- Aprender cómo se infieren automáticamente los metadatos y esquemas de argumentos.
- Conocer la integración de herramientas con modelos de lenguaje en LangChain.
- Entender el mecanismo de validación automática de tipos y esquemas usando Pydantic.
- Saber cómo manejar errores y realizar validaciones adicionales en las herramientas.
Completa LangChain y certifícate
Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.
Asistente IA
Resuelve dudas al instante
Ejercicios
Practica con proyectos reales
Certificados
Valida tus conocimientos
Más de 25.000 desarrolladores ya se han certificado con CertiDevs