Cómo construir un agente de IA con NestJS y Claude API
Cómo construir un agente de IA con NestJS + Claude API
Tiempo estimado de lectura: 4 min
- Separar cliente LLM, registro de herramientas y loop de agente para modularidad y pruebas.
- Herramientas como contratos JSON-schema y validación antes de ejecución.
- Agent loop controlado: límites de iteraciones, métricas y manejo de errores normalizado.
- Producción: no bloquear peticiones HTTP, usar SSE/WebSockets y proteger PII y costes.
- Observabilidad y testing: trazas por sesión, mocks para provider y canary releases.
Introducción
Saber cómo construir un agente de IA con NestJS + Claude API es lo que separa una demo interesante de una pieza de infraestructura que puedas mantener en producción. En este artículo encontrarás la arquitectura, decisiones técnicas y patrones que realmente importan cuando implementas tool-calling de Claude dentro de un backend modular y tipado como NestJS.
Un agente no es un chatbot: es un bucle de decisión. Recibe objetivo, decide herramientas, ejecuta, observa resultados y vuelve a razonar hasta resolver la tarea o agotar límites.
Resumen rápido (lectores con prisa)
Qué: Un agente es un bucle de decisión que orquesta llamadas a herramientas externas desde un LLM.
Cuándo: Cuando necesitas que un LLM interactúe con sistemas externos (DB, APIs, logs) de forma controlada.
Por qué importa: Permite trazabilidad, testing y control de costes frente a soluciones ad-hoc.
Cómo: Separando un provider LLM, un registro de herramientas con schemas JSON y un agente que controla el loop y límites.
Cómo construir un agente de IA con NestJS + Claude API: arquitectura y flujo
Ese bucle —Agent Loop— obliga a diseñar responsabilidades claras. El agente recibe un objetivo, decide qué herramienta usar, ejecuta esa herramienta, observa el resultado y repite hasta resolver la tarea o agotar límites.
Arquitectura mínima recomendada:
- Proveedor del cliente LLM (Anthropic) como
Providerde NestJS. - Registro dinámico de herramientas (
ToolRegistryService) que mapea nombres/JSON-schema a métodos de servicios. - Motor de ejecución (
AgentService) que orquesta el loop y gestiona historial, stop reasons y seguridad.
Referencias: NestJS Docs y Anthropic Tool Use
Capa 1 — AnthropicProvider: el cliente como dependencia inyectable
Nunca newees el cliente de Anthropic en controladores o servicios. Crea un provider que se inyecte y centralice la lógica del cliente.
- Lee
ANTHROPIC_API_KEYmedianteConfigService. - Envuelve lógica de retries, backoff y métricas (tokens usados, latencia).
- Permite mockear en tests unitarios.
Ejemplo conceptual: el provider expone sendMessage(payload) que encapsula anthropic.messages.create() y normaliza la respuesta (stop_reason, content, tool_call).
Beneficio: centralizas control de coste y modelo (p. ej. cambiar de Claude 3.5 a otro modelo sin tocar el resto).
Capa 2 — ToolRegistry: herramientas como contratos JSON y servicios
Claude espera herramientas descritas por JSON-schema. En el backend conviene modelarlas y validar antes de ejecutar.
- Definir cada herramienta con nombre, descripción y schema (tipado TypeScript).
- Mapear cada herramienta a un método de servicio inyectable (p. ej.
UsersService.getById,LogsService.append). - Implementar granularidad: una herramienta = una responsabilidad.
Diseño práctico:
ToolRegistryServicemantiene un mapa {toolName -> { schema, executor }}.executor(args)valida los args contra el schema y ejecuta el método correspondiente en try/catch.
Así el agent loop no necesita switches gigantes; resuelve métodos dinámicamente.
Capa 3 — AgentService: el bucle, stop_reasons y límites
El AgentService orquesta el loop de decisión, mantiene el historial y aplica límites y políticas de seguridad.
Patrón del Agent Loop
- Construir
messages+tools(esquemas) y llamar a Anthropic. - Leer
stop_reason:end_turn: devolver respuesta final.tool_use: extraertool_nameyarguments.
- Ejecutar herramienta vía
ToolRegistryServicey añadirtool_resultal historial. - Repetir hasta
end_turno alcanzar un límite de iteraciones.
Normas prácticas
- Límite de iteraciones (p. ej. max 5) para evitar bucles y costes excesivos.
- Cada iteración registra métricas: tokens, latencia, herramienta invocada.
- Normaliza errores: si la herramienta falla, devuelve
{ error: 'timeout' }a Claude, no throws.
Producción: latencia, UX y seguridad
Al pasar a producción hay que priorizar experiencia de usuario, seguridad y observabilidad.
Latencia y UX
- No bloquees la petición HTTP principal. Emite progreso con SSE o WebSockets: “Pensando…”, “Consultando DB…”.
- Opcional: respuesta rápida + notificación cuando el resultado final esté listo (webhook / push).
Seguridad y validación
- Valida argumentos de herramientas con
class-validator/schema JSON antes de ejecutar. - Logs sensibles: evita enviar secrets o PII a la API de Claude.
- Rate limits y circuit breakers en el provider para proteger tu backend y controlar facturación.
Observabilidad
Traza cada sesión como un árbol de spans: requests al LLM, ejecuciones de herramientas, errores.
Integra herramientas de visualización y trazabilidad como Langfuse o LangSmith para visualizar flujos y coste por sesión.
Testing y despliegue
- Mockea el
AnthropicProvidery elToolRegistryServiceen tests unitarios. - Tests de integración: entorno con Claude sandbox o replay de respuestas deterministas.
- Canary releases: habilita el agente en subset de usuarios antes de producir a toda la base.
Coste y gobernanza
- Mide tokens por iteración; extrapola a coste por sesión.
- Define políticas: cuándo permitir tool-calling (p. ej. solo usuarios verificados) y límites diarios.
Qué evitar (errores comunes)
- Herramientas “dios” que hacen todo: dificultan autorización y testing.
- Dejar excepciones sin capturar: provoca loops rotos y mala UX.
- No auditar llamadas: sin trazabilidad no sabrás por qué el agente falló o costó tanto.
Cierre práctico
Construir un agente con NestJS + Claude API no es magia, es disciplina arquitectónica. Si abstraes el cliente, modelas herramientas como contratos y controlas el bucle con límites, obtienes un sistema escalable, testeable y seguro.
En el siguiente artículo veremos ejemplos concretos de ToolRegistryService y patrones para emitir progreso en SSE desde NestJS para mejorar la experiencia del usuario.
Dominicode Labs
Para continuidad en temas de automatización y agentes, consulta recursos adicionales en Dominicode Labs. Es una fuente útil para patrones, ejemplos y plantillas prácticas que complementan esta arquitectura.
FAQ
¿Qué es un agente de IA en este contexto?
Un agente es un bucle de decisión que recibe un objetivo, decide qué herramienta invocar, ejecuta esa herramienta, observa el resultado y repite hasta completar la tarea o agotar límites.
¿Por qué usar un provider para Anthropic?
Un provider centraliza la configuración del cliente (API key, retries, métricas), facilita el mock en tests y permite cambiar de modelo o proveedor sin modificar la lógica de negocio.
¿Cómo se describen las herramientas?
Las herramientas se describen con nombre, descripción y un JSON-schema (tipado TypeScript). Se valida la entrada antes de ejecutar y se mapea a funciones/executors inyectables.
¿Qué es stop_reason y cómo se maneja?
stop_reason indica la acción del LLM: end_turn para respuesta final o tool_use para invocar una herramienta. El agente interpreta y actúa según ese valor.
¿Cómo se asegura la producción respecto a latencia?
No bloquear la petición HTTP principal; usar SSE o WebSockets para emitir progreso. También considerar respuestas rápidas con notificación posterior y aplicar límites de iteraciones para controlar latencia y coste.
¿Qué pruebas son recomendables?
Mockear el provider y el registry en tests unitarios; usar sandbox o replays deterministas en integración; ejecutar canary releases antes de un despliegue completo.
¿Te resultó útil este artículo?
Compártelo con tu comunidad y ayuda a otros desarrolladores.
