346 lines
9.5 KiB
Python
346 lines
9.5 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
QUICK START: Cómo crear tu primera herramienta en 5 minutos
|
||
|
||
Este archivo es un tutorial paso a paso que puedes ejecutar.
|
||
"""
|
||
|
||
# ============================================================================
|
||
# PASO 1: Entender la estructura
|
||
# ============================================================================
|
||
|
||
"""
|
||
El patrón Registry funciona así:
|
||
|
||
1. DEFINIR una herramienta (en tools.py):
|
||
- Crear una clase que herede de BaseTool
|
||
- Implementar: name, description, args_schema, invoke()
|
||
|
||
2. REGISTRAR la herramienta:
|
||
- Crear ToolRegistry()
|
||
- Llamar registry.register(MiHerramienta())
|
||
|
||
3. USAR las herramientas:
|
||
- Pasar registry.get_all_tools_as_langchain() al Agent
|
||
- El Agent ahora puede usar tus tools
|
||
"""
|
||
|
||
# ============================================================================
|
||
# PASO 2: Crear tu primera herramienta
|
||
# ============================================================================
|
||
|
||
"""
|
||
Abre: src/naliiabot/bot/tools/tools.py
|
||
|
||
Y pega este código (reemplaza el contenido):
|
||
"""
|
||
|
||
EJEMPLO_HERRAMIENTA = '''
|
||
"""
|
||
Implementaciones concretas de herramientas del agente.
|
||
"""
|
||
|
||
from typing import Any, Dict
|
||
from .tool_registry import BaseTool
|
||
|
||
|
||
class ObtenerHoraActualTool(BaseTool):
|
||
"""
|
||
Herramienta simple que retorna la hora actual.
|
||
|
||
El LLM puede usar esto para responder: "¿Qué hora es?"
|
||
"""
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "obtener_hora"
|
||
|
||
@property
|
||
def description(self) -> str:
|
||
return "Retorna la hora actual del sistema."
|
||
|
||
@property
|
||
def args_schema(self) -> Dict[str, Any]:
|
||
return {
|
||
"type": "object",
|
||
"properties": {
|
||
"formato": {
|
||
"type": "string",
|
||
"enum": ["12h", "24h"],
|
||
"description": "Formato de hora deseado",
|
||
"default": "24h"
|
||
}
|
||
},
|
||
"required": []
|
||
}
|
||
|
||
def invoke(self, **kwargs) -> str:
|
||
from datetime import datetime
|
||
|
||
formato = kwargs.get("formato", "24h")
|
||
ahora = datetime.now()
|
||
|
||
if formato == "12h":
|
||
return ahora.strftime("%I:%M %p")
|
||
else:
|
||
return ahora.strftime("%H:%M:%S")
|
||
|
||
|
||
class SaludarTool(BaseTool):
|
||
"""
|
||
Herramienta para saludar al usuario.
|
||
"""
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "saludar"
|
||
|
||
@property
|
||
def description(self) -> str:
|
||
return "Saluda al usuario de forma amable."
|
||
|
||
@property
|
||
def args_schema(self) -> Dict[str, Any]:
|
||
return {
|
||
"type": "object",
|
||
"properties": {
|
||
"nombre": {
|
||
"type": "string",
|
||
"description": "Nombre de la persona a saludar"
|
||
}
|
||
},
|
||
"required": ["nombre"]
|
||
}
|
||
|
||
def invoke(self, **kwargs) -> str:
|
||
nombre = kwargs.get("nombre", "Usuario")
|
||
return f"¡Hola {nombre}! 👋 Bienvenido a Naliia"
|
||
'''
|
||
|
||
# ============================================================================
|
||
# PASO 3: Usar tus herramientas
|
||
# ============================================================================
|
||
|
||
"""
|
||
En tu código principal (ejemplo en main.py):
|
||
"""
|
||
|
||
EJEMPLO_USO = '''
|
||
from src.naliiabot.bot.tools import ToolRegistry
|
||
from src.naliiabot.bot.tools.tools import ObtenerHoraActualTool, SaludarTool
|
||
from src.naliiabot.bot.agent.agent import Agent
|
||
from langchain_anthropic import ChatAnthropic
|
||
|
||
# 1. Crear el modelo LLM
|
||
modelo = ChatAnthropic(model="claude-3-5-sonnet-20241022")
|
||
|
||
# 2. Crear el registry de tools
|
||
registry = ToolRegistry()
|
||
|
||
# 3. Registrar las herramientas
|
||
registry.register(ObtenerHoraActualTool())
|
||
registry.register(SaludarTool())
|
||
|
||
# 4. Crear el agente con las tools
|
||
agent = Agent(
|
||
model=modelo,
|
||
tools=registry.get_all_tools_as_langchain()
|
||
)
|
||
|
||
# 5. Usar el agente
|
||
from langchain_core.messages import HumanMessage
|
||
|
||
resultado = agent.invoke({
|
||
"messages": [
|
||
HumanMessage(content="Hola, ¿qué hora es?")
|
||
]
|
||
})
|
||
|
||
print(resultado)
|
||
'''
|
||
|
||
# ============================================================================
|
||
# PASO 4: Verificar que funciona
|
||
# ============================================================================
|
||
|
||
"""
|
||
Ejecuta en la terminal:
|
||
|
||
cd /home/aserrador/Desktop/01-OneCluster/02-Desarrollo/03-Naliia/NaliiaBot
|
||
python -m pytest tests/test_naliia_agent_tools.py -v
|
||
|
||
Deberías ver los tests pasando.
|
||
"""
|
||
|
||
# ============================================================================
|
||
# PASO 5: Crear herramientas más complejas
|
||
# ============================================================================
|
||
|
||
"""
|
||
Para herramientas con lógica real:
|
||
|
||
1. Conectar a base de datos:
|
||
- Importa el cliente de tu BD
|
||
- En invoke(), haz la consulta
|
||
- Retorna el resultado como string
|
||
|
||
2. Manejar errores:
|
||
- Try/except en invoke()
|
||
- Retorna un mensaje de error claro
|
||
|
||
3. Validar argumentos:
|
||
- Usa el args_schema para definir requerimientos
|
||
- El LLM sabe qué argumentos necesita
|
||
|
||
Ejemplo con BD:
|
||
"""
|
||
|
||
EJEMPLO_CON_BD = '''
|
||
from typing import Any, Dict
|
||
from .tool_registry import BaseTool
|
||
from tu_modulo.database import get_db
|
||
|
||
class ObtenerClienteTool(BaseTool):
|
||
@property
|
||
def name(self) -> str:
|
||
return "obtener_cliente"
|
||
|
||
@property
|
||
def description(self) -> str:
|
||
return "Obtiene información de un cliente por ID"
|
||
|
||
@property
|
||
def args_schema(self) -> Dict[str, Any]:
|
||
return {
|
||
"type": "object",
|
||
"properties": {
|
||
"cliente_id": {
|
||
"type": "string",
|
||
"description": "ID del cliente"
|
||
}
|
||
},
|
||
"required": ["cliente_id"]
|
||
}
|
||
|
||
def invoke(self, **kwargs) -> str:
|
||
cliente_id = kwargs.get("cliente_id")
|
||
|
||
try:
|
||
db = get_db()
|
||
cliente = db.clientes.find_one({"_id": cliente_id})
|
||
|
||
if not cliente:
|
||
return f"Cliente {cliente_id} no encontrado"
|
||
|
||
return f"Nombre: {cliente['nombre']}, Email: {cliente['email']}"
|
||
|
||
except Exception as e:
|
||
return f"Error al obtener cliente: {str(e)}"
|
||
'''
|
||
|
||
# ============================================================================
|
||
# TIPS Y BUENAS PRÁCTICAS
|
||
# ============================================================================
|
||
|
||
TIPS = """
|
||
✅ BUENAS PRÁCTICAS:
|
||
|
||
1. **Nombres claros**: "obtener_agenda" mejor que "get_agenda_info"
|
||
|
||
2. **Descripciones detalladas**: El LLM las lee para decidir cuándo usar la tool
|
||
|
||
3. **Args schema completo**:
|
||
- Describe qué es cada parámetro
|
||
- Especifica si es requerido
|
||
- Usa enum para valores limitados
|
||
- Añade ejemplos en description
|
||
|
||
4. **Manejo de errores**: Siempre captura excepciones en invoke()
|
||
|
||
5. **Retorna strings**: invoke() debe retornar texto plano, no objetos
|
||
|
||
6. **Validación**: Valida argumentos en invoke() antes de usarlos
|
||
|
||
7. **Logging**: Usa logging para debugging en producción
|
||
|
||
8. **Tests**: Crea tests unitarios para cada tool
|
||
|
||
❌ ERRORES COMUNES:
|
||
|
||
- No retornar string desde invoke()
|
||
- Olvidar el args_schema completo
|
||
- No manejar excepciones
|
||
- Nombres de tools con espacios o caracteres especiales
|
||
- Tools que hacen demasiadas cosas (una responsabilidad)
|
||
|
||
🔍 DEBUGGING:
|
||
|
||
# Ver todas las tools registradas
|
||
print(registry.list_tool_names())
|
||
|
||
# Ver schema de una tool
|
||
herramienta = registry.get_tool("mi_herramienta")
|
||
print(herramienta.args_schema)
|
||
|
||
# Ver descripción
|
||
print(registry.get_tool_description("mi_herramienta"))
|
||
"""
|
||
|
||
# ============================================================================
|
||
# ESTRUCTURA FINAL
|
||
# ============================================================================
|
||
|
||
ESTRUCTURA = """
|
||
Después de seguir estos pasos, tu proyecto tendrá:
|
||
|
||
src/naliiabot/bot/tools/
|
||
├── __init__.py
|
||
│ └── Exporta: ToolRegistry, BaseTool
|
||
├── tool_registry.py
|
||
│ └── Contiene: BaseTool (clase abstracta), ToolRegistry (registro)
|
||
└── tools.py
|
||
└── TUS herramientas (ObtenerHoraActualTool, SaludarTool, etc.)
|
||
|
||
tests/
|
||
└── test_naliia_agent_tools.py
|
||
└── Tests para las tools (ya creado)
|
||
|
||
src/naliiabotapi/
|
||
└── main.py
|
||
└── Crea el registry, inicializa el agent, lanza el API
|
||
|
||
DOCUMENTACIÓN:
|
||
├── TOOLS_GUIDE.md ← Lee primero
|
||
├── AGENDA_TOOLS_EXAMPLE.py ← Ejemplos reales
|
||
├── REGISTRY_IMPLEMENTATION_SUMMARY.md ← Resumen
|
||
├── CHANGES_SUMMARY.md ← Qué cambió
|
||
└── QUICK_START.md (este archivo) ← Tutorial
|
||
"""
|
||
|
||
if __name__ == "__main__":
|
||
print("=" * 80)
|
||
print("QUICK START: Patrón Registry para Tools en NaliiaBot")
|
||
print("=" * 80)
|
||
print("\n📖 PASOS:")
|
||
print("\n1️⃣ CREA tu primera herramienta")
|
||
print(" → Abre: src/naliiabot/bot/tools/tools.py")
|
||
print(" → Pega el código de EJEMPLO_HERRAMIENTA\n")
|
||
|
||
print("2️⃣ REGISTRA la herramienta")
|
||
print(" → Crea ToolRegistry()")
|
||
print(" → Llama registry.register(MiHerramienta())\n")
|
||
|
||
print("3️⃣ USA con el Agent")
|
||
print(" → Pasa registry.get_all_tools_as_langchain() a Agent\n")
|
||
|
||
print("4️⃣ TESTA tus tools")
|
||
print(" → python -m pytest tests/test_naliia_agent_tools.py -v\n")
|
||
|
||
print("5️⃣ LEE la documentación")
|
||
print(" → TOOLS_GUIDE.md - Guía completa")
|
||
print(" → AGENDA_TOOLS_EXAMPLE.py - Ejemplos reales\n")
|
||
|
||
print("=" * 80)
|
||
print("¡Listo! Ya tienes todo lo que necesitas para empezar 🚀")
|
||
print("=" * 80)
|