Category: Blog

Your blog category

  • Cómo estructurar patrones de indicaciones para Claude Code

    Cómo estructurar patrones de indicaciones para Claude Code

    Patrones de indicaciones, memoria, estructura del proyecto, subagentes, habilidades para Claude Code

    Tiempo estimado de lectura: 5 min

    • Ideas clave:
    • Claude Code necesita prompts estructurados y deterministas para operar de forma segura y efectiva.
    • Una memoria explícita (ej. CLAUDE.md) y una estructura de repo modular son indispensables.
    • Orquestar subagentes (p. ej. con n8n) reduce riesgo y carga cognitiva del agente principal.
    • Control estricto de habilidades (tool use) y entornos sandbox evita daños en producción.

    Introducción

    Patrones de indicaciones, memoria, estructura del proyecto, subagentes y habilidades para Claude Code son los cinco pilares que determinan si un agente CLI acelera tu ingeniería o genera deuda técnica silenciosa. Si no defines cómo hablarle, qué puede recordar, cómo está organizado el repo, cómo se subdividen las tareas y qué permisos tiene, Claude actúa a ciegas. Aquí tienes una guía práctica y accionable para poner orden.

    Resumen rápido (lectores con prisa)

    Claude Code es un operador que modifica código y ejecuta shells; requiere prompts deterministas, una memoria persistente en raíz (p. ej. CLAUDE.md), una estructura de repo modular, subagentes/orquestación para QA y control estricto de habilidades. Usa TDD y sandboxes antes de delegar cambios en producción.

    Claude Code como operador

    Claude Code no es un chatbot; es un operador que puede leer y modificar tu código, ejecutar shells y (en previews) automatizar UIs. La diferencia clave: requiere prompts estructurados, memoria explícita del proyecto, una arquitectura de repositorio que el agente pueda razonar, subagentes u orquestadores para tareas auxiliares y un control estricto de habilidades (tool use). Documentación útil: docs.anthropic — Claude Code y, para orquestación, n8n. Para novedades y previews (p. ej. Computer Use) revisa releasebot.dev.

    1) Patrones de indicaciones — cómo pedirle cosas a Claude Code

    No escribas prompts vagos. Usa plantillas deterministas:

    Patrón Contexto‑Restricción‑Acción

    Contexto: qué módulo, stack, rama. (“Servicio payments — Node.js/TS — branch feat/rate-limit”)

    Restricción: reglas innegociables. (“No tocar DB schema; no añadir deps externas”)

    Acción: objetivo con criterio verificable. (“Implementa rate limiting y añade tests que cubran 429; PR con test passing en CI es criterio de éxito”)

    Prompt de TDD (Test-Driven Prompting)

    – Paso 1: “Escribe el test que debería fallar”

    – Paso 2: pedir ejecución del test

    – Paso 3: solicitar la implementación hasta que los tests pasen

    Ejemplo de prompt (compacto):

    “Contexto: /services/payments, Node 18, TS. Restricción: no tocar migraciones. Acción: añade rate limiter en /api/charge; escribe tests unitarios y de integración; criterio: pipeline CI verde. Empieza por crear tests que fallen.”

    2) Memoria — cómo mantener contexto útil y persistente

    Claude Code construye su contexto leyendo el repo; no tiene intuición humana. Dos mecanismos clave:

    • Memoria de sesión (corto plazo): archivos abiertos y árbol activo. Evita saturarla con monorepos gigantes; abre solo lo necesario.
    • Memoria persistente (largo plazo): un archivo en la raíz que Claude lee siempre. Recomendación práctica:

    CLAUDE.md o .clauderc con:

    • Convenciones de estilo y nomenclatura
    • Comandos claves (tests, build, dev)
    • ADRs esenciales
    • Dependencias permitidas/prohibidas
    • Checklists de seguridad y compliance

    Este archivo convierte normas humanas en reglas ejecutables por el agente y reduce ambigüedad.

    3) Estructura del proyecto — diseño para agentes

    Diseña el repo pensando en unidades pequeñas y autocontenidas:

    • Modularidad: archivos <300 líneas, responsabilidades únicas.
    • Rutas semánticas: /auth/use-cases/login.ts en vez de /utils/helper9.ts.
    • Tipado estricto: TypeScript/Rust/Go ayudan al agente a validar cambios antes de ejecutarlos.
    • Tests como contrato: TDD + coverage mínimo hacen al agente predecible.

    Si el repo es un monolito acoplado, prioriza una fase de refactor (extract module) manual antes de delegar en agentes.

    4) Subagentes y orquestación — dividir para no perder contexto

    Claude Code aún no gestiona subagentes complejos de forma nativa. La práctica efectiva es orquestar subagentes externos:

    – Usa n8n o un orquestador propio para:

    • Ejecutar análisis estático en entornos aislados
    • Lanzar pipelines de seguridad y escaneo de dependencias
    • Devolver reportes al CLI para que Claude actúe sobre ellos

    Patrón típico:

    1. Claude genera un PR provisional.
    2. n8n ejecuta linters, SCA y tests en una VM sandbox.
    3. Resultado vuelve al CLI; Claude corrige y reitera.

    Así evitas que un único agente cargue demasiado contexto o tome decisiones incompletas.

    5) Habilidades (Tool Use) — permisos y límites

    Define explícitamente qué puede ejecutar el agente. Habilidades críticas:

    • Bash Execution: npm test, git, docker-compose — imprescindible para feedback real.
    • File System Access: lectura/escritura de archivos.
    • Semantic Search / Repo Index: para referencias cruzadas antes de modificar.
    • (Preview) Computer Use: interacción con UIs nativas — potente, frágil y debe usarse solo en sandboxes.

    Regla de oro: nunca habilites habilidades destructivas en máquinas con credenciales reales. Usa contenedores o VMs aisladas.

    Checklist mínimo de adopción antes de delegar tareas

    1. CLAUDE.md en raíz con políticas y comandos.
    2. Tests automatizados que sirvan de contrato.
    3. Entorno sandbox (Docker/VM) para ejecución.
    4. CI que valide PRs generados por el agente.
    5. Orquestador (n8n o similar) para subagentes de QA/security.
    6. Prompts basados en Contexto‑Restricción‑Acción y TDD.

    Conclusión

    Patrones de indicaciones, memoria, estructura del proyecto, subagentes y habilidades para Claude Code no son conceptos teóricos: son requisitos operativos. Implementados juntos, convierten a Claude en un multiplicador de capacidad. Si fallas en cualquiera, el agente acelera errores, no entrega. Empieza por documentar: CLAUDE.md, tests firmes y sandboxes. Luego automatiza, orquesta y vigila. Esto no acaba aquí: quien domine estas cinco piezas tendrá ventaja real al escalar agentes en ingeniería.

    Dominicode Labs

    Para equipos que integran automatización y orquestación de subagentes como parte de su plataforma de ingeniería, una continuación natural es explorar herramientas y patrones documentados en Dominicode Labs. La referencia ayuda a unir prácticas de prompts, memoria y sandboxes con flujos de trabajo reproducibles.

    FAQ

    ¿Qué es Claude Code y en qué se diferencia de un chatbot?

    Claude Code es un operador diseñado para leer y modificar repositorios, ejecutar comandos de shell y automatizar tareas. A diferencia de un chatbot, espera prompts estructurados y tiene habilidades (tool use) que deben definirse y limitarse explícitamente.

    ¿Qué debe contener un archivo CLAUDE.md?

    Debe incluir convenciones de estilo, comandos claves (tests/build/dev), ADRs importantes, dependencias permitidas/prohibidas y checklists de seguridad. Su propósito es convertir reglas humanas en referencia legible por el agente.

    ¿Cuándo debo usar subagentes u orquestadores?

    Úsalos cuando el pipeline requiera aislamiento (análisis estático, SCA, pruebas en sandbox) o cuando el agente principal necesite retroalimentación externa antes de cometer cambios. Orquestadores como n8n facilitan este patrón.

    ¿Qué habilidades del agente debo deshabilitar en producción?

    Deshabilita cualquier ejecución con acceso a credenciales reales o capacidad destructiva directa sobre entornos de producción. Mantén ejecución de bash y acceso a filesystem solo en contenedores/VMs aisladas.

    ¿Cómo aplicar TDD con Claude Code?

    Sigue el patrón: pide primero tests que fallen, ejecuta tests en sandbox, luego solicita la implementación hasta que los tests pasen. Define criterios de éxito claros (por ejemplo, pipeline CI verde) en el prompt.

    ¿Por qué modularizar archivos en <300 líneas?

    Archivos pequeños y responsabilidades únicas facilitan que el agente razone sobre cambios y reduzcan el riesgo de efectos colaterales imprevistos.

    ¿Qué papel juega CI en el flujo con agentes?

    CI actúa como guardián: valida PRs generados por el agente, ejecuta tests y linters y evita que cambios automatizados lleguen a producción sin verificación.

  • Implementación de memoria en agentes de IA para una gestión eficiente

    Implementación de memoria en agentes de IA para una gestión eficiente

    Memoria en agentes de IA — CoALA, Mem0, Letta, Zep

    Tiempo estimado de lectura: 4 min

    Ideas clave

    • La memoria separada convierte demos en productos: el diseño determina seguridad, costo y utilidad.
    • CoALA propone cuatro capas de memoria para organizar responsabilidades y políticas.
    • Mem0, Letta y Zep cubren distintos niveles: personalización entre sesiones, RAM operativa y memoria a escala respectivamente.
    • Implementa gates, versionado, trazabilidad y pruebas de regresión para evitar drift y conflictos.

    Introducción

    La memoria en agentes de IA — CoALA, Mem0, Letta, Zep no es un tema académico bonito: es la diferencia entre un asistente útil y un agente que toma decisiones peligrosas después de tres días de uso. Si construyes agentes, tienes que decidir qué recordar, cómo hacerlo y quién corrige cuando la memoria miente. Punto.

    Resumen rápido (lectores con prisa)

    CoALA: arquitectura conceptual con cuatro capas de memoria para separar responsabilidades. Mem0: persistencia de perfil y preferencias entre sesiones. Letta: gestión del contexto operativo (RAM vs disco) para agentes de larga duración. Zep: infraestructura asíncrona para memoria a escala y baja latencia. Usa gates, versionado y trazabilidad para mitigar drift y conflictos.

    Memoria en agentes de IA — qué propone CoALA (y por qué importa)

    CoALA (Cognitive Architectures for Language Agents) es el mapa mental que deberías leer antes de elegir tecnología. No es una librería; es una arquitectura conceptual que separa responsabilidades de memoria en cuatro capas:

    Memoria de trabajo

    la ventana de contexto activa del LLM — efímera y cara.

    Memoria episódica

    historial de eventos y acciones — útil para debugging y trazabilidad.

    Memoria semántica

    hechos estables y preferencias del usuario — lo que define el perfil.

    Memoria procedimental

    herramientas, prompts y rutinas — cómo actúa el agente.

    Diseñar según CoALA significa decidir por anticipado qué pertenece a cada capa y qué políticas aplicas para mover datos entre ellas. Sin ese mapa, cualquier solución termina en un RAG desordenado o en una “caja negra” que acumula ruido.

    Mem0: memoria de usuario para personalización

    Mem0 es la categoría de herramientas centradas en persistir hechos del usuario y preferencias. En la práctica:

    • Extrae entidades y preferencias desde la conversación.
    • Las indexa en un vector store + metadatos.
    • Cuando el usuario regresa, inyecta solo lo necesario: preferencias, roles, restricciones.

    Cuándo usar Mem0: productos donde la coherencia entre sesiones importa (soporte, asistentes personales, CRMs conversacionales). No esperes de Mem0 la gestión de contexto operativo de un agente que corre tareas autónomas por horas; su foco es perfilización y personalización.

    Letta: el agente que administra su propia RAM

    Letta aborda la memoria como un sistema operativo para agentes. Conceptualmente:

    • Divide el contexto en Main Context (RAM) y External Context (disco).
    • El agente tiene funciones para decidir qué traer a RAM, cuándo resumir episodios y cuándo purgar información.
    • Aplica paginación y compactación automática para mantener la relevancia dentro del límite de tokens.

    Cuándo usar Letta: agentes autónomos de larga duración — research agents, asistentes de coding que mantienen estado operativo o pipelines que deben razonar sobre eventos pasados extensos. Letta añade autonomía, pero también complejidad operacional: monitorización, logs y políticas de gobernanza son obligatorios.

    Zep: memoria a escala y baja latencia para producción

    Zep es la opción de infraestructura: microservicio que procesa memoria de forma asíncrona y entrega contexto prefiltrado con baja latencia.

    • Extrae hechos, construye resúmenes y grafos de conocimiento en background.
    • Reduce el coste en inferencia en tiempo real porque el trabajo pesado está hecho antes.
    • Ideal para entornos B2B de alto tráfico donde milisegundos y consistencia importan.

    Cuándo usar Zep: productos que atienden muchos usuarios concurrentes y necesitan recuperar relaciones complejas entre entidades sin sacrificar SLA.

    Criterio para elegir (resumen práctico)

    • Necesitas perfilamiento entre sesiones → Mem0.
    • Necesitas un agente que se gestione a sí mismo durante horas/días → Letta.
    • Necesitas latencia baja a escala y relaciones entre entidades → Zep.
    • Necesitas diseñar el sistema completo antes de implementar → CoALA como guía.

    Riesgos técnicos que no puedes ignorar

    Memory drift: si un agente almacena una inferencia incorrecta, esa “mentira” contamina decisiones futuras. Implementa mecanismos de verificación y anclaje (por ejemplo, expiración automática o validación humana).

    Conflictos de memoria: cuando dos hechos contradictorios coexisten, la resolución automática es no determinista. Loggear confianza, orígenes y versiones de cada hecho ayuda a auditar.

    Derecho al olvido y cumplimiento: borrar vectores y metadatos es posible, pero garantizar que el agente “olvide” inferencias derivadas de esos datos es técnicamente complejo. Diseña flujos de eliminación y revisiones humanas para datos sensibles.

    Observabilidad y gobernanza: sin trazabilidad de qué dato fue recuperado y por qué, no puedes depurar ni atribuir responsabilidad. Cada recuperación debe registrar fuente, score y prompt usado.

    Implementación: checklist mínimo antes de producción

    • Define qué tipos de memoria necesita tu agente (CoALA).
    • Añade gates en la recuperación: score mínimo, límite de tokens y razón de inclusión.
    • Versiona la memoria: cada actualización con sello temporal y origen.
    • Pruebas de regresión para el comportamiento basado en memoria (no solo unitarias).
    • Monitoreo de drift: alertas automáticas cuando la tasa de correcciones humanas sube.

    La memoria transforma agentes de demos en productos reales. No es una feature; es una capa de infraestructura con requerimientos de producto, seguridad y mantenimiento. Si vas a construir agentes que duren, diseña memoria con criterio ahora — después ya será demasiado caro corregirlo. En los próximos posts de Dominicode veremos ejemplos prácticos: pipeline de Mem0 para asistentes y cómo instrumentar Letta en un agente de investigación.

    Dominicode Labs

    Si trabajas en automatización, agentes o IA aplicada y quieres ejemplos prácticos y pipelines listos para producción, explora recursos y experimentos en Dominicode Labs. Es una continuación lógica para ver implementaciones de Mem0, Letta y arquitecturas inspiradas en CoALA.

    FAQ

    ¿Qué es CoALA?

    CoALA es una arquitectura conceptual que separa responsabilidades de memoria en cuatro capas: memoria de trabajo, episódica, semántica y procedimental. No es una librería, sino un mapa mental para diseñar memoria en agentes.

    ¿Para qué sirve Mem0?

    Mem0 persiste hechos del usuario y preferencias entre sesiones. Se usa para perfilamiento y personalización en productos donde la coherencia inter-sesiones importa (por ejemplo, CRMs conversacionales o asistentes personales).

    ¿Cuándo debo usar Letta?

    Usa Letta para agentes autónomos de larga duración que necesitan gestionar activamente su contexto (RAM vs disco), como research agents o asistentes de coding que operan durante horas o días.

    ¿Qué aporta Zep a producción?

    Zep ofrece una capa de infraestructura que procesa memoria en background, construye resúmenes y grafos, y entrega contexto prefiltrado con baja latencia, útil en entornos B2B de alto tráfico.

    ¿Cómo mitigo el memory drift?

    Implementa mecanismos de verificación, expiración automática, validación humana, trazabilidad de orígenes y versionado para detectar y corregir inferencias incorrectas almacenadas en memoria.

    ¿Qué pruebas son críticas antes de lanzar?

    Además de pruebas unitarias, haz pruebas de regresión específicas para comportamiento influido por memoria, monitoriza drift y añade alertas cuando sube la tasa de correcciones humanas.

  • Implementando Claude Code para la automatización de desarrollo en Angular y NestJS

    Implementando Claude Code para la automatización de desarrollo en Angular y NestJS

    Claude Code como herramienta diaria de desarrollo

    Tiempo estimado de lectura: 5 min

    • Orquestación de tareas multi-archivo y ejecución de CLI para migraciones, generación de boilerplate y correcciones automáticas.
    • Requiere contexto persistente (ej. archivo CLAUDE.md) para evitar alucinaciones y errores arquitectónicos.
    • Útil para flujos repetibles y tests automatizados; no ideal para retoques UI o tareas atómicas simples.

    Resumen rápido (lectores con prisa)

    Claude Code es un agente orientado a orquestar tareas que implican múltiples archivos y ejecución de CLI. Úsalo cuando necesites migraciones, generación de boilerplate, tests y correcciones automáticas a partir de stack traces. No es la mejor opción para escribir una sola función o pulir UI.

    Por qué usar (o no) Claude Code en tu flujo diario

    Claude Code Claude Code está pensado para tareas que van más allá del autocompletado: migraciones, generación de boilerplate, tests y correcciones automáticas tras detectar fallos en la terminal. No es mejor que Copilot para escribir una función; es más útil cuando la tarea implica múltiples archivos y ejecución de CLI.

    Ventajas reales:

    • Orquestación multi-archivo y ejecución de comandos.
    • Correcciones automáticas tras leer stack traces.
    • Generación de tests y refactors repetibles.

    Limitaciones reales:

    • Consumo alto de contexto/token en sesiones largas.
    • Riesgo de sobreescritura si la instrucción es ambigua.
    • Posible bucle de corrección ante errores complejos.

    Decisión simple: úsalo para tareas de orquestación; no para retoques visuales ni diseño fino de UI.

    Preparación: cómo darle contexto al agente

    Sin contexto, el agente alucina. La práctica que funciona es tener un archivo de contexto que el agente lea antes de actuar. Crea CLAUDE.md en la raíz:

    # CLAUDE: reglas del repo
    Stack:
    - Backend: NestJS 10 (TypeScript estricto)  https://nestjs.com/
    - Frontend: Angular 17 (standalone components, Signals)  https://angular.io/
    
    Convenciones:
    - DTOs con class-validator
    - Servicios inyectados por constructor
    - Componentes standalone, sin NgModules
    - Commits en Conventional Commits
    

    Ese archivo actúa como prompt persistente. Reduce alucinaciones arquitectónicas y mejora resultados.

    Tutorial práctico: flujo real con NestJS y Angular

    Objetivo: crear recurso Products en backend (NestJS) y consumirlo desde Angular, con tests básicos.

    1) Generar recurso en NestJS

    En la carpeta del backend:

    # instrucción al agente
    claude "Lee CLAUDE.md. Genera recurso Products en NestJS: Controller, Service, DTO CreateProductDto con class-validator. Ejecuta npm run build y corrige errores."
    

    Qué hará:

    • Ejecutará nest g res products o creará manualmente los archivos.
    • Insertará DTOs con validaciones (@IsString, @IsNumber).
    • Ejecutará npm run build; si TypeScript falla, leerá el stack trace y aplicará correcciones iterativas.

    Ejemplo mínimo de DTO que el agente debe crear:

    // create-product.dto.ts
    import { IsString, IsNumber } from 'class-validator';
    export class CreateProductDto {
      @IsString()
      name: string;
    
      @IsNumber()
      price: number;
    }
    

    2) Consumir endpoint desde Angular

    En la carpeta del frontend:

    claude "Crea ProductService usando provideHttpClient y un componente ProductFormComponent standalone. Usa Signals para estado de formulario. Ejecuta ng build y corrige tipados."
    

    Qué esperar:

    • Creación de product.service.ts con funciones que llaman al endpoint.
    • ProductFormComponent standalone con Signals para isLoading y errors.
    • ng build que verifica tipado y dependencias; el agente corrige importaciones o tipos si hay fallos.

    Fragmento esperado en Angular:

    // product.service.ts (simplificado)
    import { inject } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    export const ProductService = () => {
      const http = inject(HttpClient);
      return {
        create: (payload: any) => http.post('/api/products', payload)
      };
    };
    

    3) Generar tests automatizados

    Comando recomendado:

    claude "Genera tests Jest para products.service.ts y products.controller.ts. Ejecuta npm run test y corrige mocks hasta que la suite pase."
    

    Valor: te ahorra el 70% del trabajo repetitivo de mocks y boilerplate.

    Riesgos y contramedidas operativas

    1. Trabaja siempre en una rama aislada:
      git checkout -b feat/claude-codex
      – Nunca en main o develop.
    2. Limita la ventana de contexto:
      – Corta sesiones largas. Ejecuta tareas atómicas y revisa resultados antes de continuar.
    3. Evita permisos globales de escritura en archivos sensibles:
      – Usa .claudeignore para bloquear rutas (si la herramienta lo soporta) o un wrapper que restrinja paths.
    4. Plan para fallos en node_modules:
      – Si entra en bucle, interrumpe y ejecuta npm ci o reinstala dependencias; luego reintenta con más contexto.

    Checklist para adopción en equipo

    • [ ] CLAUDE.md con convenciones del repo.
    • [ ] Branching obligatorio para sesiones de agente.
    • [ ] Scripts de CI que validen outputs generados por el agente.
    • [ ] Monitoreo de consumo de API/tokens.
    • [ ] Política interna para revisar commits automáticos antes de merge.

    Claude Code no es una varita mágica; es una herramienta poderosa si la gobiernas. Si empiezas documentando el proyecto y limitando sus permisos, te dará horas de productividad en tareas repetitivas y orquestación. Si no, corregirás borradores y rollbacks a mano. La diferencia está en las reglas y la disciplina.

    Relacionado: visita Dominicode Labs para ver experimentos y guías sobre agentes y automatización. Esta mención encaja como continuación lógica para equipos que exploran flujos de IA aplicada y agentes.

    FAQ

    ¿Qué es Claude Code y para qué sirve?

    Claude Code es un agente diseñado para orquestar tareas que implican múltiples archivos y comandos de terminal: migraciones, generación de boilerplate, tests y correcciones automáticas tras fallos. Es especialmente útil cuando la tarea requiere ejecutar CLI y aplicar cambios iterativos.

    ¿Cuándo debería usar Claude Code en lugar de Copilot?

    Usa Claude Code cuando la tarea sea multi-archivo, requiera ejecución de comandos o correcciones a partir de stack traces. Para pequeñas funciones o autocompletado local, Copilot suele ser más eficiente.

    ¿Cómo debo preparar mi repo antes de usar el agente?

    Crea un archivo de contexto persistente (por ejemplo CLAUDE.md) con stack, convenciones y reglas del repo. Trabaja en una rama aislada y asegúrate de tener scripts de CI que validen cambios automáticos.

    ¿Qué riesgos operativos debo mitigar?

    Principales riesgos: sobreescritura de archivos, consumo excesivo de tokens en sesiones largas y bucles de corrección. Mitígalo con ramas aisladas, límites de sesión y mecanismos para restringir paths sensibles (por ejemplo .claudeignore o wrappers).

    ¿Cómo integro tests automatizados en el flujo del agente?

    Pide al agente generar tests Jest para servicios y controladores, ejecutar npm run test y corregir mocks hasta que la suite pase. Complementa con scripts de CI que validen los cambios generados antes del merge.

    ¿Qué hacer si el agente entra en bucle de correcciones?

    Interrumpe la sesión, ejecuta npm ci o reinstala dependencias, revisa el contexto y reintenta con instrucciones más atómicas y detalladas. Limitar la ventana de contexto también ayuda a evitar bucles.

  • Cómo gestionar PRs generadas por agentes en la revisión de código

    Cómo gestionar PRs generadas por agentes en la revisión de código

    Code review en equipos con agentes — qué cambia cuando el 60% del código no lo escribió un humano

    Tiempo estimado de lectura: 4 min

    • La revisión pasa de comprobación sintáctica a auditoría semántica y arquitectónica.
    • El volumen y la fatiga de revisión aumentan; los humanos agregan criterio, no velocidad pura.
    • Reglas operativas: prompts en PR, PRs pequeñas, tests deterministas y gates automáticos.
    • Responsabilidad y formación deben definirse: ownership legal y mentoría combinada hombre-máquina.

    Code review en equipos con agentes — qué cambia cuando el 60% del código no lo escribió un humano: esa frase ya debería sonar como una alarma. Si tu repositorio empieza a parecer una fábrica de PRs escritas por LLMs, no estás ante una mejora de productividad: estás ante un cambio de paradigma en la gobernanza del código.

    El problema no es que el código generado sea malo. Es que es convincente. Y lo convincente pasa sin pedir permiso por la puerta de revisión.

    Resumen rápido (lectores con prisa)

    Qué es: Código producido por agentes (LLMs/agentes automatizados) que entra al repositorio vía PR.

    Cuándo usarlo: Cuando buscas acelerar tareas repetibles, con controles automáticos y ownership claro.

    Por qué importa: Cambia la revisión de sintaxis a auditoría de dominio, coherencia y riesgos.

    Cómo funciona: Implementa gates automáticos, exige prompts en PRs, fragmenta PRs grandes y usa agentes como primer filtro.

    Cuando la mayoría del código viene de agentes

    Cuando la mayoría del código viene de agentes, la revisión deja de ser corrección ortográfica. Pasa a ser auditoría semántica, arquitectónica y de riesgos. La prioridad deja de ser “¿compile?” y pasa a ser “¿esto respeta nuestro dominio, nuestras abstracciones y nuestras reglas de operación?”.

    A partir de ahí, todo cambia: volumen de PRs, tipos de errores dominantes, responsabilidad técnica y los criterios mínimos para aceptar cambios.

    Los cuatro efectos inmediatos que verás

    1. Fatiga de revisión a escala

    Un agente puede abrir varias PRs en minutos. Leer código cuesta. El riesgo real es aprobar por inercia. No es moral; es una falla de proceso.

    2. Ruido ejecutivo: syntactic correctness ≠ business correctness

    Linters y tipado son una alfombra. Bajo ella puede haber duplicaciones, incompatibilidades con contratos internos o decisiones de diseño rotas.

    3. Pérdida de contexto global

    Los agentes funcionan bien en ámbitos locales. Fallan cuando hay decisiones históricas, utilidades compartidas o patrones no escritos. El repo se fragmenta si nadie vigila la coherencia.

    4. Reasignación del valor humano

    El humano deja de competir en velocidad y pasa a proporcionar criterio: editor, arquitecto y protector de deuda técnica.

    Reglas prácticas para revisar PRs generadas por IA

    Obligatoriedad del prompt en la PR

    Cada PR que provenga de un agente debe incluir: el prompt completo, parámetros del agente (temperature, model, herramientas usadas) y, si aplica, los snippets intermedios que el agente evaluó. Sin esto, rechaza la PR.

    PRs pequeñas y cambiables

    Límite duro: <400 líneas por PR. Si un agente genera más, fracciona. Revisa unidades pequeñas y reusables, no borradores monolíticos.

    Pipeline que no negocia: tests + validadores automáticos

    Nada pasa si no hay tests deterministas. Añade validadores automatizados (SAST, DAST, complejidad ciclomática) y gates en CI que bloqueen merges hasta cumplir umbrales.

    Agentes revisando a agentes (primer filtro)

    Usa workflows (p. ej. n8n) para que un agente verificador haga la primera pasada: seguridad, duplicados, dependencias nuevas. Solo PRs filtradas llegan a humanos.

    Código como contrato: exige integraciones con Code Owners

    Que las áreas propietarias (backend, auth, shared-utils) deban aprobar cambios automáticos en su zona. No delegues ownership a un bot.

    Criterios claros para aprobar o rechazar (chequeo rápido)

    Aprueba manualmente si:

    • Prompt incluido y comprensible.
    • PR ≤ 400 líneas.
    • Tests cubren casos límite relevantes.
    • No introduce dependencias externas sin aprobación.
    • Integra con abstractions/shared modules existentes.

    Rechaza o solicita rework si:

    • No hay prompt o está incompleto.
    • Replica utilidades existentes.
    • Falla validadores automáticos de seguridad o complejidad.
    • No hay evidencia de decisión humana sobre trade-offs.

    Riesgos no técnicos que debes tener en cuenta

    Responsabilidad y ownership: una vulnerabilidad surgida de un output de IA que fue aprobada por cansancio recae en personas y procesos. Define legalmente quién firma cambios críticos.

    Formación del equipo: si los juniors solo “pegotean” código generado, la curva de aprendizaje se aplana. Plan de mentoría obligatorio: revisiones combinadas hombre-máquina para formación.

    Conclusión: el criterio gana peso

    Si 60% del código viene de agentes, tu ventaja competitiva no estará en cuánto puedes generar, sino en cuánto puedes coordinar, auditar y dar criterio sobre ese output. El trabajo humano deja de ser teclear y pasa a ser decidir.

    ¿Quieres dejar de sufrir LGTM y convertir a tus agentes en productores útiles en lugar de ruido? Empieza por exigir prompts en cada PR, probar todo y automatizar el primer filtro con agentes. Si lo haces, ganarás velocidad sin perder control.

    Apúntate a la newsletter de Dominicode para recibir plantillas de prompts, ejemplos de pipelines en n8n y una checklist lista para aplicar mañana.

    Dominicode Labs

    Si trabajas con automatización, IA aplicada, n8n, agentes o workflows, puedes encontrar recursos y ejemplos prácticos en Dominicode Labs. Es una continuación lógica para plantillas de prompts y pipelines aplicables de inmediato.

    FAQ

    Respuesta: Cada PR debe incluir el prompt completo, parámetros del agente (por ejemplo: temperature, model, herramientas usadas) y los snippets intermedios que el agente evaluó. Sin esto, la PR debe rechazarse.

    Respuesta: Aplica un límite duro: <400 líneas por PR. Si un agente genera más, fracciona en unidades pequeñas y revisables. Revisa unidades reusables, no borradores monolíticos.

    Respuesta: Nada debe pasar sin tests deterministas. Añade validadores automatizados (SAST, DAST, complejidad ciclomática) y gates en CI que bloqueen merges hasta cumplir umbrales.

    Respuesta: Usa workflows para que un agente verificador haga la primera pasada (seguridad, duplicados, dependencias). Ejemplo de herramienta citada: n8n. Solo las PRs filtradas llegan a revisión humana.

    Respuesta: La responsabilidad recae en personas y procesos si una vulnerabilidad aprobada por cansancio entra en producción. Define legalmente quién firma cambios críticos.

    Respuesta: Implementa un plan de mentoría obligatorio: revisiones combinadas hombre-máquina para asegurar que los juniors aprendan criterio, no solo a pegar código generado.

  • Cómo garantizar la confiabilidad del código generado por IA

    Cómo garantizar la confiabilidad del código generado por IA

    Vibe Coding: la trampa del 84%

    Tiempo estimado de lectura: 3 min

    Ideas clave

    • El 84% de desarrolladores usa IA a diario, pero solo el 29% confía en el código generado — la brecha es riesgo operativo.
    • Los LLMs generan código verosímil pero frágil: happy-paths, alucinaciones de API y antipatrones a escala.
    • Auditoría práctica: validar dependencias, exigir sad-paths desde el prompt, tests humanos para edge cases, auditar queries y requerir métricas.
    • Aplicar Zero Trust: checklist de confianza y CI que impida merges sin cobertura e instrumentación.

    Introducción

    Vibe Coding: la trampa del 84% no es un titular sensacionalista: es una advertencia práctica. El 84% de los desarrolladores usa IA diariamente, pero solo el 29% confía en el código que obtiene. Esa brecha no es una estadística; es un agujero por donde entra la deuda técnica, la fuga de datos y las regresiones en caliente. (Fuente: Stack Overflow Developer Survey 2024)

    Este artículo te da un marco operativo: cómo revisar, auditar y —sobre todo— confiar en código generado por modelos de lenguaje sin que la velocidad mate la fiabilidad.

    Resumen rápido (lectores con prisa)

    Los LLMs generan código verosímil pero no garantizan manejo de errores ni adaptación al dominio. Valida dependencias, exige sad-paths desde el prompt, escribe tests humanos para edge cases y exige métricas y trazas antes de mergear.

    Vibe Coding: la trampa del 84% — por qué sucede y qué rompe

    El problema no es que la IA escriba mala sintaxis. Es que escribe código verosímil. Y lo verosímil engaña al ojo. Un LLM predice tokens; no entiende tu dominio, tus SLAs ni tu topología de datos. Eso genera tres fallos constantes:

    • Happy-path en serie: el código funciona cuando todo va bien. No maneja latencias, timeouts o datos corruptos.
    • Alucinaciones de API: métodos que “suenan” correctos pero no existen en tu versión de la librería.
    • Antipatrones a escala: consultas N+1, bloqueos por locks mal usados, o rutas críticas sin instrumentación.

    Aceptar ese output sin auditoría es como aceptar un merge request sin tests: rápido, pero peligroso.

    Auditoría práctica: pasos que aplicas hoy mismo

    Cambia tu rol: con IA, no recibes código; recibes la propuesta de un “junior hiperproductivo”. Revíalo como tal.

    1) Valida dependencias antes de instalar

    • No copies imports sin comprobar. Busca la API en la documentación oficial.
    • Consulta npm para fecha de publicación y descargas.
    • Ejecuta npm audit tras añadir paquetes y antes de mergear. Herramienta: docs.npmjs.com/cli/v9/commands/npm-audit

    2) Obliga el Sad Path desde el prompt

    • No pidas solo “la función”. Pide manejo de fallos, retries y logging contextual.
    • Prompt débil: “Genera una función que llame a la API de pagos”
    • Prompt fuerte:
      "Genera una función que llame a la API de pagos. Incluye:
       - timeout y retry con backoff exponencial,
       - logging con requestId y contexto,
       - pruebas de unidad para timeouts y respuestas 5xx,
       - no devolver datos sensibles en la respuesta."

    3) Tests: el humano decide los edge cases

    • No dejes que la IA escriba tanto la función como los tests críticos.
    • Define tú los casos límite y las aserciones. La IA puede generar mocks y el setup repetitivo.
    • Cubre: inputs inválidos, latencias extremas, concurrencia (race conditions) y fallos de autenticación.

    4) Base de datos: audita las queries antes de producción

    • Habilita logging de queries en dev y revisa el número de hits por operación.
    • Verifica índices para columnas filtradas.
    • Comprueba serialización de objetos para no exponer campos sensibles.

    5) Métricas y observabilidad como contrato

    • Exige que cualquier cambio generado incluya: métricas (latencia, error rate), trazas correlacionadas y logs estructurados.
    • Si el PR no contiene instrumentación mínima, reviértelo.

    Checklist de confianza (Zero Trust aplicado)

    • [ ] Prompts que exigen Sad Path y límites de recursos.
    • [ ] Dependencias verificadas y npm audit limpio.
    • [ ] Tests escritos por humanos para edge cases críticos.
    • [ ] Logging y tracing incluidos en el cambio.
    • [ ] Revisión de queries e índices en DB.
    • [ ] Branch aislado y CI que rechaza merge sin cobertura mínima.

    Cuándo delegar y cuándo no

    Usa IA para acelerar tareas repetitivas y de bajo riesgo:

    • Boilerplate, DTOs, validaciones simples, plantillas de tests, conversiones de sintaxis.

    No delegues a la IA decisiones de criterio:

    • Modelado de dominio, reglas de autorización, diseño de esquemas, SLAs o decisiones que impacten seguridad y privacidad.

    Cierre directo

    La diferencia entre el 84% que usa IA y el 29% que confía en ella no es tecnología: es proceso y criterio. Si tu equipo aprende a auditar como si cada PR viniera de un “junior sin contexto”, reducirás fallos graves sin renunciar a la velocidad.

    La IA debe ahorrar tipeo; no debe asumir la responsabilidad arquitectónica. Haz que ese sea tu contrato interno hoy.

    Una continuación práctica y recursos relacionados están disponibles en Dominicode Labs, donde se publican frameworks y workflows para auditoría y observabilidad integrables en equipos que usan IA.

    FAQ

    ¿Por qué no confiar de entrada en código generado por IA?

    Porque los LLMs generan código verosímil sin comprender tu dominio, SLAs o topología de datos. Ese código puede funcionar en happy-paths pero fallar en latencia, datos corruptos o versiones de librerías.

    ¿Qué preguntas agregar al prompt para obtener código más fiable?

    Exige manejo de fallos, retries con backoff, timeouts, logging contextual (requestId), pruebas unitarias para errores 5xx y restricciones sobre datos sensibles.

    ¿Cómo validar dependencias antes de instalarlas?

    Comprueba la API en la documentación oficial, revisa fecha de publicación y descargas en npm y ejecuta npm audit tras añadir paquetes y antes de mergear.

    ¿Qué tests deben escribir los humanos?

    Los humanos deben definir y escribir tests para edge cases críticos: inputs inválidos, latencias extremas, condiciones de carrera y fallos de autenticación. La IA puede generar mocks y setups repetitivos.

    ¿Qué instrumentación mínima exigir en un PR?

    Métricas de latencia y tasa de error, trazas correlacionadas y logs estructurados. Si el PR no contiene instrumentación mínima, debería revertirse.

    ¿Cuándo es apropiado delegar tareas a la IA?

    Para tareas repetitivas y de bajo riesgo: boilerplate, DTOs, validaciones simples, plantillas de tests y conversiones de sintaxis. No para modelado de dominio, reglas de autorización, diseño de esquemas o decisiones que afecten seguridad y privacidad.

  • Cómo implementar un loop de agente efectivo para LLM en producción

    Cómo implementar un loop de agente efectivo para LLM en producción

    El loop de agente que sí funciona en producción

    Tiempo estimado de lectura: 5 min

    • Contrato y salida clara: fuerza una condición de salida semántica explícita (herramienta finalizar / AgentFinish con respuesta_final).
    • Validación antes de actuar: validar payloads con Pydantic y devolver errores estructurados como observaciones.
    • Errores como contexto: convertir fallos de herramientas en observaciones legibles (p. ej. ERROR_TOOL: nombre — detalle).
    • Límites y circuit breakers: limitar iteraciones con MAX_STEPS y cortar si el mismo error aparece repetidamente.

    ¿Quieres que tu agente deje de repetir el mismo error a las 3 a. m. y empiece a resolver problemas reales? El loop de agente que sí funciona en producción es exactamente eso: una celda de contención determinista alrededor de un motor estocástico.

    En las primeras líneas: El loop de agente que sí funciona en producción obliga al agente a operar con contratos claros (plan), validar antes de actuar (act), convertir fallos en contexto (observe) y respetar límites duros (reflect). Si no aplicas estas reglas, el agente acabará en bucles infinitos, consumiendo tokens y creando deuda técnica.

    Resumen rápido (lectores con prisa)

    Qué es: un patrón de control que encierra un LLM estocástico en un loop determinista con contratos claros y límites.

    Cuándo usarlo: flujos síncronos y de corta duración (consultas DB, enriquecimiento, generación de artefactos pequeños).

    Por qué importa: evita bucles infinitos, reduce deuda técnica y mejora la capacidad de recuperación ante errores de herramienta.

    Cómo funciona: usar una herramienta de cierre (finalizar), validar entradas con Pydantic, registrar errores como observaciones y aplicar límites de iteración.

    El loop de agente que sí funciona en producción: diseño y principios

    Los LLMs no tienen intención ni memoria fiable. Son modelos probabilísticos que requieren disciplina del lado del ingeniero. Esto significa aplicar cuatro reglas innegociables:

    1. Forzar una condición de salida semántica explícita

    Define la herramienta de cierre del flujo. Llama a la función finalizar o AgentFinish y exige que incluya respuesta_final. Ese es el interruptor lógico que separa “sigo pensando” de “he terminado”.

    2. Validar todos los argumentos antes de ejecutar herramientas

    Valida con Pydantic cada payload que el modelo devuelve. Si no pasa validación, no ejecutes nada: devuelve el error al agente como observación estructurada.

    3. Inyectar errores técnicos al historial como observaciones

    Si una herramienta falla (timeout, DB deadlock, error de tipo), captura la excepción y agrega al historial un mensaje tipo: “ERROR_TOOL: nombre — detalle”. No ocultes fallos: convertirlos en contexto mejora la capacidad del agente para corregir su siguiente plan.

    4. Imponer límites duros de iteración y circuit breakers semánticos

    Finalmente, limita las iteraciones con MAX_STEPS. Si el agente alcanza ese límite, devuelve un error controlado y registra el incidente. Implementa circuit breakers si el mismo error aparece repetidamente.

    Ejemplo práctico en Python

    Aquí tienes un esqueleto funcional, pensado para integrarse con cualquier cliente LLM que soporte tool-calling. Incluye validación Pydantic y la inyección de errores al historial.

    import json
    from pydantic import BaseModel, ValidationError
    
    MAX_STEPS = 5
    
    # Ejemplo de validator para una tool
    class CreateTicketArgs(BaseModel):
        title: str
        priority: str  # 'low'|'medium'|'high'
    
    # Simulación de herramientas
    def create_ticket(title: str, priority: str):
        # lógica real aquí (DB, API)
        return {"ticket_id": "TCK-123", "title": title, "priority": priority}
    
    TOOLS = {
        "create_ticket": (create_ticket, CreateTicketArgs),
        # "finalizar" no necesita validator complejo; solo espera respuesta_final
    }
    
    def run_agent(user_prompt: str, llm_client) -> str:
        messages = [
            {"role": "system", "content":
             "Eres un agente. Devuelve siempre JSON con 'tool_call' o 'final_text'. "
             "Usa la herramienta 'finalizar' con {'respuesta_final': '...'} para terminar."},
            {"role": "user", "content": user_prompt}
        ]
    
        seen_errors = {}
        for step in range(MAX_STEPS):
            response = llm_client.chat(messages=messages, tools=get_tool_schemas(TOOLS))
    
            # respuesta textual sin tool_call
            if response.finish_reason == "stop" and not response.tool_calls:
                return response.content
    
            for tc in response.tool_calls:
                name = tc.name
                args_raw = json.loads(tc.arguments)
    
                if name == "finalizar":
                    return args_raw.get("respuesta_final", "")
    
                tool_fn, validator = TOOLS[name]
    
                # VALIDACIÓN (Act)
                try:
                    args = validator(**args_raw)
                except ValidationError as ve:
                    observation = f"VALIDATION_ERROR: {ve.json()}"
                    messages.append({"role": "assistant", "content": response.content})
                    messages.append({"role": "tool", "tool_call_id": tc.id, "content": observation})
                    # registro para circuit breaker
                    seen_errors.setdefault(str(ve), 0)
                    seen_errors[str(ve)] += 1
                    if seen_errors[str(ve)] >= 2:
                        return f"Interrumpido: error recurrente de validación: {ve}"
                    continue
    
                # EJECUCIÓN segura (Observe)
                try:
                    result = tool_fn(**args.dict())
                    observation = f"RESULT: {json.dumps(result)}"
                except Exception as e:
                    observation = f"ERROR_TOOL: {name} — {str(e)}"
                    seen_errors.setdefault(str(e), 0)
                    seen_errors[str(e)] += 1
                    if seen_errors[str(e)] >= 2:
                        return f"Interrumpido: error recurrente en herramienta: {e}"
    
                messages.append({"role": "assistant", "content": response.content})
                messages.append({"role": "tool", "tool_call_id": tc.id, "content": observation})
    
        return "Error: el agente superó el límite de pasos permitidos."

    Operaciones que debes instrumentar desde el día uno

    • Logging estructurado por paso: step, tool, args, resultado, tokens consumidos.
    • Conteo de tokens del historial; si supera el 75–80% de la ventana del modelo, ejecuta resumen (ver técnicas de resumen).
    • Circuit breaker semántico: si el mismo error aparece dos veces, corta y alerta.
    • Métricas SLIs: tiempo por petición, reintentos por herramienta, tasa de finalización exitosa.

    Cuándo no usar este loop y optar por orquestación

    Usa este loop en procesos síncronos y de corta duración: consultas DB, enriquecimiento de datos, generación de artefactos pequeños. Si tu flujo dura horas/días, incluye pasos humanos o requiere durabilidad de estado, cambia a un orquestador (n8n, LangGraph) que persista estado y permita reprogramación.

    Cierre práctico

    El loop de agente que sí funciona en producción no es una trick de prompts: es ingeniería. Forzar salida semántica (finalizar), validar antes de actuar (Pydantic), convertir fallos en contexto y aplicar límites duros son las piezas que convierten un prototipo ruidoso en un agente fiable. Implementa esto, instrumenta y repite: la estabilidad viene de la disciplina, no de la magia.

    Para recursos experimentales y proyectos relacionados con automatización y agentes, considera explorar los trabajos y laboratorios prácticos en Dominicode Labs. Es una referencia contextual para implementar pipelines y pruebas prácticas en entornos de ingeniería.

    FAQ

    ¿Cuál es la función de la herramienta finalizar?

    Es el interruptor semántico que indica que el agente ha terminado su trabajo. Debe devolver un objeto que incluya respuesta_final, que el loop interpreta como salida definitiva.

    ¿Por qué usar Pydantic para validar payloads?

    Porque ofrece validación estructurada y errores claros. Validar evita ejecuciones inseguras y permite convertir fallos en observaciones reutilizables por el agente.

    ¿Qué hacer si una herramienta externa falla repetidamente?

    Registrar el fallo como ERROR_TOOL: nombre — detalle, aplicar un circuit breaker y, si el error se repite, interrumpir el loop con un error controlado para evitar consumo indefinido de recursos.

    ¿Cómo definir MAX_STEPS?

    Depende del dominio y del coste por iteración. Empieza con un valor conservador (p. ej. 5) y monitoriza reintentos y tiempo por petición para ajustarlo.

    ¿Cuándo prefiero un orquestador en lugar de este loop?

    Si el flujo requiere durabilidad, pasos humanos o puede durar horas/días, usa un orquestador como n8n o LangGraph para persistir estado y reintentar tareas.

    ¿Qué métricas debo recolectar desde el día uno?

    Tiempo por petición, reintentos por herramienta, tasa de finalización exitosa, conteo de tokens y registros estructurados por paso (tool, args, resultado).

  • Cómo mejorar la calidad del código con Spec-Driven Development

    Cómo mejorar la calidad del código con Spec-Driven Development

    Spec-Driven Development en la práctica: del prompt al código mantenible — Un walkthrough real mostrando cómo una buena spec cambia la calidad del output de Claude Code o Cursor. Caso antes/después

    Tiempo estimado de lectura: 6 min

    • Ideas clave:
    • Una spec técnica reduce la ambigüedad en prompts y convierte salidas generativas en contratos verificables.
    • Sin spec, los LLMs tienden a producir código rápido pero frágil y con deuda técnica.
    • Una spec mínima (stack, artefactos, contratos, edge cases) es suficiente para outputs reproducibles y testeables.
    • Integra specs en CI/PR para automatizar comprobaciones y mantener control humano sobre arquitectura.

    Spec-Driven Development en la práctica: del prompt al código mantenible — esto no es una etiqueta elegante. Es la diferencia entre código que sobrevive y código que tendrás que reescribir dentro de tres sprints. Si usas Claude Code, Cursor o cualquier herramienta generativa, sin una spec clara estás empujando decisiones arquitectónicas a un modelo estadístico.

    En estas primeras líneas: definimos el problema, mostramos un caso antes/después y entregamos una receta práctica para que tu equipo obtenga salidas reproducibles y revisables por humanos.

    Resumen rápido (lectores con prisa)

    Qué es: Una spec técnica es un documento corto que define stack, artefactos, contratos de datos y criterios de aceptación.

    Cuándo usarla: Antes de pedirle a un LLM que genere código o acciones automáticas; imprescindible para features que afectan arquitectura o seguridad.

    Por qué importa: Reduce ambigüedad, limita el espacio de decisión del modelo y convierte output en un contrato auditables y testeable.

    Cómo funciona: Provee stack y contratos (ej. Zod schemas, tipos TS, API contracts) que el agente implementa exactamente, produciendo artefactos modulares y testeables.

    Por qué una spec cambia todo

    Los LLMs son excelentes en patrones, no en contexto de producto. Cuando reciben un prompt abierto, generan la solución más probable según su entrenamiento: ejemplos de tutoriales y antipatrón comunes. Esa es la razón por la que el output suele ser rápido pero frágil.

    Una especificación técnica (spec) reduce el “espacio de probabilidad” del modelo. Le das:

    • el stack exacto,
    • las restricciones arquitectónicas,
    • los contratos de datos,
    • y los criterios de aceptación/edge cases.

    Con esa entrada, herramientas como Cursor o Claude dejan de improvisar y comienzan a implementar un contrato.

    Walkthrough real: formulario de registro en Next.js

    Escenario: crear un registro de usuario con validación Zod y Server Actions (Next.js App Router). Te muestro el antes y el después, sin adornos.

    Antes — Prompt conversacional (vibe coding)

    Prompt enviado al modelo:

    “Crea un formulario de registro en Next.js con email, password y confirmación. Conéctalo a la API.”

    Salida típica:

    • Un solo archivo RegisterForm.tsx con JSX, estado useState y fetch mezclados.
    • Validación DIY con regex.
    • Manejo de errores = console.log.
    • Tipos débiles (any o sin tipos).
    • No hay tests ni contractos reutilizables.

    Resultado: funciona en local. Falla en producción. Es deuda técnica con firma.

    Después — Prompt con spec (Spec-Driven Development)

    Antes de preguntar al modelo, escribes spec-auth-register.md y lo adjuntas.

    Fragmento de spec:

    # Spec: Registro de usuario
    Stack: Next.js App Router, React Hook Form, Zod
    Outputs: 3 archivos
      - src/lib/validations/auth.ts (registerSchema)
      - src/actions/auth.actions.ts (Server Action) -> devuelve { success: boolean; error?: string }
      - src/components/auth/RegisterForm.tsx
    UI: usar useTransition para isPending; mostrar errores por campo; redirigir a /dashboard en éxito.
    Edge cases: handling de timeouts, duplicados, validación server-side.
    

    Prompt al modelo:

    “Lee @spec-auth-register.md e implementa exactamente los archivos descritos, respetando tipos y contratos.”

    Salida típica con spec:

    • registerSchema en auth.ts (Zod) reutilizable en cliente y servidor.
    • Server Action tipada que devuelve { success, error }.
    • Componente de presentación que usa React Hook Form y solo hace binding.
    • Estados de UI y manejo de errores explícito.
    • Código modular, testeable y legible.

    La diferencia es clara: la spec obliga al modelo a ceñirse a un contrato verificable. Lo que se genera se puede code-reviewar, testear e integrar.

    Plantilla mínima de spec que funciona

    No necesitas escribir una novela. Esta plantilla (portable en .specs/feature.md) es suficiente:

    1. Contexto de negocio (1-2 líneas).
    2. Stack y restricciones (libraries permitidas/prohibidas).
    3. Artefactos esperados (files + path).
    4. Contratos de datos (TS interfaces o Zod schemas).
    5. Estados UI y criterios de aceptación.
    6. Edge cases y métricas de éxito.

    Incluye URLs útiles en la spec para librerías: Zod, OWASP para seguridad, documentación de Cursor si lo usas.

    Integración práctica en el flujo de trabajo

    • Guarda specs en .specs/ y referencia el archivo en el prompt (Cursor soporta @Files).
    • Automatiza comprobaciones básicas con linters/CI: que exista un schema Zod, que acciones devuelvan un tipo estándar, que tests unitarios pasen.
    • Añade una regla en code review: si el cambio viene de un agente, el PR debe acompañar la spec original y un ADR si la modificación afecta arquitectura.
    • No olvides observabilidad y testing: cada tool o action generada debe tener tests unitarios independientes del LLM.

    Conclusión: la IA ejecuta, el ingeniero decide

    Spec-Driven Development no elimina la IA; la pone en su lugar. En lugar de confiar en la creatividad del modelo, confías en el criterio técnico del equipo para dirigirlo. Los equipos que adoptan specs claras convierten a Claude Code y Cursor en herramientas productivas en lugar de fuentes de deuda técnica. Implementar specs no es una carga extra: es la inversión que transforma prototipos de IA en software mantenible y auditable.

    La siguiente pieza en esta serie mostrará ejemplos de specs reales y scripts de CI que validan la conformidad automática entre spec y código.

    Para continuidad con iniciativas de automatización y prácticas de ingeniería aplicadas a IA, revisa recursos adicionales y experimentos en Dominicode Labs. Estos materiales complementan la adopción de specs y proporcionan plantillas y scripts para integrar comprobaciones automatizadas en CI/PR.

    FAQ

     

    ¿Qué es una spec técnica y cuánto debe medir?

    Una spec técnica es un documento conciso que define contexto, stack, artefactos requeridos, contratos de datos y criterios de aceptación. Suele medir entre 1 y 2 páginas; la clave es ser suficiente para convertir decisiones arquitectónicas en reglas ejecutables.

     

    ¿Qué diferencia hay entre una spec y una historia de usuario?

    Una historia de usuario describe el problema de negocio y la necesidad. La spec técnica traduce esa necesidad en artefactos técnicos concretos (files, tipos, contratos, edge cases) que un agente o desarrollador implementará.

     

    ¿Qué herramientas debo pedir en la spec para validación de datos?

    Especifica la librería (por ejemplo, Zod), el archivo donde residirá el schema y el contrato de retorno esperado para server actions. Indica validación client/server y casos límite relevantes.

     

    ¿Cómo integro specs en CI?

    Automatiza comprobaciones que verifiquen la presencia de schemas Zod, la firma de acciones y tests unitarios mínimos. Añade una regla en PRs que requiera la spec original cuando cambios provengan de un agente.

     

    ¿Qué hacer si el LLM ignora la spec?

    Ajusta el prompt para referenciar explícitamente la spec (ej. @spec-auth-register.md), valida output contra tests automatizados y rechaza cambios que no cumplan contratos en CI. Mantén revisión humana obligatoria para PRs generados por agentes.

  • Resource API en Angular 22: el fin del subscribe() manual

    Resource API en Angular 22: el fin del subscribe() manual

    Revisé hace poco un componente de Angular que cargaba una lista de productos. Contaba los observables con los dedos: un BehaviorSubject para la categoría seleccionada, un switchMap hacia HttpClient, un catchError para los fallos, un takeUntilDestroyed para no dejar suscripciones vivas, y al final, un async pipe en el template.

    Todo correcto. Todo necesario. Y todo código que explica exactamente lo mismo que cualquier otro componente de carga de datos en la aplicación. La Resource API de Angular 22 resuelve exactamente este problema.

    Ese patrón tiene quince años. Angular 22 tiene la respuesta definitiva.

    Qué es la Resource API y por qué existe

    La Resource API es el mecanismo nativo de Angular para gestionar operaciones asíncronas dentro del sistema de Signals. No es una librería de terceros, no es un wrapper sobre RxJS: es la pieza que faltaba para que el modelo reactivo de Angular estuviera completo.

    La idea central es sencilla: tienes un signal que representa un parámetro (un ID, un filtro, una página), y quieres que Angular haga automáticamente el fetch cuando ese parámetro cambia. Sin subscribe, sin pipe, sin gestión manual del ciclo de vida.

    En Angular 22 el ecosistema completo se compone de tres APIs:

    • resource() — fetch genérico con Promise. Estable en v22.
    • rxResource() — puente para servicios basados en Observable. Estable en v22.
    • httpResource() — wrapper declarativo sobre HttpClient. Experimental en v22.

    El matiz de los estados de estabilidad importa. resource() y rxResource() ya son API pública con garantías de compatibilidad. httpResource() sigue marcado como experimental — la API puede cambiar. Para producción crítica, ten eso en cuenta.

    resource(): el punto de entrada

    Usa resource() cuando el origen de datos es una Promise o una función fetch directa. El parámetro reactivo se define en params, y la función que carga los datos en loader.

    import { ChangeDetectionStrategy, Component, signal, resource } from '@angular/core';
    

    interface Producto { id: number; nombre: string; }

    @Component({ selector: 'app-catalogo', changeDetection: ChangeDetectionStrategy.OnPush, template: ` @switch (productos.status()) { @case ('loading') { <p>Cargando...</p> } @case ('reloading') { <p>Actualizando...</p> } @case ('error') { <p>Error: {{ productos.error() }}</p> } @default { @if (productos.hasValue()) { <ul> @for (p of productos.value(); track p.id) { <li>{{ p.nombre }}</li> } </ul> } } } <button (click)="categoria.set(categoria() + 1)">Siguiente</button> <button (click)="productos.reload()">Recargar</button> `, }) export class CatalogoComponent { categoria = signal(1);

    productos = resource<Producto[], { cat: number }>({ params: () => ({ cat: this.categoria() }), loader: ({ params, abortSignal }) => fetch(/api/products?category=${params.cat}, { signal: abortSignal }) .then(r => r.json()), }); }

    Dos errores que verás en código antiguo o en tutoriales desactualizados:

    • El campo se llama params, no request. Eso era la API experimental anterior.
    • Los estados son strings literales: 'loading', 'reloading', 'error'ResourceStatus no es un enum TypeScript nativo — es un objeto de constantes (as const), así que se compara con strings literales, no con ResourceStatus.Loading.

    Cuando categoria cambia, Angular cancela el fetch anterior (usando el abortSignal que recibe el loader) y lanza uno nuevo. El ciclo de vida completo, gestionado sin escribir una sola línea de cleanup.

    rxResource(): para servicios que devuelven Observables

    La mayoría de proyectos Angular tienen servicios basados en HttpClient que devuelven Observable. Migrar todo a fetch puro no es viable ni deseable.

    rxResource() es el puente. En lugar de loader, usa stream, que devuelve un Observable.

    import { ChangeDetectionStrategy, Component, signal, inject } from '@angular/core';
    import { rxResource } from '@angular/core/rxjs-interop';
    import { HttpClient } from '@angular/common/http';
    

    interface Producto { id: number; nombre: string; }

    @Component({ selector: 'app-catalogo-rx', changeDetection: ChangeDetectionStrategy.OnPush, template: ` @if (productos.isLoading()) { <p>Cargando...</p> } @else if (productos.hasValue()) { <ul> @for (p of productos.value(); track p.id) { <li>{{ p.nombre }}</li> } </ul> } `, }) export class CatalogoRxComponent { private http = inject(HttpClient); categoria = signal(1);

    productos = rxResource({ params: () => ({ cat: this.categoria() }), stream: ({ params }) => this.http.get<Producto[]>(/api/products?category=${params.cat}), }); }

    Dos puntos que generan confusión frecuente:

    • El import correcto es @angular/core/rxjs-interop, no @angular/core.
    • El método se llama stream, no loader. Los ejemplos de versiones experimentales anteriores usaban loader, de ahí la confusión.

    httpResource(): la opción declarativa

    httpResource() va un paso más allá: elimina la necesidad de declarar un servicio intermedio para casos de fetching simple. Lo declaras directamente en el componente.

    import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
    import { httpResource } from '@angular/common/http';
    

    interface User { id: number; name: string; }

    @Component({ selector: 'app-user-profile', changeDetection: ChangeDetectionStrategy.OnPush, template: ` @if (user.isLoading()) { <p>Cargando...</p> } @else if (user.error()) { <p>Error al cargar el perfil</p> } @else if (user.hasValue()) { <p>{{ user.value()?.name }}</p> } `, }) export class UserProfileComponent { userId = signal(1);

    user = httpResource<User>(() => /api/user/${this.userId()}); }

    httpResource() expone dos signals exclusivos que no tienen resource() ni rxResource():

    • .statusCode() — el código HTTP de la respuesta (200, 404, 500…)
    • .headers() — las cabeceras de la respuesta

    Ambas son señales independientes de .status(), que sigue siendo el estado del ciclo de vida del recurso. Confundir .status() con .statusCode() es el error más frecuente al empezar con esta API.

    Para respuestas que no son JSON:

    // Texto plano
    const readme = httpResource.text(() => /docs/readme.md);
    

    // Binario const avatar = httpResource.blob(() => /api/user/${this.userId()}/avatar);

    Requiere provideHttpClient() en el bootstrap. Usa HttpClient e interceptores por debajo, así que tus interceptores de autenticación siguen funcionando sin cambiar nada.

    Recuerda que httpResource() sigue marcado como experimental en v22. Para proyectos con requisitos estrictos de estabilidad de API, usa rxResource() con tu servicio HttpClient habitual hasta que se estabilice.

    Cuándo usar cada uno

    No es una decisión complicada si tienes claros los criterios:

    | Situación | API recomendada | |—|—| | Fetch puro o API externa directa | resource() | | Tienes servicios con Observable existentes | rxResource() | | Fetching simple sin servicio intermedio (experimental) | httpResource() | | Necesitas el status code HTTP como signal | httpResource() |

    Las tres APIs comparten la misma superficie de lectura: .value(), .isLoading(), .error(), .hasValue(), .status(), .reload(). Cambiar de una a otra es mínimamente invasivo.

    Validación del dato en runtime

    El genérico de TypeScript solo existe en tiempo de compilación. Si el backend devuelve algo inesperado, httpResource() no lanzará ningún error — simplemente tendrás un objeto mal tipado en runtime.

    La opción parse existe exactamente para este caso:

    import { z } from 'zod';
    

    const UserSchema = z.object({ id: z.number(), name: z.string(), });

    user = httpResource( () => /api/user/${this.userId()}, { parse: UserSchema.parse } );

    Si el dato del backend no cumple el schema, el resource entra en estado 'error' automáticamente. Sin try/catch manual, sin runtime silencioso. Si quieres profundizar en cómo construir schemas robustos con Zod para este tipo de validación, el curso de Zod para TypeScript cubre exactamente estos patrones de producción.

    Lo que cambia en tu arquitectura

    La Resource API no elimina los servicios Angular — los reorganiza. Sigues necesitando servicios para encapsular lógica de negocio compleja, componer múltiples endpoints, o compartir estado entre componentes. Lo que elimina es el boilerplate de gestión de ciclo de vida en los componentes que simplemente cargan y muestran datos.

    Un componente que antes necesitaba un servicio, tres operadores RxJS y un takeUntilDestroyed ahora expresa la misma intención en diez líneas. La lógica no desaparece — se mueve al lugar correcto.

    Si quieres el cuadro completo — Signals, Resource API, Signal Forms, Zoneless y todo lo que llegó en v22 — el curso Angular Moderno tiene el módulo M10 dedicado íntegramente a Resource API con ejemplos sobre el proyecto ShopFlow.

    Qué hacer hoy

    Identifica en tu proyecto los componentes que tienen este patrón: signal o BehaviorSubject como parámetro, switchMap hacia HttpClient, y async pipe en el template.

    Esos son tus candidatos para migrar a rxResource(). No necesitas reescribir los servicios. Solo cambias la forma en que el componente consume el Observable.

    Empieza por un componente de solo lectura — uno que carga datos y no tiene formularios complejos. Comprueba que .status() en el template te da todo lo que necesitabas del loading$ que tenías antes.

    Si funciona ahí, tienes el patrón. El resto de la migración es repetirlo.

    Preguntas frecuentes

    ¿Cuál es la diferencia entre resource() y httpResource() en Angular 22? resource() acepta cualquier función que devuelva una Promise — puedes usarlo con fetch, con SDKs externos, o con cualquier operación asíncrona. httpResource() es un wrapper declarativo sobre HttpClient que además expone el status code HTTP y las cabeceras como signals independientes. La diferencia clave: httpResource() sigue siendo experimental en v22; resource() es API estable.

    ¿Puedo usar rxResource() si tengo servicios que devuelven Observables? Sí. rxResource() está diseñado exactamente para ese caso. En lugar de loader, defines un stream que devuelve un Observable. Tus servicios existentes no cambian — solo cambia cómo el componente los consume.

    ¿La Resource API reemplaza completamente RxJS en Angular? No. RxJS sigue siendo útil para transformaciones complejas de streams, operadores avanzados y casos donde necesitas combinar múltiples fuentes. La Resource API reemplaza el patrón subscribe/unsubscribe para carga de datos HTTP en componentes — no todos los casos de uso reactivo.

    ¿Qué ocurre con los datos en caché cuando cambia el signal de parámetros? Cuando el signal de params cambia, el resource entra en estado 'reloading' (no 'loading'). El valor anterior sigue disponible en .value() durante la recarga. Esto permite mostrar datos obsoletos mientras llegan los nuevos, en lugar de mostrar un spinner que vacía la UI. Es el comportamiento por defecto — no necesitas configurarlo.

    ¿Funciona la Resource API con Angular SSR? Sí. httpResource() usa HttpClient internamente, que ya tiene soporte de transferencia de estado para SSR. Con resource() y rxResource() necesitas gestionar tú mismo la transferencia de estado si el servidor precarga datos. La integración más limpia con SSR actualmente es a través de httpResource() o rxResource() con un servicio que use TransferState.

    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode. Ha migrado proyectos Angular en producción desde v2 hasta v22.

    Sources:

  • Construye un agente de IA en TypeScript: stack mínimo para 2026

    Construye un agente de IA en TypeScript: stack mínimo para 2026

    El stack mínimo para un agente de IA en TypeScript en 2026

    Tiempo estimado de lectura: 4 min

    Ideas clave

    • Anthropic SDK + Zod + tsx + dotenv es la combinación práctica para agentes en producción: observabilidad, tipado y control.
    • Zod como frontera: declara schemas de herramientas, valida args y convierte a JSON Schema para pasar al modelo.
    • Bucle explícito: orquesta tool-calls en un único proceso, limita iteraciones y registra cada uso.
    • No es minimalismo estético: es técnica operativa para que el equipo pueda depurar y reparar a cualquier hora.
    • Escala solo cuando métricas y requisitos lo exijan: añade memoria, orquestadores o trazas distribuidas según necesidad.

    Tabla de contenidos

    El stack mínimo propuesto es una combinación práctica y limitada de dependencias enfocadas a reducir superficie de fallo, mantener trazabilidad y controlar consumo de tokens: Anthropic SDK para el motor, Zod para contratos, tsx para ejecución TypeScript rápida y dotenv para gestionar secretos.

    Resumen rápido (lectores con prisa)

    Stack: Anthropic SDK + Zod + tsx + dotenv. Usa Zod para declarar y validar schemas de herramientas, convierte Zod a JSON Schema para pasárselo al modelo y orquesta tool-calls en un bucle explícito. Añade PostgreSQL+pgvector, orquestadores o trazas solo cuando lo exijan métricas y requisitos.

    tsx + dotenv — entorno y secretos

    tsx te permite ejecutar TypeScript directamente en Node sin compilar manualmente. En desarrollo y CI rápidos esto reduce ciclos de retroalimentación.

    dotenv mantiene las claves fuera del repo: ANTHROPIC_API_KEY, DATABASE_URL, etc. Ambos son higiene operativa, no glamour.

    Anthropic SDK — motor cognitivo directo

    Usa el SDK oficial: Anthropic SDK. Evita enrutadores genéricos que suavizan diferencias entre modelos y esconden comportamientos de tool-calling. Anthropic devuelve explícitamente cuándo el modelo quiere invocar una herramienta; tú ejecutas la función y devuelves el resultado, con control total del flujo.

    Zod — contrato entre texto probabilístico y tipos

    Zod es la frontera. Define los schemas de herramientas y valida los argumentos que el modelo genera. Convierte Zod a JSON Schema con zod-to-json-schema para declarar las herramientas al modelo. Resultado: menor tasa de alucinaciones en tool_use y errores tipo detectables y manejables.

    Por qué este stack vence en producción (ejemplos técnicos)

    1) Trazabilidad total

    Cuando el modelo pide usar una herramienta, el SDK devuelve nombre + args. Antes de ejecutar, haces schema.safeParse(args). Si falla, capturas el error, lo loggeas y agregas ese fallo al historial que reenvías al modelo. No hay retries automáticos “mágicos” que oculten la causa.

    2) Menor latencia y coste

    Un único proceso que orquesta tool-calls evita encadenados innecesarios. Si cada handoff fuera otra llamada LLM, multiplicas tokens y TTFT. Con un loop explícito controlas el número máximo de iteraciones y evitas bucles de cortesía.

    3) Menos superficie de bugs

    Las capas extra (framework + adaptadores) introducen incompatibilidades y reintentos implícitos. Tener cuatro dependencias estables reduce puntos de falla.

    El patrón de implementación: el loop explícito

    Escribes un bucle claro. Pseudodiagrama:

    1. Inicializar cliente Anthropic con la API key desde dotenv.
    2. Preparar mensajes (system + user + tool_history).
    3. Llamar a client.messages.create(…) con tool definitions derivadas de Zod.
    4. Si respuesta es texto → devolver.
    5. Si respuesta es tool_use → validar con Zod; si válido ejecutar función; añadir resultado al historial; repetir.

    Ese flujo se implementa en 30–80 líneas y es 100% controlable. No es necesario heredar de clases ni integrar callbacks crípticos.

    Validación práctica y contratos: ejemplo de herramientas

    Define una tool con Zod:

    - ticketId: z.string().regex(/^[A-Z]+-\d+$/)
    - includeComments: z.boolean().default(false)

    Convierte esto a JSON Schema y pásalo a Anthropic. Cuando el LLM devuelva args, safeParse te dice inmediatamente si se puede ejecutar. Si no, devuelves el error al modelo como contexto y le pides corrección. Ese patrón reduce las llamadas inválidas y mejora la seguridad.

    Qué no cubre este stack y cuándo añadir componentes

    • Memoria de largo plazo: integra PostgreSQL + pgvector si necesitas retrieval persistente.
    • Flujos empresariales largos (days/weeks): añade un orquestador (n8n o LangGraph) para persistencia de estado y control de aprobaciones humanas.
    • Observabilidad distribuida: añade OpenTelemetry o similar si tu cluster requiere trazas correlacionadas a escala.

    Empieza simple; añade estas piezas solo con datos que demuestren necesidad.

    Reglas operativas antes de desplegar

    • Nunca expongas una herramienta sin Zod schema.
    • Registra cada tool_use y su validación. Logs estructurados; no texto plano.
    • Limita iteraciones del loop por petición (por ejemplo, max 5 reintentos).
    • Implementa el patrón Result (ok/error) en todas las funciones ejecutadas por el agente.

    Conclusión práctica

    El stack mínimo para un agente de IA en TypeScript en 2026 devuelve poder al equipo de ingeniería: trazabilidad, tipos y control operativo. Para la mayoría de agentes productivos —consultas a APIs, limpieza de datos, consultas SQL parametrizadas— esta pila es suficiente y más fiable que una montaña de frameworks. Escala solo cuando las métricas (latencia, coste por token, fallos en producción) y los requisitos (memoria, durabilidad) lo exijan. Así evitas añadir complejidad por moda y mantienes un sistema que puedas entender, auditar y mejorar.

    Dominicode Labs

    Para quienes construyen agentes y workflows, una referencia útil y complementaria sobre prácticas operativas y plantillas de integración está disponible en Dominicode Labs. Considera consultarlo como continuación lógica al patrón de loop explícito y validación con Zod.

    FAQ

    ¿Por qué usar Anthropic SDK en vez de adaptadores genéricos?

    Porque el SDK oficial expone el comportamiento nativo del modelo (por ejemplo, tool_use) sin abstracciones que oculten diferencias entre modelos. Esto permite un control más preciso sobre cuándo y cómo ejecutar herramientas.

    ¿Cuál es el papel exacto de Zod en este stack?

    Zod define los schemas de las herramientas y valida los argumentos generados por el modelo. Convertir esos schemas a JSON Schema permite declararlos al modelo y reducir llamadas inválidas y alucinaciones en tool_use.

    ¿Necesito tsx en producción?

    tsx facilita ciclos de desarrollo y CI al evitar compilación manual. En producción puedes seguir usándolo o compilar, según tu pipeline; la recomendación es usarlo para reducir fricción durante desarrollo y pruebas.

    ¿Cómo reducir costes de tokens con este patrón?

    Orquesta tool-calls en un único proceso, limita iteraciones del loop y evita encadenar llamadas LLM por cada handoff. Controlar explícitamente el número de iteraciones reduce tokens enviados y latencia.

    ¿Cuándo añadir bases de datos y vectores (pgvector)?

    Añade PostgreSQL + pgvector cuando necesites retrieval persistente y la memoria a corto plazo del agente no sea suficiente para tus casos de uso.

    ¿Qué límites de seguridad operativa aplicar al expositor de herramientas?

    Nunca expongas una herramienta sin schema Zod, registra cada tool_use con logs estructurados, limita reintentos y aplica validaciones estrictas (Result ok/error) en todas las funciones ejecutadas por el agente.

  • Cómo medir el rendimiento de agentes de IA con evals efectivos

    Cómo medir el rendimiento de agentes de IA con evals efectivos

    Evals para código generado por IA — cómo medir si tu agente está mejorando o empeorando con tu spec

    Tiempo estimado de lectura: 6 min

    • Combina validación determinista y semántica: ambas dimensiones son necesarias para señales accionables.
    • Golden Dataset + rúbricas: versiona casos reales con criterios explícitos para comparar versiones del spec.
    • Two-speed pipeline: validación determinista en cada PR; juez LLM y revisiones completas en merges/release.
    • Métricas operativas clave: pass rate, semantic score, flakiness, coste por eval y regression rate.

    Si cambias una línea en tu CLAUDE.md o ajustas las instrucciones del sistema y luego aceptas código “porque se ve bien”, estás apostando a que la intuición compense la probabilidad. No lo hace. Necesitas implementar evals para código generado por IA — cómo medir si tu agente está mejorando o empeorando con tu spec para convertir esa intuición en métricas reproducibles.

    Este artículo explica qué medir, cómo construir un pipeline fiable, qué herramientas usar y las decisiones operativas que separan a los equipos que gestionan agentes con criterio de los que lo hacen por esperanza.

    Resumen rápido (lectores con prisa)

    Qué es: Un enfoque combinado de evals deterministas y semánticos para código generado por IA.

    Cuándo usarlo: Siempre que tu agente genere código que afecte producción o el diseño arquitectónico.

    Por qué importa: Transforma intuición en métricas reproducibles y reduce regresiones al cambiar el spec.

    Cómo funciona: Golden Dataset versionado + pipeline: determinista rápido en PRs, juez LLM y/o humanos en merges y releases.

    ¿Qué miden los evals para código generado por IA — cómo saber si tu agente mejora o empeora?

    Un eval profesional mide dos dimensiones complementarias:

    • 1. Validación determinista — ¿el output cumple reglas objetivas?
    • 2. Validación semántica — ¿el output cumple criterios arquitectónicos, de seguridad y estilo que sólo pueden evaluarse con criterio?

    Si sólo ejecutas una, te quedas cojo. Combínalas y obtendrás señales accionables.

    Validación determinista

    Objetivos claros y automatizables:

    • Síntaxis / AST: el código parsea sin errores.
    • Linter/style: ESLint/Prettier pasan según la configuración del repo.
    • Tests unitarios de integración en sandbox: el código generado se inyecta en un contenedor efímero y ejecuta Jest/Vitest/PyTest.
    • Reglas binarias del spec: por ejemplo, “no usar fetch en cliente” → comprobación estática.

    Resultado: métricas binarias y tasas de paso (pass rate) que puedes agregar y comparar entre versiones del spec.

    Validación semántica — LLM-as-a-Judge y estrategias híbridas

    Algunos criterios no son booleanos: diseño, seguridad implícita, uso idiomático. Aquí entra un juez LLM:

    • El juez recibe: el spec original, el código generado, y una rúbrica estructurada.
    • Produce: una puntuación y un reasoning structured (json) que explica fallos de arquitectura, riesgos de seguridad, o desviaciones de estilo.

    Precaución: existe sesgo de auto-preferencia. Mitigaciones prácticas:

    • Usar un modelo juez distinto y preferible más capaz (ej. GPT‑4o o Claude avanzado).
    • Ensembles: combinar juicios de 2–3 modelos y una muestra humana para calibrar.
    • Registrar justificaciones (no sólo la puntuación).

    Cómo construir un pipeline de Evals paso a paso

    1. Golden Dataset (20–50 casos reales)

    • Casos representativos del código y dominios del producto.
    • Cada caso: input, contexto (memory files relevantes), criterios de éxito explícitos.
    • Versionado en Git junto al spec.

    2. Frameworks y herramientas

    • Promptfoo — orquestación de evals en CLI.
    • LangSmith (observabilidad y tracing).
    • Braintrust (plataformas de evals y datasets).
    • Integrar linters, AST analyzers y runners de tests (Jest/Vitest/PyTest).

    3. Sandbox seguro para deterministas

    • Contenedores efímeros sin red ni credenciales, preferiblemente con políticas de seccomp/gVisor o Firecracker para microVMs.
    • Tiempo límite por test y quotas de CPU/RAM.

    4. LLM-as-a-Judge

    • Definir rúbricas concretas (JSON schema) por caso del Golden Dataset.
    • Ejecutar juez sólo en merges o nightly builds si el coste es alto; o en un flujo “two-speed” (ver abajo).

    5. Métricas y alertas

    • Pass rate determinista por caso y agregado.
    • Puntuación semántica media y desviación estándar.
    • Flakiness rate (casos con resultados inconsistentes entre corridas).
    • Cost per eval (tokens, wall time).
    • Guardrails: bloquear PRs si la adherencia agregada cae por debajo de un umbral (ej. 85–90%).

    6. Integración CI/CD

    • Disparar evals cuando cambie el spec (CLAUDE.md, AGENTS.md, memory files).
    • Pipeline típico: generar → determinista (rápido) → reporte → si pasa, opcional: juez LLM → aprobar o bloquear PR.

    Estrategia operativa: coste vs seguridad vs velocidad

    • Two-speed pipeline: Validación determinista ligera en cada PR; validación semántica completa en merges a main o releases. Reduce coste y mantiene seguridad.
    • Ensembles y muestreo: Si el coste de juez LLM es prohibitivo, ejecuta juez en una muestra estadística del Golden Dataset por cada cambio mayor.
    • Human-in-the-loop: para nuevas rules o casos edge, requiere revisión humana antes de aceptar un cambio en el spec.

    Métricas que realmente importan

    • Regression rate por cambio de spec (número de casos del Golden Dataset que empeoran).
    • Mean Semantic Score delta entre versiones del spec.
    • Time-to-fix promedio cuando un eval falla.
    • Token cost por ejecución y coste por PR.
    • Porcentaje de automatización (qué % de PRs infractions se bloquean automáticamente vs requieren intervención humana).

    Conclusión operativa

    Trata tu spec como código crítico: versiona, prueba y monitoriza. Implementar evals para código generado por IA transforma la gestión de agentes de una caja de sorpresas a un proceso auditable. Si quieres que el agente mejore con cambios en tu spec, mide, automatiza y obliga a retroalimentación continua. Sin datos no hay control; sin control, el agente termina rompiendo más de lo que arregla.

    Si trabajas con automatización, agentes o workflows y quieres ejemplos prácticos y experimentos reproducibles, revisa Dominicode Labs. Encontrarás recursos y prototipos alineados con pipelines de evals y prácticas de integración.

    FAQ

    Respuesta: Miden dos dimensiones complementarias: validación determinista (sintaxis, linters, tests, reglas binarias) y validación semántica (diseño, seguridad, estilo evaluados por un juez LLM o humanos).

    Respuesta: Es la comprobación automática y objetiva: el código parsea, pasa linters, ejecuta tests en sandbox y cumple reglas estáticas definidas en el spec.

    Respuesta: Reúne 20–50 casos reales representativos. Cada caso debe incluir input, contexto relevante y criterios de éxito explícitos; versiona el dataset en Git junto al spec.

    Respuesta: Ejecuta juez LLM en merges o nightly builds si el coste es alto, o en un flujo two-speed donde aplicas juez a cambios aprobados determinísticamente o a muestras estadísticamente relevantes.

    Respuesta: Pass rate determinista, mean semantic score, regression rate por cambio de spec, flakiness rate, token cost por ejecución y time-to-fix promedio.

    Respuesta: Usa una validación determinista ligera en cada PR y ejecuta validación semántica completa en merges/releases. Muestrea casos para reducir coste y aplica ensembles o revisión humana en casos críticos.