Cómo construir un agente de IA con NestJS y Claude API

agente-ia-nestjs-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 Provider de 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_KEY mediante ConfigService.
  • 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:

  • ToolRegistryService mantiene 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

  1. Construir messages + tools (esquemas) y llamar a Anthropic.
  2. Leer stop_reason:
    • end_turn: devolver respuesta final.
    • tool_use: extraer tool_name y arguments.
  3. Ejecutar herramienta vía ToolRegistryService y añadir tool_result al historial.
  4. Repetir hasta end_turn o 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 AnthropicProvider y el ToolRegistryService en 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

Respuesta: 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.

Respuesta: 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.

Respuesta: 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.

Respuesta: 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.

Respuesta: 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.

Respuesta: 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.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *