# Guía: Usar ToolRegistry para crear herramientas en NaliiaBot El patrón **Registry** permite gestionar de forma centralizada todas las herramientas del agente. Aquí te muestro cómo usarlo. ## 1. Estructura básica El proyecto tiene esta estructura de tools: ``` src/naliiabot/bot/tools/ ├── __init__.py ├── tool_registry.py # Base + Registry └── tools.py # Tus herramientas personalizadas ``` ## 2. Crear una herramienta personalizada En el archivo `src/naliiabot/bot/tools/tools.py`, define tu herramienta: ```python from typing import Any, Dict from .tool_registry import BaseTool class ObtenerAgendaTool(BaseTool): """Obtiene los eventos de la agenda del usuario.""" @property def name(self) -> str: return "obtener_agenda" @property def description(self) -> str: return "Obtiene los eventos programados en la agenda del usuario para una fecha específica." @property def args_schema(self) -> Dict[str, Any]: return { "type": "object", "properties": { "fecha": { "type": "string", "description": "Fecha en formato YYYY-MM-DD" }, "usuario_id": { "type": "string", "description": "ID del usuario" } }, "required": ["fecha", "usuario_id"] } def invoke(self, **kwargs) -> str: fecha = kwargs.get("fecha") usuario_id = kwargs.get("usuario_id") # Aquí va la lógica real: consultar DB, API, etc. # Por ahora es un ejemplo simulado return f"Eventos para {usuario_id} el {fecha}: Reunión 10:00, Almuerzo 12:30" ``` ## 3. Registrar y usar herramientas ### Opción A: En el código principal ```python from src.naliiabot.bot.tools.tool_registry import ToolRegistry from src.naliiabot.bot.tools.tools import ObtenerAgendaTool, OtraHerramienta from src.naliiabot.bot.agent.agent import Agent # Crear el registry registry = ToolRegistry() # Registrar las herramientas registry.register(ObtenerAgendaTool()) registry.register(OtraHerramienta()) # Obtener en formato LangChain herramientas_langchain = registry.get_all_tools_as_langchain() # Crear el agente con las herramientas agent = Agent(model=mi_modelo, tools=herramientas_langchain) ``` ### Opción B: Crear una factory para simplificar Crea un archivo `src/naliiabot/bot/tools/factory.py`: ```python from .tool_registry import ToolRegistry from .tools import ObtenerAgendaTool, OtraHerramienta def create_tool_registry() -> ToolRegistry: """Factory para crear el registry con todas las tools.""" registry = ToolRegistry() registry.register(ObtenerAgendaTool()) registry.register(OtraHerramienta()) return registry ``` Luego úsalo así: ```python from src.naliiabot.bot.tools.factory import create_tool_registry from src.naliiabot.bot.agent.agent import Agent registry = create_tool_registry() tools = registry.get_all_tools_as_langchain() agent = Agent(model=mi_modelo, tools=tools) ``` ## 4. Métodos disponibles del ToolRegistry ```python registry = ToolRegistry() # Registrar una herramienta registry.register(MiHerramienta()) # Obtener una herramienta específica herramienta = registry.get_tool("obtener_agenda") # Obtener todas las herramientas como BaseTool todas = registry.get_all_tools() # Obtener todas como LangChain Tools (para usar con Agent) herramientas_lc = registry.get_all_tools_as_langchain() # Verificar si existe una herramienta existe = registry.has_tool("obtener_agenda") # Listar nombres de todas las herramientas nombres = registry.list_tool_names() # Obtener descripción de una herramienta desc = registry.get_tool_description("obtener_agenda") ``` ## 5. Ejemplo completo: Herramienta para gestionar agenda ```python from typing import Any, Dict from .tool_registry import BaseTool from datetime import datetime class AgregarEventoTool(BaseTool): """Agrega un evento a la agenda del usuario.""" @property def name(self) -> str: return "agregar_evento" @property def description(self) -> str: return "Agrega un nuevo evento a la agenda del usuario." @property def args_schema(self) -> Dict[str, Any]: return { "type": "object", "properties": { "usuario_id": { "type": "string", "description": "ID del usuario" }, "titulo": { "type": "string", "description": "Título del evento" }, "fecha": { "type": "string", "description": "Fecha en formato YYYY-MM-DD" }, "hora_inicio": { "type": "string", "description": "Hora de inicio en formato HH:MM" }, "duracion_minutos": { "type": "integer", "description": "Duración del evento en minutos", "default": 30 }, "descripcion": { "type": "string", "description": "Descripción del evento (opcional)" } }, "required": ["usuario_id", "titulo", "fecha", "hora_inicio"] } def invoke(self, **kwargs) -> str: usuario_id = kwargs.get("usuario_id") titulo = kwargs.get("titulo") fecha = kwargs.get("fecha") hora = kwargs.get("hora_inicio") duracion = kwargs.get("duracion_minutos", 30) descripcion = kwargs.get("descripcion", "") try: # Aquí iría la lógica para guardar en BD # base_de_datos.agregar_evento(...) return ( f"✓ Evento '{titulo}' agregado con éxito\n" f"Fecha: {fecha}\n" f"Hora: {hora}\n" f"Duración: {duracion} minutos" ) except Exception as e: return f"Error al agregar evento: {str(e)}" class ModificarEventoTool(BaseTool): """Modifica un evento existente.""" @property def name(self) -> str: return "modificar_evento" @property def description(self) -> str: return "Modifica los detalles de un evento existente en la agenda." @property def args_schema(self) -> Dict[str, Any]: return { "type": "object", "properties": { "evento_id": { "type": "string", "description": "ID del evento a modificar" }, "titulo": { "type": "string", "description": "Nuevo título (opcional)" }, "hora_inicio": { "type": "string", "description": "Nueva hora en formato HH:MM (opcional)" }, "duracion_minutos": { "type": "integer", "description": "Nueva duración en minutos (opcional)" } }, "required": ["evento_id"] } def invoke(self, **kwargs) -> str: evento_id = kwargs.get("evento_id") try: # Lógica para actualizar en BD return f"✓ Evento {evento_id} modificado correctamente" except Exception as e: return f"Error al modificar evento: {str(e)}" class EliminarEventoTool(BaseTool): """Elimina un evento de la agenda.""" @property def name(self) -> str: return "eliminar_evento" @property def description(self) -> str: return "Elimina un evento de la agenda del usuario." @property def args_schema(self) -> Dict[str, Any]: return { "type": "object", "properties": { "evento_id": { "type": "string", "description": "ID del evento a eliminar" }, "usuario_id": { "type": "string", "description": "ID del usuario propietario" } }, "required": ["evento_id", "usuario_id"] } def invoke(self, **kwargs) -> str: evento_id = kwargs.get("evento_id") try: # Lógica para eliminar de BD return f"✓ Evento {evento_id} eliminado correctamente" except Exception as e: return f"Error al eliminar evento: {str(e)}" ``` ## 6. Usar con el Agent Una vez que has creado tus herramientas, úsalas con el agente: ```python from src.naliiabot.bot.tools.tool_registry import ToolRegistry from src.naliiabot.bot.tools.tools import ( ObtenerAgendaTool, AgregarEventoTool, ModificarEventoTool, EliminarEventoTool ) from src.naliiabot.bot.agent.agent import Agent from langchain_anthropic import ChatAnthropic # Crear modelo modelo = ChatAnthropic(model="claude-3-5-sonnet-20241022") # Crear registry y registrar herramientas registry = ToolRegistry() registry.register(ObtenerAgendaTool()) registry.register(AgregarEventoTool()) registry.register(ModificarEventoTool()) registry.register(EliminarEventoTool()) # Crear agente con las herramientas agent = Agent( model=modelo, tools=registry.get_all_tools_as_langchain() ) # Usar el agente resultado = agent.invoke({ "messages": [ HumanMessage(content="Agrega una reunión el 15 de febrero a las 10:00") ] }) ``` ## 7. Ventajas del patrón Registry ✅ **Centralización**: Todas las tools en un solo lugar ✅ **Escalabilidad**: Fácil agregar nuevas herramientas ✅ **Testabilidad**: Cada tool se prueba independientemente ✅ **Mantenibilidad**: Cambios en una tool no afectan otras ✅ **Reusabilidad**: Las tools se pueden usar en múltiples agentes ✅ **Validación**: Verificación automática de esquemas ✅ **Inspección**: Fácil listar y documentar tools disponibles ## 8. Próximos pasos 1. Define tus herramientas específicas en `tools.py` 2. Crea un factory o inicializar el registry en tu main 3. Prueba con tests unitarios (los tests ya están en `test_naliia_agent_tools.py`) 4. Integra con el API FastAPI en `src/naliiabotapi/main.py`