Category: AI

  • 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.

  • 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.

  • Cómo funcionan los Signals en Angular 22 y React 19

    Cómo funcionan los Signals en Angular 22 y React 19

    Signals en Angular 22 y React 19: el nuevo modelo de reactividad

    Tiempo estimado de lectura: 4 min

    Ideas clave

    • Reactividad de grano fino actualiza solo los nodos del DOM que dependen de un valor.
    • Angular 22 introduce Signals explícitos, elimina Zone.js y ofrece formularios sincronizados basados en Signals.
    • React 19 apuesta por optimizaciones vía compilador y el hook use() en lugar de un primitivo signal.
    • Elegir entre ambos depende de control/depurabilidad (Angular) vs. fricción y compatibilidad con código existente (React).

    Tabla de contenidos

    Signals en Angular 22 y React 19: el nuevo modelo de reactividad es la discusión que está redefiniendo cómo pensamos la UI: menos trozos de árbol reevaluados, más actualizaciones puntuales y menos sorpresas en producción. Si tu equipo decide entre control explícito o automatización por compilador, este artículo te da criterios prácticos y ejemplos reales para elegir con criterio.

    Resumen rápido (lectores con prisa)

    Fine-grained reactivity actualiza solo dependencias directas. Angular 22 introduce Signals (signal(), computed(), effect()) y formulas sin Zone.js. React 19 usa el React Compiler para inferir memoización y añade use() para leer Promises/recursos en render. Ambos mejoran escalabilidad; Angular es explícito y más trazable, React reduce fricción de adopción.

    Signals en Angular 22 y React 19: el nuevo modelo de reactividad (explicación rápida)

    La reactividad de grano fino significa actualizar únicamente el nodo del DOM que depende de un valor concreto. Angular 22 lo hace declarando Signals (signal(), computed(), effect()), eliminando Zone.js y ofreciendo formularios basados en Signals. React 19 opta por no añadir un primitivo signal; en su lugar usa el React Compiler para inferir memoización y añade el hook use() para leer Promises/recursos en render. Documentación oficial Angular. Blog oficial React 19.

    ¿Por qué importa la reactividad de grano fino?

    Los problemas reales aparecen en aplicaciones con alta densidad de datos:

    • Dashboards financieros con cientos de celdas que actualizan simultáneamente.
    • Formularios complejos con validaciones cruzadas y campos dependientes.
    • UIs que requieren latencia mínima y CPU predecible en clientes de bajo rendimiento.

    La solución tradicional (Virtual DOM diffs o Zone.js) escala mal: consumes CPU revisando cosas que no cambiaron. Fine-grained reactivity evita ese trabajo inútil.

    Angular 22: Zoneless, Signals y formularios sincronizados

    Angular reescribió su motor de detección. Resultado práctico:

    • Renderizado Zoneless: sin interceptar microtasks; si no cambia un Signal, no hay re-render.
    • Signals explícitos: control total sobre qué es reactivo y cuándo muta.
    • Signal-based Forms: lectura síncrona del estado del formulario, menos RxJS, menos suscripciones que se filtran.

    Ejemplo Angular

    import { signal } from '@angular/core';
    
    const count = signal(0);
    count.set(count() + 1); // solo actualiza los lectores de `count`

    Para convivir con código existente, Angular ofrece utilidades toSignal() / toObservable(), facilitando migraciones incrementales. Guía.

    Ventajas concretas: trazabilidad, depuración directa (sabes qué mutó), rendimiento determinista. Coste: curva de aprendizaje y refactor en bases de código grandes.

    React 19: Reactividad inferida vía compilador y hook use()

    React evita imponer nuevos primitivos. Estrategia:

    • React Compiler: analiza en build y genera memos/mecanismos de actualización automáticos.
    • use(): permite consumir Promises o recursos directamente en render, funcionando con <Suspense> para carga declarativa.
    • Server Actions / useActionState: reduce boilerplate del ciclo formulario → servidor → feedback.

    Ejemplo React

    function Product({ id }) {
      const product = use(fetchProduct(id)); // Suspense maneja loading
      return <div>{product.name}</div>;
    }

    Ventajas: baja fricción de adopción; equipo no reescribe mentalmente la app. Coste: optimizaciones «invisibles» por el compilador que pueden complicar diagnóstico fino; depuración menos directa que en Angular.

    React Suspense referencia

    Comparativa práctica (qué esperar en producción)

    • Performance pura: ambos escalan mucho mejor que modelos antiguos. Angular da mayor predictibilidad por su modelo explícito; React consigue grandes ganancias sin romper DX.
    • Depuración: Angular facilita trazar el origen del update; en React necesitas entender qué transformó el compilador.
    • Migración: Angular exige trabajo incremental (conversión de formularios y algunos patrones de RxJS). React permite migración más suave, porque el compilador optimiza el código existente.
    • Formularios complejos: Angular gana por tipado y sincronía; React compensa con Server Actions para patrones CRUD.

    Recomendaciones prácticas para equipos

    1. Haz un piloto con módulos concretos. No migres todo de golpe.
    2. Para UIs de alta densidad de datos, prioriza Angular 22 si necesitas control y trazabilidad estricta.
    3. Si tu stack ya es Next.js / SSR y quieres mejorar rendimiento sin reeducar al equipo, React 19 es opción pragmática.
    4. Añade pruebas de rendimiento (microbenchmarks) y observabilidad: mide renders por segundo, tamaño de paint y memoria.
    5. Documenta patrones: en Angular, establece cómo y cuándo crear Signals; en React, especifica cómo instrumentar y auditar transformaciones del compilador.

    Conclusión práctica

    Signals en Angular 22 y React 19 solucionan el mismo problema con filosofías distintas: Angular te da el control explícito; React te lo facilita automáticamente. No hay «mejor» universal: hay mejor para tu equipo. Si quieres predictibilidad y depurabilidad en sistemas críticos, apuesta por Angular 22. Si prefieres un camino de menor fricción y eres heavy-SSR, React 19 acelera el time-to-market. Dominar fin-grained reactivity es ahora requisito, no lujo.

    FAQ

    Respuesta: La reactividad de grano fino actualiza solo los nodos del DOM que dependen de un valor específico, en lugar de reevaluar grandes porciones del árbol. Reduce trabajo innecesario de CPU y mejora latencia en UIs densas.

    Respuesta: Angular 22 elimina la dependencia de Zone.js y usa Signals declarativos. En lugar de interceptar microtasks para detectar cambios, los Signals notifican solo a sus lectores cuando cambian, proporcionando renders deterministas.

    Respuesta: No: React 19 no introduce un primitivo signal. Usa el React Compiler para inferir memoización y optimizaciones, y añade use() para consumo de Promises/recursos en render.

    Respuesta: Los Signal-based Forms permiten lectura síncrona del estado del formulario, reducen la necesidad de RxJS y evitan suscripciones filtradas. Mejoran trazabilidad y simplifican validaciones dependientes.

    Respuesta: Haz un piloto. Si necesitas control y trazabilidad estricta para sistemas críticos, Angular 22 es preferible. Si buscas mínima fricción y tu stack ya usa SSR/Next.js, React 19 reduce fricción de adopción.

    Respuesta: Parcialmente. Angular ofrece utilidades como toSignal() / toObservable() para migraciones incrementales, pero adaptar formularios y patrones RxJS puede requerir refactor. React 19 suele permitir migración más suave gracias al compilador.

  • Implementación de Generics para Wrappers de IA en TypeScript

    Implementación de Generics para Wrappers de IA en TypeScript

    Generics para wrappers de IA en TypeScript

    Tiempo estimado de lectura: 4 min

    • Evita desincronización: usa un wrapper genérico withAI<T>() para enlazar firma TypeScript y validación Zod.
    • Zod‑first: Zod en runtime + z.infer en TypeScript ofrece validación práctica frente al type erasure.
    • Autodocumentación y registros: genera descripciones básicas y registra prompt, rawResponse y resultado de Zod.
    • Operación segura: define límites de reintentos y métricas; en sistemas críticos separa intención (LLM) de efecto (máquina de estado).

    Generics para wrappers de IA en TypeScript: si vas a exponer funciones de negocio a agentes, necesitas una forma segura y mantenible de hacerlo. En las primeras líneas: usar generics y Zod evita duplicar contratos y convierte la exposición de funciones en un proceso reproducible y tipado. Aquí explico por qué funciona, cómo implementarlo y qué decisiones arquitectónicas debes tomar.

    Resumen rápido (lectores con prisa)

    Patrón Zod‑first: pasa un esquema Zod al wrapper y usa z.infer<…> para que TypeScript infiera tipos. El wrapper genérico withAI<T> enlaza la firma de la función con el esquema, validando en runtime y detectando incompatibilidades en compilación.

    Úsalo cuando expongas funciones a LLMs o agentes; mejora seguridad estática, validación runtime y trazabilidad.

    Por qué necesitas Generics para wrappers de IA en TypeScript

    Exponer una función como herramienta para un LLM suele generar cuatro elementos repetitivos: descripción, esquema de validación, bindings del SDK y la ejecución. Ese boilerplate se desincroniza con el tiempo: la firma cambia, el esquema no, y el error aparece en producción, no en el IDE.

    La solución es un wrapper genérico —withAI<T>()— que capture la firma de la función mediante tipos TypeScript y reciba un esquema Zod en runtime. Zod vive en ejecución; TypeScript no. Esta combinación (TypeScript + Zod) te da lo mejor de ambos mundos: seguridad estática y validación runtime.

    Limitación real: type erasure y la decisión Zod‑first

    TypeScript suprime tipos en runtime (type erasure). No puedes inspeccionar en ejecución que un parámetro se llama userId y es string. Por eso hay dos rutas:

    • Extraer metadatos en build time (AST/JSDoc) — viable pero compleja.
    • Patrón Zod‑first — práctico y fiable: pasas un esquema Zod al wrapper, Zod valida en runtime y TypeScript infiere tipos con z.infer<…>.

    Recomiendo Zod‑first. Es simple, robusto y encaja con flujos CI/CD.

    Implementación: withAI<T> paso a paso

    Idea: recibir la función original, su esquema Zod y devolver una herramienta lista para el SDK de IA (p. ej. Vercel AI SDK https://sdk.vercel.ai/docs). El genérico obliga a coherencia entre firma y esquema.

    Ejemplo reducido

    import { z } from 'zod';
    import { tool } from 'ai'; // Vercel AI SDK
    
    export function withAI>(
      fn: T,
      schema: z.ZodType<Parameters<T>[0]>,
      description?: string
    ) {
      const autoDesc = description ?? generateDescription(fn.name, schema);
    
      return tool({
        description: autoDesc,
        parameters: schema,
        execute: async (args) => {
          // args ya validado por Zod cuando el SDK integra la validación
          return await fn(args as Parameters<T>[0]);
        },
      });
    }
    

    Claves:

    • Parameters<T>[0] enlaza el tipo esperado del primer argumento de fn con el esquema.
    • Si la firma de fn cambia y el esquema no, TypeScript marcará el error en compilación.
    • tool() es una abstracción; adapta al SDK que uses (Vercel, OpenAI, etc.).

    Autodocumentación práctica

    El wrapper puede generar una descripción básica a partir del nombre de la función y las claves del esquema. No es NLP mágico, pero reduce trabajo manual y mejora la señal hacia el modelo.

    function generateDescription(name: string, schema: z.ZodTypeAny) {
      const readable = name.replace(/([A-Z])/g, ' $1').trim().toLowerCase();
      const params = schema instanceof z.ZodObject ? Object.keys(schema.shape).join(', ') : 'input object';
      return `Use this tool to ${readable}. Parameters: ${params}.`;
    }
    

    Para funciones críticas, proporciona siempre una descripción manual y ejemplos de uso. Puedes enriquecer la doc con ejemplos JSON y constraints — los modelos modernos respetan instrucciones claras (ver Structured Outputs de OpenAI: https://platform.openai.com/docs/guides/structured-outputs).

    Buenas prácticas operativas

    • Valida con .safeParse() en agentes que puedan autocorregirse; usa .parse() para endpoints que deban fallar rápido.
    • Registra siempre: prompt, rawResponse, resultado de Zod (error.flatten()), la herramienta invocada y contexto. Sin esto, los postmortems son inútiles.
    • Mide: tasa de validación fallida, latencia de autocorrección, reintentos por prompt y degradaciones a humano.
    • Define límites: si tras N reintentos no hay corrección, encola para revisión humana. Evita loops que consuman tokens/requests.

    Trade‑offs y decisiones arquitectónicas

    • Autogeneración vs. precisión: la descripción automática agiliza pero no sustituye documentación humana para casos sensibles.
    • Structured Outputs + generateObject (OpenAI) reducen errores de formato, pero no reemplazan validaciones semánticas (p. ej. rangos, signos). Zod sigue siendo necesario.
    • En sistemas críticos, deja que el LLM decida la herramienta, pero que una máquina de estado (n8n, XState) controle la ejecución final; así separas intención y efecto.

    Ejemplo completo: patrón en producción

    1. Define la función pura:

    async function getOrder(args: { orderId: string }) { /* ... */ }

    2. Define esquema Zod:

    const OrderSchema = z.object({ orderId: z.string().uuid() });

    3. Envuelve:

    const getOrderTool = withAI(getOrder, OrderSchema, 'Obtiene estado de un pedido por ID');

    4. Registra y mide cada llamada. Si Zod falla, serializa error.flatten() y envíalo al LLM para autocorrección o al equipo de soporte.

    Conclusión

    Generics para wrappers de IA en TypeScript no es un truco académico: es una medida práctica para escalar agentes sin introducir deuda técnica. El patrón Zod‑first con withAI<T> convierte la exposición de funciones en una operación segura, rastreable y testeable. Si tu agente escribe en bases de datos, llama APIs facturadas o ejecuta efectos críticos, aplica este patrón hoy: te evitará errores que sólo descubres en producción.

    Para equipos que diseñan flujos de agentes y workflows relacionados con automatización e IA aplicada, puede ser útil revisar trabajos y herramientas experimentales. Más recursos y experimentos están disponibles en Dominicode Labs.

    FAQ

     

     

    ¿Qué es exactamente el patrón Zod‑first?

    Es la práctica de definir esquemas de validación con Zod en runtime y usar z.infer<…> para que TypeScript derive los tipos, evitando depender de metadatos de tipos en ejecución.

     

     

    ¿Cuándo debo usar safeParse() vs parse()?

    Usa safeParse() cuando el agente pueda autocorregirse o cuando quieras manejar errores sin lanzar. Usa parse() en endpoints que deban fallar rápido y propagar excepciones.

     

     

    ¿Cómo detecta TypeScript desalineaciones entre firma y esquema?

    El wrapper genérico usa tipos como Parameters<T>[0]. Si la firma de la función cambia y el esquema suministrado no coincide, TypeScript emitirá un error en compilación por incompatibilidad de tipos.

     

     

    ¿Qué hacer si Zod falla de forma recurrente?

    Registra el resultado de error.flatten(), envía el fallo al LLM para autocorrección o encola el caso para revisión humana si supera N reintentos. Mide la tasa de validación fallida para priorizar correcciones.

     

     

    ¿Puedo usar este patrón con otros SDKs además de Vercel?

    Sí. tool() en el ejemplo es una abstracción; adapta la forma de registrar parámetros, validar y ejecutar según el SDK (Vercel, OpenAI u otros).

     

     

    ¿Cómo debo registrar errores y métricas?

    Registra prompt, rawResponse, resultado de Zod (error.flatten()), herramienta invocada, contexto y métricas como latencia y reintentos. Estos datos son esenciales para postmortems y mejoras iterativas.

  • Cómo Spec-First Optimiza el Desarrollo de Software con IA

    Cómo Spec-First Optimiza el Desarrollo de Software con IA

    Por qué Spec-First cambió mi forma de programar con IA (y por qué debería cambiar la tuya)

    Tiempo estimado de lectura: 4 min

    • Spec-First reduce suposiciones del modelo al definir contratos antes de pedir implementación.
    • Escribir tipos y casos de error toma minutos; arreglar código generado con suposiciones incorrectas puede costar días.
    • Combinar Spec-First con TDD convierte especificaciones en tests ejecutables y acelera desarrollo mantenible.
    • Aplica Spec-First en sistemas críticos, APIs públicas y módulos que deben escalar; evita para prototipos one-off.

    Por qué Spec-First cambió mi forma de programar con IA (y por qué debería cambiar la tuya). Poca gente habla de esto después del entusiasmo inicial. Descubrí algo curioso: no era la IA la que fallaba, era el orden de mis decisiones.

    La primera vez que pides código a un asistente te sientes en una peli de ciencia ficción. La décima vez estás peleando con alucinaciones, nombres mal elegidos y lógica que solo funciona en el mundo ideal del modelo. Spec-First rompió esa dinámica.

    Resumen rápido (lectores con prisa)

    Spec-First: escribe el contrato (tipos, entradas/salidas, casos límite) antes de pedir implementación. Reduce suposiciones del modelo y convierte especificaciones en tests ejecutables. Útil para código mantenible y APIs, menos para prototipos one-off.

    El coste real del Prompt-Driven Development

    El flujo habitual es: pides, pegas, arreglas. Repetir. Para prototipos funciona. Para software que vive y crece, no.

    • El modelo no conoce tu arquitectura.
    • No sabe tus convenciones ni decisiones pasadas.
    • No respeta tus límites de efectos secundarios ni tus políticas de error.

    Resultado: módulos que compilan pero no encajan. Bugs lógicos distribuidos. Revisiones interminables.

    Spec-First no te da respuesta mágica. Te devuelve tiempo y predictibilidad.

    Qué debe contener una spec si vas a usar IA

    No necesitas un documento de 30 páginas. Necesitas lo mínimo imprescindible para quitarle decisiones al modelo:

    Tipos e interfaces

    define entradas y salidas antes de pedir lógica.

    interface CreateUser { email: string; name?: string }
    type Result<T> = { ok: true; value: T } | { ok: false; error: string }

    Casos límite

    nulos, dominios bloqueados, fallos de red, retries, timeouts.

    Comportamiento determinista

    funciones puras, sin efectos laterales, o explícitamente con side effects autorizados.

    Restricciones de integración

    versiones de librería, patrones prohibidos, dónde puede tocar la base de datos.

    Escribir esto toma minutos. Arreglar un desastre generado por IA puede costarte días.

    Spec-First + TDD = velocidad real

    Si ya definiste tipos y casos de error, pedirle al modelo que genere tests primero es natural. Los tests pasan a ser la especificación ejecutable.

    Flujo práctico:

    • 1) Escribe tipos y contratos.
    • 2) Genera tests unitarios con la IA.
    • 3) Pide la implementación hasta que los tests pasen.

    La diferencia: pasas menos tiempo adivinando por qué algo falla y más en ajustar diseño.

    Ejemplo rápido (mental, no código largo)

    En vez de: “Crea función que valide emails”, di:

    “Función pura que recibe string, valida email corporativo (rechaza gmail.com, hotmail.com), retorna Result<Email, ValidationError>, cero excepciones, sin llamadas externas.”

    Esa frase evita que el modelo haga lo que le da la gana y te devuelve algo integrable.

    Cuándo aplicar Spec-First (y cuándo no)

    No es una religión. Úsalo cuando importe la mantenibilidad y la integración:

    • Sistemas críticos, core domain, APIs públicas.
    • Equipos distribuidos con contratos firmes.
    • Proyectos que deben escalar o durar.

    No lo emplees para scripts one-off o prototipos exploratorios donde la velocidad de concepto importa más que la calidad.

    Cambia tu rol profesional: de mecanógrafo a director de orquesta

    La IA está comoditizando la escritura de código. El valor real se desplaza hacia quien define qué construir y por qué. Spec-First es el instrumento para ejercer ese criterio sin perder velocidad.

    Tú no vas a competir con la IA en velocidad de tecleo. Vas a competir en claridad de intención, disciplina arquitectónica y capacidad de traducir requisitos imprecisos en contratos firmes.

    Cómo empezar hoy (3 pasos prácticos)

    1. Antes de pedir código, escribe los tipos. Solo eso.
    2. Genera tests unitarios desde esa spec.
    3. Pide la implementación, haz que los tests pasen.

    Hazlo en el siguiente ticket que abras. No hace falta cambiar todo tu flujo; prueba en un módulo nuevo y compara el resultado.

    Haz esto ahora: la próxima vez que pidas una función al asistente, detente 30 segundos y define solo los tipos. Luego vuelve y genera los tests. Verás la diferencia.

    Esto no acaba aquí: si quieres, puedo convertir tu próxima descripción vaga en una spec lista para usar con cualquier LLM.

    Este artículo trata sobre IA aplicada y flujos de trabajo con modelos, por lo que puede interesarte explorar recursos prácticos y experimentos en Dominicode Labs. Es un complemento natural para probar especificaciones y pipelines de tests en prototipos controlados.

    FAQ

     

     

    ¿Qué es Spec-First?

    Es una práctica que prioriza escribir contratos (tipos, entradas/salidas, casos límite) antes de solicitar la implementación a un asistente IA o a un desarrollador.

     

    ¿Cuándo debo usar Spec-First?

    Cuando la mantenibilidad, integraciones o el dominio crítico importen: APIs públicas, core domain y equipos distribuidos. No es necesario para scripts one-off o experimentos rápidos.

     

    ¿Spec-First reemplaza al TDD?

    No lo reemplaza; se complementan. Spec-First define contratos y TDD convierte esos contratos en tests ejecutables que guían la implementación.

     

    ¿Cuánto tiempo toma crear una spec básica?

    En muchos casos, minutos. Definir tipos y casos límite mínimos suele ser suficiente para reducir suposiciones del modelo y evitar reescrituras costosas.

     

    ¿Es útil para prototipos rápidos?

    No siempre. Para prototipos donde la velocidad de concepto importa más que la calidad, puedes omitirlo. Para piezas que deban mantenerse o integrarse, sí.

     

    ¿Qué incluye una spec mínima?

    Los tipos e interfaces de entradas/salidas, casos límite (nulos, dominios bloqueados, fallos de red), comportamiento determinista (funciones puras o efectos explícitos) y restricciones de integración (versiones, patrones prohibidos).

  • Cuándo usar multi-agente sin orquestador para sistemas LLM

    Cuándo usar multi-agente sin orquestador para sistemas LLM

    Multi-agente sin orquestador: cuándo sí, cuándo no

    Tiempo estimado de lectura: 4 min

    • Elige previsibilidad o diversidad: la decisión arquitectónica entre coreografía y orquestación define latencia, trazabilidad y coste.
    • Usa coreografía sólo cuando la impredecibilidad es funcional: simulaciones, brainstorming y generación de datos sintéticos.
    • Prefiere un agente único con tools tipadas para sistemas con SLAs, integridad de datos o costes por token relevantes.

    Multi-agente sin orquestador: cuándo sí, cuándo no. Es la pregunta que separa prototipos brillantes de sistemas que explotan en producción. Antes de escribir una sola línea de código, decide: ¿quieres impredecibilidad controlada o previsibilidad verificable? Ese matiz definirá tu arquitectura y tus costes operativos.

    En este artículo explico con ejemplos, métricas y criterios técnicos cuándo un solo agente bien diseñado supera a un enjambre de cinco agentes encadenados, y cuándo la coreografía descentralizada aporta valor real.

    Resumen rápido (lectores con prisa)

    Un sistema multi-agente sin orquestador (coreografía) permite que varios agentes LLM intercambien contexto sin una máquina de estados central. Úsalo para simulaciones, brainstorming y generación de datos sintéticos donde la impredecibilidad es valor. Evítalo en sistemas transaccionales, atención crítica o cuando necesitas trazabilidad determinista. Empieza siempre con un agente único y herramientas tipadas; escala a múltiples agentes solo si el límite es cognitivo, no de diseño.

    Multi-agente sin orquestador: definición y contexto

    Un sistema multi-agente sin orquestador (coreografía) es aquel en que varios agentes LLM se transfieren contexto entre sí sin una máquina de estados central que valide transiciones. Frameworks experimentales como OpenAI Swarm exploran handoffs ligeros entre agentes. En contraste, soluciones orquestadas usan grafos de estado deterministas: LangGraph, n8n o XState.

    La diferencia crítica: en la orquestación, la infraestructura controla el flujo; en la coreografía, el flujo emerge de decisiones probabilísticas del modelo. Esa diferencia tiene consecuencias prácticas en latencia, trazabilidad y tolerancia al error.

    Cuándo SÍ usar multi-agente sin orquestador

    • Simulaciones con actores contrapuestos. Cuando el objetivo es generar comportamiento emergente o modelar negociaciones entre agentes con incentivos opuestos, la autonomía produce diversidad útil.
    • Investigación y brainstorming creativo. Si buscas múltiples perspectivas no filtradas para enriquecer creatividad, dejar que agentes critiquen y propongan sin una regla rígida puede aportar hallazgos inesperados.
    • Generación de datos sintéticos. Interacciones caóticas entre agentes generan datasets variados útiles para entrenamiento o evaluación.

    Estos usos comparten dos características: no arriesgan datos reales ni SLAs estrictos, y toleran impredecibilidad como una funcionalidad, no un bug.

    Cuándo NO usar multi-agente sin orquestador

    Evita coreografías si hay dinero, integridad de datos o experiencia de usuario en juego:

    • Sistemas transaccionales con escrituras en BD, ERPs o CRMs: necesitas rollbacks y garantías ACID; la orquestación es obligatoria.
    • Atención al cliente y workflows críticos: latencias y respuestas incoherentes son inaceptables.
    • Modelos con presupuesto de tokens limitado: los enjambres tienden a entrar en bucles costosos (cortesías, indecisiones).

    Además, si necesitas auditoría y trazabilidad determinista, la coreografía complica el post-mortem.

    Por qué un solo agente supera a cinco encadenados (ejemplos técnicos)

    1) Context Loss

    Cada handoff serializa el razonamiento en texto. El receptor procesa un resumen; pierde activaciones internas y matices. Resultado: degradación progresiva del contexto. Un solo agente mantiene la cadena lógica en una ventana de contexto continua.

    2) Latencia y coste

    Cinco llamadas secuenciales multiplican TTFT y factura. Para servicios con SLA de respuesta o coste por token relevante, el impacto es directo en UX y en la cuenta.

    3) Roles que deberían ser tools

    A menudo se crean agentes por rol cuando lo que se necesita son herramientas especializadas. Un agente único con acceso a una herramienta de ejecución de código (sandbox Python), a DB queries parametrizadas y a validadores Zod/JSON Schema resuelve mejor que cinco agentes que no comparten capacidades. Usa Zod para tipos estrictos y pgvector para retrieval cuando necesites seleccionar herramientas por semántica.

    Criterios concretos previos al diseño (decide antes de codificar)

    Aplica estas tres pruebas rápidas:

    1. Conflicto de system prompts

    ¿Los prompts necesarios entran en conflicto (alta creatividad vs. máxima precisión)? Si sí, separa agentes u orquesta. Si no, usa uno solo.

    2. Determinismo del flujo

    ¿El paso B requiere que A sea validado con certeza? Si sí, la infraestructura debe controlar la transición (n8n, LangGraph). El LLM debe ejecutar acciones, no decidir el avance del workflow.

    3. Coste del fallo

    Calcula el impacto de un error en el tercer agente de la cadena (tokens perdidos, rollback requerido, datos corruptos). Si el coste excede el umbral tolerable, no uses coreografía.

    Mide antes de decidir: precisión de selección de herramienta, retries por fallo, tokens gastados en reintentos. Define umbrales y automatiza tests de estrés que simulen handoffs y fallos.

    Patrón recomendado de inicio

    1. Un agente central con tools tipadas (schemas, enums).
    2. Validación server-side estricta y Result pattern para errores, evitando throws incontenidos.
    3. Retira herramientas del prompt con Dynamic Tool Retrieval (RAG) para reducir la entropía. Usa embeddings + búsqueda vectorial para inyectar solo las herramientas relevantes.

    Escala a múltiples agentes solo cuando hayas demostrado que la solución simple falla por límite cognitivo del prompt y no por diseño.

    La arquitectura correcta no es la más sofisticada, es la que puedes operar, auditar y reparar. En producción, predecible vence a impresionante.

    Para equipos que prototipan o validan patrones de integración y workflows con agentes, puede ser útil revisar trabajos y experimentos prácticos. Una referencia complementaria se mantiene en Dominicode Labs, donde se documentan enfoques aplicados y pruebas de concepto relacionadas con agentes y automatización.

    FAQ

    Es un sistema en el que varios agentes LLM intercambian contexto y toman decisiones de forma descentralizada, sin una máquina de estados central que controle las transiciones entre pasos.
    Cuando el objetivo es generar comportamiento emergente, diversidad de perspectivas o datasets sintéticos, y no hay requisitos estrictos de integridad de datos, SLAs o trazabilidad determinista.
    Pérdida de contexto por serialización, mayor latencia y coste por llamadas secuenciales, bucles de comportamiento que consumen tokens y dificultad para auditoría y rollbacks.
    Aplica pruebas sobre conflicto de prompts, determinismo del flujo y coste del fallo. Mide precisión de selección de herramienta, retries y tokens gastados; automatiza tests de estrés.
    Un agente único con acceso a tools tipadas (validadores, sandboxes, consultas parametrizadas) y Dynamic Tool Retrieval usando embeddings y búsqueda vectorial suele resolver muchos casos de uso.
    Se citan LangGraph, n8n y XState como ejemplos de soluciones orquestadas.