Método @tool

Intermedio
LangChain
LangChain
Actualizado: 08/07/2025

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

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.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

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

⭐⭐⭐⭐⭐
4.9/5 valoración