Category: AI

  • Algoritmos de machine learning que todo developer web debería entender

    Algoritmos de machine learning que todo developer web debería entender

    Hace un año integré una búsqueda semántica en un proyecto SaaS. El cliente quería que los usuarios encontraran artículos aunque escribieran con sinónimos, con errores ortográficos, o en un idioma distinto al del contenido.

    La solución: tres líneas de TypeScript llamando a algoritmos de machine learning vía la API de OpenAI. Funcionó en una tarde.

    Pero el cliente preguntó algo que me dejó sin respuesta inmediata: "¿Qué hace exactamente ese modelo por dentro?". Y yo, con 15 años de experiencia en desarrollo, tuve que admitir que no tenía una respuesta clara más allá de "convierte texto en números".

    Ese hueco me molestó. No porque necesitara implementar los algoritmos desde cero, sino porque cuando no entiendes qué hay debajo del capó, tomas peores decisiones: eliges el modelo equivocado, debuggeas en la dirección incorrecta, o diseñas una arquitectura que no escala.

    Este post es lo que me hubiera gustado leer ese día. Los algoritmos de machine learning explicados para developers web — sin fórmulas, sin Python, sin pretender que vas a ser data scientist.

    Tres familias que lo explican todo

    Los algoritmos de machine learning son procedimientos que permiten a un sistema aprender patrones a partir de datos, sin que un programador defina explícitamente las reglas. En lugar de escribir if (spam) { ... }, le muestras miles de emails al modelo y él deduce las reglas solo.

    Hay tres formas fundamentales en que ocurre ese aprendizaje:

    Aprendizaje supervisado. Le das al modelo ejemplos con respuesta correcta. "Este email es spam. Este otro no lo es." El modelo aprende el patrón. Cuando llega un email nuevo, predice a cuál categoría pertenece. Úsalo cuando tienes datos etiquetados y una tarea de predicción o clasificación concreta.

    Aprendizaje no supervisado. No hay respuestas correctas. Le das datos sin etiquetar y el modelo encuentra estructura por sí solo. "Estos usuarios tienen comportamiento parecido. Estos otros también. Hay tres grupos." Úsalo cuando quieres descubrir patrones que no conoces de antemano — clustering de usuarios, detección de anomalías.

    Reinforcement learning. El modelo aprende por ensayo y error: hace una acción, recibe una recompensa o penalización, ajusta. Es cómo funcionan los modelos de juegos, pero también cómo se afinan los LLMs para que sus respuestas sean más útiles (RLHF — Reinforcement Learning from Human Feedback).

    Con esto en mente, los algoritmos concretos tienen contexto.

    Los algoritmos de machine learning que te importan como developer

    Resumen antes de entrar en detalle — ninguno lo vas a implementar tú:

    Algoritmo Tipo Cuándo lo usas en web ¿Lo implementas?
    Regresión logística Supervisado Scoring, predicción de churn No — API
    Random Forest Supervisado Moderación, detección de fraude No — API
    K-Means No supervisado Clustering de usuarios No — API
    Redes neuronales Supervisado Base de embeddings, clasificación No — modelos preentrenados
    Embeddings Supervisado Búsqueda semántica, recomendaciones No — OpenAI/HuggingFace
    Transformers Supervisado LLMs, generación, clasificación avanzada No — API

    Regresión lineal y logística

    Son los más simples. La regresión lineal predice un número: "¿Cuánto va a costar este apartamento?" La logística predice una probabilidad: "¿Hay un 87% de probabilidad de que este usuario cancele su suscripción este mes?"

    No las vas a implementar, pero las vas a encontrar en APIs de scoring, en features de predicción de churn, en sistemas de precios dinámicos. Cuando una API te devuelve un score: 0.87, probablemente hay una regresión logística detrás.

    Árboles de decisión y Random Forest

    Imagina una serie de preguntas de sí/no encadenadas. "¿El usuario tiene más de 30 días de cuenta? ¿Ha hecho al menos una compra? ¿Abrió el último email?" Cada camino lleva a una predicción. Eso es un árbol de decisión.

    Random Forest toma cientos de árboles distintos y combina sus respuestas. El resultado es más robusto y menos propenso a overfitting que un solo árbol.

    Son los algoritmos detrás de sistemas de moderación de contenido basados en reglas aprendidas, de detección de fraude, de sistemas de recomendación básicos.

    K-Means (clustering)

    K-Means agrupa datos en K clusters. Tú dices cuántos grupos quieres (K), el algoritmo encuentra cuáles puntos de datos pertenecen a cada grupo.

    Como developer web, esto aparece en sistemas de personalización: "Usuarios que actúan como tú también compraron esto." No hay etiquetas previas — el modelo descubre los segmentos solo.

    Redes neuronales

    Aquí empieza lo que la gente llama "deep learning". Una red neuronal es una cadena de capas matemáticas que transforman una entrada (texto, imagen, audio) en una salida (una clasificación, un número, un vector).

    Lo importante para entenderlas no es la matemática — es el concepto de representación. Cada capa aprende a representar la entrada de una forma más abstracta que la anterior. La primera capa de un modelo de visión detecta bordes. La siguiente detecta formas. La siguiente detecta objetos. Ningún programador definió esas representaciones: emergieron del entrenamiento.

    Embeddings — el algoritmo que ya usas

    Los embeddings son el resultado de pasar texto (o imágenes, o audio) por una red neuronal especializada. La salida es un vector de números — típicamente de 768 a 3072 dimensiones.

    La magia es que los vectores capturan significado semántico. "Perro" y "can" producen vectores muy cercanos en ese espacio de alta dimensión. "Perro" y "hipoteca" producen vectores lejanos.

    Esto es lo que permite la búsqueda semántica: conviertes tu query en un vector, comparas contra los vectores de tu base de datos, y devuelves los más cercanos. No importa si el usuario escribió "gato" y el documento dice "felino" — los vectores están cerca.

    Transformers — la arquitectura detrás de los LLMs

    Un Transformer es una arquitectura de red neuronal diseñada para procesar secuencias. El mecanismo clave se llama "atención" (attention): permite que el modelo, al procesar una palabra, preste atención a otras palabras del contexto según su relevancia.

    "El banco estaba lleno de peces" vs "El banco rechazó mi solicitud". La misma palabra "banco", significado completamente distinto. El mecanismo de atención resuelve esto mirando el contexto completo de la frase.

    GPT, Claude, Llama y Gemini usan Transformers como arquitectura base. Los modelos de embeddings de OpenAI también son Transformers, pero optimizados para producir buenas representaciones vectoriales en lugar de generar texto.

    Cuándo le importan al developer web

    No necesitas un data scientist para beneficiarte de ML. Estas son las integraciones más comunes en proyectos web reales. Puedes ver más ejemplos aplicados en el blog de Dominicode.

    Búsqueda semántica. Reemplaza o complementa la búsqueda por palabras clave. Los embeddings convierten queries y documentos en vectores, y una base de datos vectorial (Pinecone, pgvector, Supabase Vector) hace el matching por similitud coseno.

    Moderación de contenido. Clasifica si un texto es tóxico, si una imagen es apropiada, si un comentario viola normas. HuggingFace tiene modelos de clasificación listos para usar via API — zero setup del lado del ML.

    Recomendaciones. Clustering de usuarios por comportamiento o embeddings de productos para "productos similares". No necesitas construir un sistema de recomendación desde cero — embeddings + similitud coseno es suficiente para empezar.

    Extracción de información. Parsear emails, facturas, formularios en lenguaje natural. Un LLM con un prompt bien estructurado hace esto mejor que cualquier regex que vayas a escribir.

    TypeScript en la práctica

    Aquí es donde todo esto se vuelve concreto. No vas a implementar K-Means. Vas a llamar a una API que usa K-Means internamente. Pero entender qué hace el algoritmo te ayuda a saber qué esperar y qué debuggear.

    Embeddings con OpenAI

    import OpenAI from "openai";
    
    const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
    
    async function getEmbedding(text: string): Promise<number[]> {
      const response = await client.embeddings.create({
        model: "text-embedding-3-small",
        input: text,
      });
    
      return response.data[0].embedding; // Vector de 1536 dimensiones
    }
    
    // Similitud coseno entre dos vectores
    function cosineSimilarity(a: number[], b: number[]): number {
      const dot = a.reduce((sum, val, i) => sum + val * b[i], 0);
      const magA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
      const magB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
      return dot / (magA * magB);
    }
    
    // Búsqueda semántica básica
    // En producción: usar batching o rate limiting para evitar errores 429 de la API
    async function semanticSearch(query: string, documents: string[]) {
      const queryVector = await getEmbedding(query);
      const docVectors = await Promise.all(documents.map(getEmbedding));
    
      const scores = docVectors.map((vec, i) => ({
        document: documents[i],
        similarity: cosineSimilarity(queryVector, vec),
      }));
    
      return scores.sort((a, b) => b.similarity - a.similarity);
    }
    
    const docs = [
      "Cómo configurar un servidor NestJS",
      "Recetas de cocina italiana",
      "Deploying Node.js to production",
    ];
    
    const results = await semanticSearch("backend con Node", docs);
    console.log(results[0]); // { document: "Deploying Node.js...", similarity: 0.89 }
    

    Referencia oficial: OpenAI Embeddings API.

    Clasificación con HuggingFace Inference API

    const HF_TOKEN = process.env.HF_TOKEN;
    const MODEL = "cardiffnlp/twitter-roberta-base-sentiment-latest";
    
    interface ClassificationResult {
      label: string;
      score: number;
    }
    
    async function classifySentiment(text: string): Promise<ClassificationResult[]> {
      const response = await fetch(
        `https://api-inference.huggingface.co/models/${MODEL}`,
        {
          method: "POST",
          headers: {
            Authorization: `Bearer ${HF_TOKEN}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ inputs: text }),
        }
      );
    
      // Si el modelo lleva tiempo sin uso, la primera respuesta puede tardar
      // 20-30 segundos con { error: "Model is currently loading" } — reintentar.
      const data = await response.json();
      return data[0] as ClassificationResult[];
    }
    
    const result = await classifySentiment("Este producto es increíble!");
    // [{ label: "POSITIVE", score: 0.97 }, { label: "NEUTRAL", score: 0.02 }, ...]
    
    if (result[0].label === "NEGATIVE" && result[0].score > 0.85) {
      // Marcar para revisión manual
    }
    

    Referencia oficial: HuggingFace Inference API.

    Dos ejemplos, dos APIs reales, cero instalación de librerías de ML. El algoritmo corre en la nube. Tú consumes el resultado y construyes producto.

    Si quieres explorar estas integraciones dentro de un flujo completo — desde la idea hasta el producto funcionando — en el curso Construye con IA cubrimos exactamente esta capa: cómo conectar modelos de ML reales a una arquitectura de producto sin convertirte en data scientist. También publicamos tutoriales y ejemplos en el canal de YouTube de Dominicode.

    La decisión que cambia todo

    Entender estos algoritmos no significa que vayas a entrenar modelos. Significa que cuando eliges entre una búsqueda por palabras clave y una búsqueda semántica, sabes exactamente qué estás eligiendo y por qué.

    Significa que cuando un modelo de clasificación te devuelve un score bajo, sabes si el problema está en el modelo, en los datos de entrada, o en cómo estás interpretando el output.

    Significa que cuando alguien en tu equipo dice "usemos ML para esto", puedes hacer las preguntas correctas: ¿supervisado o no supervisado? ¿Tienes datos etiquetados? ¿Qué métrica defines como éxito?

    Los modelos los entrenan los data scientists. El producto lo construyes tú. Saber qué hay debajo del capó es lo que hace la diferencia entre un developer que consume IA y uno que la integra de forma inteligente.

    En Dominicode Labs tenemos proyectos completos donde aplicamos estas integraciones en contextos reales — búsqueda semántica, pipelines con embeddings, agentes que usan clasificadores como herramientas. Si quieres ver el código funcionando, es donde empieza.


    FAQ

    ¿Necesito saber matemáticas para usar algoritmos de machine learning como developer?

    No para usarlos, sí para entenderlos en profundidad. La mayoría de las integraciones que harás como developer web consumen modelos ya entrenados via API. Saber qué hace el algoritmo — qué tipo de problema resuelve y qué output produce — es suficiente para tomar buenas decisiones de arquitectura. Si en algún momento necesitas afinar un modelo o interpretar métricas de entrenamiento, entonces sí vale la pena profundizar en la matemática.

    ¿Cuál es la diferencia entre un LLM y un modelo de embeddings?

    Un LLM (como GPT-4 o Claude) está entrenado para generar texto: toma una secuencia de tokens y predice los siguientes. Un modelo de embeddings está optimizado para producir representaciones vectoriales del texto, capturando su significado semántico en un espacio de alta dimensión. Ambos usan arquitectura Transformer, pero con objetivos de entrenamiento distintos. Para búsqueda semántica, usa modelos de embeddings — son más baratos y específicos para esa tarea.

    ¿Cuándo debería usar TensorFlow.js en lugar de una API de ML?

    TensorFlow.js tiene sentido cuando necesitas ejecutar inferencia en el cliente (sin enviar datos al servidor, por privacidad), cuando tienes latencia muy baja como requisito, o cuando quieres evitar costos de API a escala. El tradeoff es que los modelos disponibles para el navegador son más pequeños y menos potentes. Para la mayoría de proyectos web, una API de HuggingFace o OpenAI es la opción correcta hasta que tengas una razón específica para moverse al cliente.

    ¿Qué es el overfitting y por qué le importa al developer que consume modelos?

    El overfitting ocurre cuando un modelo aprende demasiado bien los datos de entrenamiento y pierde capacidad de generalizar a datos nuevos. Como developer que consume un modelo ya entrenado, el overfitting se manifiesta como comportamiento inesperado: el modelo funciona bien en ejemplos estándar pero falla en casos edge de tu dominio específico. Si ves esto, la solución no es ajustar el código — es cambiar de modelo, hacer fine-tuning, o cambiar cómo preparas el input (prompt engineering, preprocesado de texto).

    ¿Qué base de datos debo usar para guardar y consultar embeddings?

    Depende de tu stack. Si ya usas PostgreSQL o Supabase, la extensión pgvector añade soporte nativo para búsqueda por similitud coseno sin infraestructura adicional. Si necesitas escala masiva (millones de vectores con latencia sub-50ms), Pinecone o Weaviate son las opciones especializadas. Para prototipos o proyectos pequeños, guardar vectores en memoria con una búsqueda lineal es perfectamente válido mientras no superes los 10k documentos.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Claude API: Crash Course para developers con TypeScript

    Claude API: Crash Course para developers con TypeScript

    Hace unos meses un developer me escribió frustrado. Llevaba dos días intentando integrar Claude en su app. No le funcionaba el streaming, no entendía por qué sus respuestas llegaban cortadas, y había probado tres ejemplos distintos de Stack Overflow que usaban versiones diferentes del SDK.

    El problema no era la API. Era que había empezado por el medio.

    Esta es la Claude API introducción que yo habría querido tener al principio: sin rodeos, con código real, y con el orden correcto para entender qué está pasando antes de que algo falle.

    Qué es la Claude API y por qué te importa

    Claude es el modelo de lenguaje de Anthropic. La API te da acceso directo a ese modelo desde tu código: puedes enviarle mensajes, pedirle que razone, que use herramientas externas, que responda en streaming o que procese imágenes.

    La diferencia respecto a ChatGPT para developers es principalmente la calidad del razonamiento en tareas de código complejas y el system prompt — Claude lo sigue con una precisión que cambia cómo construyes agentes.

    Setup: API key y SDK

    Primero necesitas una cuenta en console.anthropic.com. Una vez dentro, ve a API Keys y genera una nueva clave. Guárdala — no la vuelves a ver.

    Instala el SDK oficial con npm o Bun:

    npm install @anthropic-ai/sdk
    # o con Bun
    bun add @anthropic-ai/sdk
    

    Guarda la clave en una variable de entorno. Nunca en el código:

    # .env
    ANTHROPIC_API_KEY=sk-ant-...
    

    Tu primera llamada en TypeScript

    Este es el "Hello World" de la Claude API. Sin clases, sin abstracción, directo al grano:

    import Anthropic from "@anthropic-ai/sdk";
    
    const client = new Anthropic({
      apiKey: process.env.ANTHROPIC_API_KEY,
    });
    
    async function main() {
      const response = await client.messages.create({
        model: "claude-sonnet-4-6",
        max_tokens: 1024,
        messages: [
          {
            role: "user",
            content: "Explica qué es un closure en JavaScript en 2 líneas.",
          },
        ],
      });
    
      console.log(response.content[0].type === "text" ? response.content[0].text : "");
    }
    
    main();
    

    Eso es todo. Ejecutas esto y tienes una respuesta de Claude en tu terminal.

    Lo que necesitas entender de la estructura:

    • model — qué versión de Claude usas (más sobre esto abajo)
    • max_tokens — límite de tokens en la respuesta (no el total de la conversación)
    • messages — array de turnos de conversación con role: "user" o role: "assistant"

    Los conceptos que no puedes ignorar

    Modelos disponibles

    Anthropic tiene tres familias activas:

    Modelo Cuándo usarlo
    claude-sonnet-4-6 El equilibrio perfecto: velocidad + calidad. Mi default para casi todo.
    claude-haiku-4-5 Más rápido y barato. Bueno para tareas simples o llamadas en volumen.
    claude-opus-4-8 El más potente. Para tareas de razonamiento complejo donde el coste no es el problema.

    Si estás empezando, usa claude-sonnet-4-6. No pienses más.

    System prompt vs User message

    El system es la personalidad y las instrucciones permanentes de Claude. El user es lo que cambia en cada turno.

    const response = await client.messages.create({
      model: "claude-sonnet-4-6",
      max_tokens: 1024,
      system: "Eres un reviewer de código senior. Responde siempre en español. Sé directo y señala el problema antes de proponer la solución.",
      messages: [
        {
          role: "user",
          content: "Revisa esta función: function add(a, b) { return a - b; }",
        },
      ],
    });
    

    El system prompt es donde ocurre la mayor parte de la magia cuando construyes agentes. Si quieres ver cómo llevamos esto a proyectos reales con Claude Code, en el curso Construye con IA cubrimos exactamente eso: de la idea al producto con agentes que siguen instrucciones de producción.

    Tokens: lo que cuesta dinero

    Un token es aproximadamente 0,75 palabras en inglés (algo menos en español). La API te cobra por input_tokens (lo que envías) y output_tokens (lo que Claude responde).

    Después de cada llamada puedes ver el uso:

    console.log(response.usage);
    // { input_tokens: 48, output_tokens: 312 }
    

    max_tokens limita la respuesta, no la llamada completa. Si pones max_tokens: 100 y la respuesta necesita 200 tokens, Claude cortará el texto a mitad. Es uno de los errores más comunes al empezar.

    ¿Cómo implementar streaming con la Claude API en TypeScript?

    Sin streaming, esperas a que Claude termine de generar toda la respuesta antes de recibirla. Con streaming, recibes los tokens a medida que se generan — igual que ves escribir a Claude en el chat web.

    Para UX en tiempo real, el streaming no es opcional. Es lo que distingue una app que se siente viva de una que "se congela" tres segundos antes de mostrar algo. En los proyectos de agentes que construimos en Labs, migrar de llamada síncrona a streaming eliminó la necesidad de un loader — los usuarios percibieron la respuesta como inmediata sin que cambiáramos nada más.

    import Anthropic from "@anthropic-ai/sdk";
    
    const client = new Anthropic({
      apiKey: process.env.ANTHROPIC_API_KEY,
    });
    
    async function streamResponse() {
      const stream = await client.messages.create({
        model: "claude-sonnet-4-6",
        max_tokens: 1024,
        stream: true,
        messages: [
          {
            role: "user",
            content: "Escribe un test unitario en TypeScript para una función que suma dos números.",
          },
        ],
      });
    
      for await (const event of stream) {
        if (
          event.type === "content_block_delta" &&
          event.delta.type === "text_delta"
        ) {
          process.stdout.write(event.delta.text);
        }
      }
    
      console.log("\n--- Stream completado ---");
    }
    
    streamResponse();
    

    El loop for await itera sobre los eventos del stream. El tipo que te importa es content_block_delta con delta.type === "text_delta" — ahí está el texto.

    ¿Qué es el tool use en Claude API y cómo funciona?

    Tool use (o function calling) permite que Claude llame a funciones definidas por ti. Claude decide cuándo usarlas y con qué argumentos. Tú ejecutas la función y le devuelves el resultado.

    El siguiente ejemplo define una herramienta get_weather ficticia:

    const response = await client.messages.create({
      model: "claude-sonnet-4-6",
      max_tokens: 1024,
      tools: [
        {
          name: "get_weather",
          description: "Obtiene el tiempo actual para una ciudad.",
          input_schema: {
            type: "object",
            properties: {
              city: {
                type: "string",
                description: "El nombre de la ciudad.",
              },
            },
            required: ["city"],
          },
        },
      ],
      messages: [
        {
          role: "user",
          content: "¿Qué tiempo hace en Madrid ahora mismo?",
        },
      ],
    });
    
    // Si Claude quiere usar la herramienta, el stop_reason será "tool_use"
    if (response.stop_reason === "tool_use") {
      const toolUse = response.content.find((b) => b.type === "tool_use");
      console.log("Claude quiere llamar a:", toolUse?.name);
      console.log("Con argumentos:", toolUse?.input);
      // Aquí ejecutarías la función real y devolverías el resultado a Claude
    }
    

    Esto es la base de cualquier agente. Claude no ejecuta código — tú lo ejecutas y le informas del resultado. El loop de razonamiento lo controla Claude; la ejecución la controlas tú. Si quieres ver cómo este patrón escala a un pipeline completo — desde un ticket de Jira hasta el deploy —, tienes el ejemplo en el post sobre automatizar el proceso de desarrollo con IA.

    Errores comunes al empezar

    Rate limits. La API tiene límites por minuto tanto en requests como en tokens. Si los golpeas, recibes un 429. Solución: exponential backoff o usar Haiku para prototipos de alto volumen.

    Context window agotado. Cada modelo tiene un límite de tokens totales en conversación (input + output). Sonnet 4.6 tiene 200K tokens de context window — es enorme, pero si metes archivos enteros en cada llamada, lo llenas. Sé selectivo con lo que incluyes en el contexto.

    Formato de mensajes incorrecto. El array messages debe alternar user y assistant. No puedes tener dos mensajes de user seguidos sin un assistant entre medias. Eso devuelve un error 400.

    max_tokens demasiado bajo. Si la respuesta se corta, sube max_tokens. El valor por defecto no existe — es un parámetro obligatorio. Empieza con 1024 y ajusta según lo que necesites.

    Variables de entorno no cargadas. Si ves AuthenticationError, casi siempre es que ANTHROPIC_API_KEY no está disponible en el proceso. Verifica con console.log(process.env.ANTHROPIC_API_KEY) antes de depurar nada más.

    Qué explorar después

    Una vez tienes la llamada básica y el streaming funcionando, estos son los siguientes pasos lógicos:

    Vision. Puedes enviar imágenes en el array content y Claude las analiza. Útil para screenshots, diagramas, facturas.

    Embeddings. Anthropic no tiene embeddings propios en la API, pero Claude funciona muy bien combinado con embeddings de OpenAI o Cohere para búsqueda semántica.

    Batch API. Para procesar cientos de prompts sin necesidad de respuesta en tiempo real. Hasta un 50% más barato que llamadas individuales.

    Workbench de Anthropic. En console.anthropic.com tienes un playground para probar prompts, comparar modelos y ver el uso de tokens antes de escribir una sola línea de código. Es la herramienta que más uso al diseñar system prompts.

    Multiturno real. Construir una conversación que mantenga contexto entre turnos requiere gestionar el array messages manualmente — añadir cada respuesta de Claude como role: "assistant" y cada input del usuario como role: "user". No hay estado en la API.

    Si quieres ver tool use aplicado a un workflow de code review automático antes de un PR, tienes el flujo completo en el post sobre agentic code review con Claude Code.

    Si tuvieras que elegir solo un área para explorar después del streaming, elige Vision — es el salto de ROI más rápido y el que más impacto tiene en una demo.


    FAQ

    ¿Necesito tarjeta de crédito para empezar?
    Sí. Anthropic requiere un método de pago para activar la API, pero tiene un tier de prueba con crédito gratuito. Puedes hacer cientos de llamadas de desarrollo sin pagar nada en los primeros días.

    ¿Cuál es la diferencia entre la API de Claude y Claude.ai?
    Claude.ai es el producto de consumo (el chat web). La API es el acceso programático al modelo. Tienen facturación y cuentas separadas. Una suscripción a Claude.ai no te da acceso a la API.

    ¿Cuánto cuesta en producción?
    Depende del modelo y el volumen. Claude Sonnet 4.6 está alrededor de $3 por millón de input tokens y $15 por millón de output tokens — verifica siempre en anthropic.com/pricing antes de hacer estimaciones de arquitectura, los precios se actualizan con cada generación de modelo.

    ¿Puedo usar la API en el frontend directamente?
    Técnicamente sí, pero nunca deberías. La API key quedaría expuesta en el cliente. Siempre llama a la API desde un backend o un serverless function que tú controlas.

    ¿Qué pasa si Claude no termina la respuesta y stop_reason no es end_turn?
    Si stop_reason es max_tokens, la respuesta se cortó por el límite que pusiste. Si es tool_use, Claude quiere ejecutar una herramienta. Si es stop_sequence, alcanzó una secuencia de parada que definiste. Valida siempre stop_reason en producción.


    Si quieres ver todo esto aplicado en un proyecto real — no en ejemplos de tutorial sino en un producto con usuarios — en Dominicode Labs tenemos el código de los proyectos que construimos en directo, incluyendo agentes con tool use y streaming. Es donde llevamos la teoría a producción.

    Y si prefieres el formato video con más ejemplos en directo, en el canal de YouTube de Dominicode cubrimos estas integraciones con frecuencia.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Formación en IA para equipos de desarrollo: 4 módulos

    Formación en IA para equipos de desarrollo: 4 módulos

    Me llamó un CTO a las 11 de la mañana. Su empresa tiene 18 developers. Llevan un año diciéndose que “van a adoptar IA”. Han probado ChatGPT, han instalado GitHub Copilot, alguien hizo un tutorial de Claude Code un sábado.

    Y aun así, el equipo sigue trabajando igual que en 2022.

    El problema no está en las herramientas. Está en que nadie tiene claro cómo integrar la formación en IA para equipos de desarrollo de forma coordinada, con metodología, sin que cada developer invente su propio flujo en solitario.

    Eso es exactamente lo que resuelve el programa que ofrezco desde Dominicode.

    El programa de formación en IA para equipos de desarrollo de Dominicode es un itinerario corporativo de 4 módulos — Fundamentos, Claude Code Avanzado, SDD y n8n — diseñado para equipos tech de 5 a 50 personas que necesitan adoptar IA de forma coordinada, no ad-hoc. Duración total: 48-72 horas.

    Por qué los equipos no adoptan IA (y el problema no es la herramienta)

    Cuando un equipo “no adopta IA”, el instinto es buscar la herramienta correcta. Probar otra. Comprar otra licencia. Mandar a alguien a un curso de medio día.

    Eso no funciona porque el problema no es la herramienta.

    La IA cambia cómo se diseña, cómo se especifica y cómo se construye software. Si solo añades una herramienta encima de un proceso que no ha cambiado, el resultado es ruido. Developers que usan IA para generar código que después nadie entiende. Tech leads que no saben cómo revisar trabajo asistido por IA. Proyectos que empiezan con entusiasmo y acaban con un pull request de 2.000 líneas que nadie quiere tocar.

    Según la investigación de GitHub sobre productividad con Copilot, los developers completan tareas hasta un 55% más rápido con asistencia de IA — pero solo cuando tienen flujos de trabajo estructurados, no cuando improvisan cada uno por su cuenta.

    Ya escribí sobre las consecuencias concretas en las consecuencias de no adoptar IA en el desarrollo. Lo que sigue aquí es la solución estructurada.

    El programa de formación en IA para equipos: 4 módulos en orden

    El programa no es una colección de talleres desconectados. Es una progresión deliberada: cada módulo construye sobre el anterior. No puedes enseñar Claude Code avanzado a un equipo que no entiende cómo funciona un LLM. No puedes implantar SDD en un equipo que aún no tiene flujos de trabajo con IA.

    El orden importa.

    Módulo Tema Duración Nivel
    1 Fundamentos de IA para Developers 8-12 h Todos
    2 Claude Code Avanzado 16-24 h Avanzado
    3 Spec-Driven Development (SDD) 12-20 h Intermedio
    4 n8n para Automatización 12-16 h Intermedio

    ### Módulo 1 — Fundamentos de IA para Developers

    Duración: 8-12 horas (varía según el nivel de partida del equipo)

    Aquí el objetivo no es impresionar. Es nivelar.

    Un equipo de 15 personas tiene 15 modelos mentales distintos sobre qué es la IA, qué puede hacer y cuándo falla. Este módulo construye una base compartida: cómo funcionan los LLMs, por qué el contexto es el recurso más escaso, cómo escribir prompts que no sean ruleta rusa.

    Sin esto, cada developer toma decisiones técnicas basadas en suposiciones distintas. Y eso se nota en producción.

    Módulo 2 — Claude Code Avanzado

    Duración: 16-24 horas

    Este es el módulo donde el equipo pasa de “usar IA” a “trabajar con IA de verdad”.

    No es un tutorial de instalación. Es flujo de trabajo real: cómo estructurar el contexto con CLAUDE.md, cómo usar hooks para automatizar validaciones, cómo orquestar subagentes para tareas paralelas, cómo integrar MCP servers con las herramientas internas del equipo.

    Si quieres entender el nivel de profundidad que cubre este módulo, el curso Construye con IA es la versión individual del mismo material — pensada para developers que quieren avanzar por su cuenta antes o después del programa corporativo.

    Módulo 3 — Spec-Driven Development (SDD)

    Duración: 12-20 horas

    Este módulo es el que más sorprende a los equipos. Y el que más impacto tiene a largo plazo.

    SDD es la metodología que desarrollé para el desarrollo asistido por IA — una forma de trabajar donde la especificación técnica existe antes del código y funciona como contrato compartido entre el equipo y la IA. Eso elimina la ambigüedad, reduce el retrabajo y hace que la IA genere código que encaja con la arquitectura real del proyecto.

    En el post sobre SDD en proyectos greenfield con slices verticales puedes ver cómo funciona aplicado a un proyecto real. El módulo corporativo va más lejos: cómo adaptar SDD a equipos con diferentes niveles de seniority y cómo integrarlo con metodologías ágiles existentes.

    Si alguien del equipo quiere prepararse antes del programa, el libro de SDD en Leanpub cubre la metodología completa.

    Módulo 4 — n8n para Automatización

    Duración: 12-16 horas

    n8n (open-source, self-hosteable) es el multiplicador. Cuando el equipo ya trabaja bien con IA a nivel individual, n8n permite construir workflows que amplifican esa productividad a nivel de proceso.

    Automatización de revisiones de código. Pipelines de QA asistidos por IA. Agentes internos que conectan el stack de la empresa — Jira, GitHub, Slack, Notion — con los modelos de lenguaje. Sin necesidad de escribir integraciones desde cero cada vez.

    Este módulo es deliberadamente el último. Sin los tres anteriores se convierte en un set de automatizaciones frágiles sin principios de diseño detrás.

    Para quién es este programa

    Para empresas tech de LATAM o España con equipos de desarrollo de 5 a 50 personas que quieren adoptar IA de forma coordinada, no ad-hoc.

    Para CTOs y tech leads que ya saben que la IA va en serio, pero necesitan un marco estructurado para llevarlo al equipo sin que sea caos.

    Para directores de ingeniería que tienen que justificar la inversión ante negocio y necesitan un programa con entregables concretos, no solo “horas de formación”.

    Para quién no es:

    No es para equipos que buscan un taller de dos horas para “motivar” al equipo con IA. No es para empresas que quieren implementar IA sin cambiar ningún proceso. Y no es para developers individuales — para eso existe el curso individual y Dominicode Labs, la comunidad donde trabajo estos temas cada semana.

    Cómo se entrega

    El programa puede ser presencial, online en vivo, o híbrido. Se adapta al calendario del equipo — no tienes que parar el sprint.

    Cada módulo incluye material práctico, código de ejemplo y entregables que el equipo se lleva: templates de prompts, configuraciones de CLAUDE.md, especificaciones SDD adaptadas a vuestro stack, workflows de n8n listos para customizar.

    El enfoque es 30% teoría, 70% práctica con casos reales. No slides de PowerPoint con capturas de pantalla de ChatGPT.

    ¿Te interesa para tu empresa?

    Si tienes un equipo de desarrollo y quieres entender si este programa encaja con vuestras necesidades, lo primero es una llamada de 30 minutos sin compromiso.

    Escríbeme directamente a bezael@gmail.com con el asunto “Formación B2B” y cuéntame brevemente el tamaño del equipo y el contexto. Te respondo en 24 horas.

    O si prefieres explorar más sobre el enfoque antes de contactar, visita dominicode.com — hay material suficiente para que entiendas exactamente cómo trabajo.

    FAQ — Preguntas frecuentes sobre el programa de formación en IA para equipos

    ¿El programa es modular o hay que contratarlo completo?

    Los cuatro módulos están diseñados para funcionar juntos, pero pueden contratarse de forma independiente. Si el equipo ya tiene base en fundamentos de IA, podemos entrar directamente desde Claude Code. La llamada inicial sirve para diagnosticar dónde está el equipo y qué tiene más sentido.

    ¿Cuánto cuesta el programa?

    El precio varía según modalidad (online, presencial, híbrido), número de módulos y tamaño del equipo. No hay una tarifa fija publicada porque cada empresa parte de un punto distinto. Escríbeme a bezael@gmail.com con el asunto “Formación B2B” y te envío propuesta personalizada en 24 horas.

    ¿Cuál es la duración total del programa completo?

    Entre 48 y 72 horas en total. Se imparte habitualmente en sesiones de 3-4 horas, 2-3 veces por semana, a lo largo de 4-8 semanas. También es posible formato intensivo de inmersión.

    ¿El programa es online, presencial o híbrido?

    Las tres opciones son posibles. Online en vivo es la más habitual para equipos distribuidos en LATAM y España. Presencial está disponible principalmente en España. El formato se decide según la distribución del equipo.

    ¿Qué nivel técnico se requiere para participar?

    Los módulos 1 y 2 son accesibles para cualquier developer con experiencia básica. Los módulos de SDD y n8n requieren nivel mid — no por la complejidad de las herramientas, sino porque el valor real está en aplicarlos a problemas de arquitectura reales.

    ¿Cómo se mide el impacto del programa?

    Definimos métricas antes de empezar: tiempo de ciclo de desarrollo, calidad de especificaciones, reducción de retrabajo, adopción activa de herramientas. Hacemos seguimiento 30 días después de cada módulo.

    ¿Qué diferencia este programa de un curso online normal?

    Un curso online lo hace cada developer a su ritmo, sin coordinación con el equipo. Este programa está diseñado para que el equipo aprenda junto, con casos del proyecto real de la empresa cuando es posible, generando cultura de equipo alrededor de la IA — no solo skills individuales.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Consecuencias de no adoptar la IA en tu equipo de desarrollo

    Consecuencias de no adoptar la IA en tu equipo de desarrollo

    Hace unos meses hablé con un CTO de una startup de logística. Tiene un equipo de ocho developers. Llevan dos años con el mismo stack, el mismo proceso, y la misma velocidad de entrega.

    Me preguntó qué pensaba de la IA en equipos de desarrollo.

    Le dije lo que pienso: que no adoptar IA hoy no es una postura neutral. Las consecuencias de no adoptar IA en desarrollo son concretas y medibles — se ven en la cuenta de resultados, en la rotación del equipo, y en la capacidad de competir.

    Se quedó callado unos segundos. Luego dijo: “Es que no quiero que el equipo dependa de una herramienta que no controlamos.”

    Eso es un miedo legítimo. Pero es el miedo equivocado.

    No adoptar IA en un equipo de desarrollo significa mantener flujos de trabajo manuales en tareas donde los modelos de lenguaje ya ofrecen ventaja medible: generación de tests, code review inicial, documentación y traducción de diseños a componentes. No es una opción neutral — es una decisión activa con un coste que se acumula cada semana.

    Las consecuencias no llegan de golpe. No hay una fecha en el calendario marcada “el día que te quedaste atrás”. Llegan de forma gradual, acumulada, invisible hasta que de repente son demasiado grandes para ignorar.

    Este post no es para convencerte de que la IA es maravillosa. Es para que veas con claridad lo que está pasando cuando un equipo decide no moverse.

    La brecha de velocidad que ya no puedes cerrar contratando

    La primera consecuencia es la más obvia y la más subestimada.

    Según la investigación de GitHub sobre productividad con Copilot, los developers completan tareas hasta un 55% más rápido cuando usan asistencia de IA. En la práctica, en los equipos con los que he trabajado y hablado, la diferencia oscila entre 2x y 4x según el tipo de tarea — las más repetitivas son las que más se aceleran.

    Si tu equipo no usa IA y tu competencia sí, no estás compitiendo en las mismas condiciones. Estás haciendo una carrera de 100 metros en la que la mitad de los participantes arrancó diez metros antes.

    El problema no es solo velocidad bruta. Es que la diferencia se amplifica. El equipo que usa IA itera más rápido, aprende más rápido, comete errores más baratos porque los detecta antes. El equipo que no usa IA itera a la misma velocidad que hace tres años.

    En doce meses esa brecha no se cierra contratando un developer más. Porque la empresa de al lado también puede contratar, y además tiene multiplicadores de velocidad que tú no tienes.

    Pierdes a los developers que más te importa conservar

    Esta es la consecuencia que menos anticipan los CTOs y tech leads.

    Los developers que más rinden — los que tienen criterio, autonomía, y ganas de aprender — son exactamente los que primero se van de un entorno donde no pueden usar las herramientas que ya usan en casa.

    Un developer senior en 2026 experimenta con Claude Code en sus proyectos personales. Entiende cómo funciona un agente. Tiene flujos de trabajo propios con IA que le hacen más productivo.

    Si llega a la oficina y le pides que trabaje como si todo eso no existiera, el mensaje que recibe no es “somos conservadores”. El mensaje que recibe es “aquí no valoramos que te mantengas actualizado”.

    Y se va. No a otra empresa que haga lo mismo. Se va a un sitio donde puede usar lo que sabe.

    Esta transformación ya está ocurriendo en el mercado — los mejores perfiles están pasando de developer a product builder, y los entornos que no permiten IA son los primeros de los que escapan.

    Los developers que se quedan en equipos sin IA no siempre son los que menos valen. Pero con el tiempo, sí son cada vez más los que no tienen dónde ir.

    El coste de oportunidad que nadie contabiliza

    Hay un tercer coste que es más difícil de ver porque nunca aparece en ningún informe.

    Es el coste de todo lo que no construiste.

    Cuando un equipo sin IA tarda tres semanas en sacar una feature, no solo está tardando tres semanas. Está eligiendo no sacar las otras features que hubiera podido sacar si fuera más rápido. Está retrasando el feedback del usuario. Está postergando el aprendizaje de si la dirección que tomó es correcta.

    Un equipo con IA que entrega en una semana no solo tiene dos semanas más. Tiene dos iteraciones más. Dos ciclos de feedback más. Dos oportunidades de corregir antes de haber invertido demasiado en la dirección equivocada.

    El coste de oportunidad no se ve en el sprint review. Se ve doce meses después, cuando la empresa que iteraba más rápido ya encontró el product-market fit y la tuya sigue ajustando la primera versión.

    La deuda técnica de la IA ignorada

    Hay equipos que no adoptan IA de forma activa pero tampoco la prohíben. Lo que pasa en esos equipos es peor de lo que parece.

    Los developers individuales empiezan a usar IA de forma clandestina, sin criterio compartido, sin patrones comunes. Uno usa Copilot para autocompletar. Otro usa ChatGPT para generar tests. Otro usa Claude para hacer code reviews. Cada uno con su propio criterio, sus propias convenciones, y sin que nadie sepa qué se generó con IA y qué no.

    Eso es deuda técnica de un tipo nuevo. No es deuda de código mal escrito. Es deuda de proceso: nadie sabe cómo se tomaron las decisiones, nadie puede auditar el output, y la calidad del código depende del prompt del developer en ese momento específico, no de los estándares del equipo. Ya escribí sobre este problema en detalle en el post sobre vibe coding y confiabilidad en proyectos de IA — y la raíz es siempre la misma: IA sin sistema.

    La adopción estructurada de IA — con criterio, con convenciones, con revisión — es precisamente lo que evita ese caos. Ignorar la IA no lo evita. Solo lo empuja debajo de la superficie hasta que explota.

    En el curso Construye con IA: de la idea al producto con Claude Code trabajo exactamente este problema: no cómo usar la IA para escribir código más rápido, sino cómo construir un sistema — con especificaciones, contexto persistente, y flujos estructurados — para que el output sea consistente y revisable.

    Qué significa adoptar IA en un equipo (y qué no)

    Adoptar IA no significa que el equipo pase a generar código sin revisión.

    No significa confiar ciegamente en el output del modelo. No significa eliminar code reviews, ni tirar la arquitectura que funciona, ni que cualquier developer junior pueda hacer el trabajo de un senior porque “la IA lo ayuda”.

    Significa integrar herramientas de IA en el flujo de trabajo del equipo con criterio. Definir qué tareas se benefician de la IA y cuáles no. Establecer convenciones sobre cómo se revisa el código generado. Formarse en cómo dar contexto de calidad a los modelos para obtener output de calidad.

    El miedo legítimo del CTO que mencioné al principio — no querer depender de una herramienta que no controlas — tiene una respuesta estructurada: aprender a controlarla. Entender sus límites. Usar IA donde amplifica el criterio humano, no donde lo sustituye.

    Eso requiere formación, no solo instalación de plugins.

    Qué puede hacer un equipo esta semana

    No voy a decirte “empieza con un piloto de tres meses y mide los resultados”. Eso es lo que dice alguien que no tiene que entregar mañana.

    Lo que puede hacer un equipo esta semana es concreto:

    1. Identifica una tarea repetitiva que haga el equipo a diario: escribir tests, generar documentación, hacer code reviews iniciales, traducir diseños a componentes.
    2. Elige a un developer con ganas de experimentar. Que no sea el más escéptico ni el más entusiasta sin criterio.
    3. Deja que pase una semana usando IA en esa tarea específica, con la consigna de que documente qué funcionó y qué no.
    4. Revisa los resultados con el equipo. No los números — la experiencia. Qué cambió en el proceso, qué parte del output necesitó más revisión, qué parte sorprendió.

    Una semana. Una tarea. Un developer. Eso es suficiente para tener datos reales en lugar de suposiciones.

    Si quieres un marco más estructurado para llevarlo a tu equipo, en Dominicode Labs tenemos proyectos y patrones de adopción que hemos validado en proyectos reales — no teoría de management sino flujos que developers usan en producción.

    El momento en que la decisión ya no es tuya

    Hay una última consecuencia que vale la pena nombrar.

    Si esperas demasiado, la decisión de adoptar IA deja de ser una decisión estratégica y se convierte en una reacción de emergencia.

    El CEO presiona porque vio a un competidor entregar más rápido. Los clientes preguntan por qué la velocidad de entrega no mejora. Los developers más valiosos se van a empresas que ya tienen el sistema montado.

    Y entonces adoptas IA con prisa, sin criterio, sin formación, y produces exactamente el caos que querías evitar.

    La ventana para hacer esto bien — de forma estructurada, sin presión, con tiempo para equivocarse y corregir — es ahora. No porque la IA vaya a desaparecer. Sino porque cuanto más tiempo pasa, más dura es la curva de puesta al día.

    Los equipos que adoptan IA hoy no solo producen más. Están construyendo un músculo que cada mes que pasa se hace más difícil de construir partiendo de cero.

    Si quieres empezar de forma estructurada, el siguiente paso concreto está aquí: Construye con IA: de la idea al producto con Claude Code — el sistema que uso yo, aplicado a proyectos reales desde el primer día.

    Resumen: consecuencias de no adoptar IA en equipos de desarrollo

    Consecuencia Cuándo se nota Cómo prevenirla
    Brecha de velocidad vs. competidores 3-6 meses Adopción estructurada en tareas repetitivas
    Fuga de talento senior 6-12 meses Permitir y formalizar el uso de herramientas IA
    Pérdida de coste de oportunidad 6-18 meses Reducir ciclos de iteración con IA
    Deuda de proceso (IA sin sistema) Desde el día 1 Establecer convenciones de uso y revisión
    Pérdida de control estratégico +12 meses Adoptar antes de que la presión externa obligue

    ## Preguntas frecuentes sobre la adopción de IA en equipos de desarrollo

    ¿Es demasiado pronto para que los equipos adopten IA en su flujo de trabajo de desarrollo?

    No. GitHub Copilot lleva años en equipos enterprise. Claude Code y Cursor tienen bases de usuarios activas y en crecimiento documentado. El riesgo de adoptar demasiado pronto es mucho menor que el de adoptar demasiado tarde — y los datos de productividad ya están ahí.

    ¿La IA en desarrollo requiere que todos los developers del equipo la usen?

    No de golpe. Pero sí con el tiempo. Una adopción parcial sin coordinación — donde cada developer hace lo que quiere — genera inconsistencia en el codebase y deuda de proceso. Empieza con los que tienen ganas, documenta lo que funciona, y después extiéndelo con convenciones comunes.

    ¿Qué pasa con la calidad del código si se genera con IA?

    Depende del contexto que le des al modelo. Contexto preciso — especificación clara, arquitectura documentada, convenciones definidas — produce código que pasa code review. Descripción vaga produce código que necesita reescribirse. El problema de calidad no es la IA: es la falta de sistema alrededor de la IA.

    ¿Cómo convenzo a mi equipo de empezar a usar IA si hay resistencia?

    No convenzas. Muestra. Toma una tarea concreta, hazla tú con IA delante del equipo, y deja que el resultado hable. Los equipos resistentes suelen estarlo porque nunca han visto un caso de uso real y bien ejecutado — solo demos de hype. Un ejemplo concreto, en su stack, con su tipo de problema, cambia la conversación.

    ¿Qué riesgos reales existen en adoptar IA en un equipo de desarrollo?

    Tres riesgos concretos: código generado sin revisión que introduce bugs o vulnerabilidades, dependencia de modelos propietarios con costes variables, y degradación de habilidades en developers que delegan demasiado sin entender el output. Todos son mitigables: code review obligatorio del código generado, presupuesto controlado de API, y formación en cómo evaluar críticamente el output del modelo.

    ¿Cuánto tiempo lleva ver resultados reales de adoptar IA en un equipo?

    En tareas repetitivas — tests, documentación, boilerplate — los resultados son visibles en la primera semana. El impacto en velocidad de entrega de features completas se mide bien a partir del primer mes, cuando el equipo ya tiene un flujo establecido en lugar de experimentar caso a caso.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Agentic code review con Claude Code: fin al review inconsistente

    Agentic code review con Claude Code: fin al review inconsistente

    Hace unos meses revisé el historial de PRs de un proyecto que llevaba tres años en producción. Había 600 pull requests cerrados. De esos, el 40% tenían el mismo comentario de review: "Falta manejo de errores".

    El mismo comentario. 600 veces. Durante tres años.

    Nadie había creado una regla. Nadie había automatizado la revisión. El code review dependía de que alguien con criterio tuviera tiempo y energía ese día. Y cuando no lo tenía, el PR se aprobaba igual.

    Ese patrón tiene nombre: es el problema que el agentic code review viene a eliminar. Y hoy, con Claude Code, puedes tenerlo funcionando en tu proyecto en minutos.

    Qué es el agentic code review (y qué no es)

    Un agentic code review no es pedirle a un LLM que "revise este archivo". Eso es un chat con contexto limitado.

    Un agentic code review es un proceso donde un agente de IA recorre el diff de tu PR de forma autónoma, lanza subagentes especializados en paralelo, analiza el historial de git para entender el contexto, y filtra los resultados por nivel de confianza antes de reportar.

    La diferencia es estructural. En lugar de una respuesta de texto libre, tienes un pipeline que:

    1. Lee el PR completo con todos sus cambios
    2. Lanza múltiples agentes en paralelo con roles distintos
    3. Puntúa cada hallazgo con un nivel de confianza configurable
    4. Solo reporta los problemas que superan un umbral concreto
    5. Entrega los resultados con enlaces directos a las líneas de código

    Con Claude Code, este pipeline puedes crearlo hoy y activarlo en segundos.

    Cómo funciona /code-review en Claude Code

    Claude Code te permite crear el comando /code-review como un slash command personalizado en .claude/commands/review.md. No es un built-in nativo de Claude Code — es un skill que configuras una vez y luego ejecutas en cualquier repositorio.

    Prerequisito: Necesitas crear el archivo .claude/commands/review.md con la definición del comando. Si ya tienes Claude Code con skills personalizados instalados (como los de Dominicode), este paso lo tienes cubierto. Puedes ver más artículos sobre cómo configurar Claude Code en el blog de Dominicode.

    Una vez configurado, cuando lo ejecutas sobre un PR abierto, lanza cuatro agentes en paralelo:

    • Agentes #1 y #2: Auditan el cumplimiento de las reglas definidas en tu CLAUDE.md (con redundancia para reducir falsos negativos)
    • Agente #3: Escanea los cambios del PR en busca de bugs evidentes — no el codebase completo, solo el diff
    • Agente #4: Analiza el git blame e historial del repo para detectar problemas que solo tienen sentido con contexto histórico

    El skill de review define un sistema de puntuación de confianza — un ejemplo habitual que puedes copiar y adaptar:

    0   → Falso positivo probable
    25  → Podría ser real
    50  → Real, pero menor
    75  → Real e importante
    100 → Absolutamente seguro
    

    El threshold por defecto en la mayoría de implementaciones es 80. Cualquier hallazgo por debajo no se reporta. Esto no es arbitrario: es lo que separa el ruido del signal en una revisión útil.

    El comando en la práctica

    # Revisión en terminal (mientras trabajas en local)
    /code-review
    
    # Publicar la revisión como comentario en el PR de GitHub
    /code-review --comment
    

    Nota: El flag --comment forma parte de la implementación del skill personalizado. Para que funcione, tu archivo .claude/commands/review.md debe incluir la lógica para detectar el PR activo del branch y postear el comentario en GitHub via gh CLI. El comportamiento no es nativo de Claude Code — lo defines tú en el skill.

    El flag --comment es el que convierte la herramienta en algo que vive dentro de tu flujo de trabajo real. El agente no solo te dice qué está mal — lo posta directamente en el PR con los links exactos a las líneas.

    Un output real tiene este aspecto (output de ejemplo):

    ## Code review
    
    Found 3 issues:
    
    1. Missing error handling for OAuth callback
       (CLAUDE.md says "Always handle OAuth errors")
       https://github.com/owner/repo/blob/abc123/src/auth.ts#L67-L72
    
    2. Memory leak: OAuth state not cleaned up after failed login
       (missing cleanup in finally block — bug, not pre-existing)
       https://github.com/owner/repo/blob/abc123/src/auth.ts#L88-L95
    
    3. Inconsistent naming: function uses snake_case
       (conventions/CLAUDE.md says "Use camelCase for functions")
       https://github.com/owner/repo/blob/abc123/src/utils.ts#L23-L28
    

    Tres problemas. Tres links directos. Sin ruido.

    Por qué el code review manual falla en producción

    No es una cuestión de habilidad. Es una cuestión de sistema.

    El code review manual tiene tres fallos estructurales que ningún proceso de equipo ha conseguido eliminar completamente:

    Inconsistencia por contexto. El mismo developer revisa de forma diferente un lunes a las 9 de la mañana y un viernes a las 6 de la tarde. Las reglas que aplica dependen de su estado mental, no del código.

    Punto ciego de los cambios recientes. Cuando tienes el código en la cabeza porque acabas de escribirlo, tu cerebro autocompleta lo que falta. El reviewer que eres tú mismo a los 5 minutos de terminar no ve los bugs que sí vería dentro de 3 horas.

    Reglas no escritas que no se comprueban. Tu equipo puede tener convenciones de arquitectura claras en la mente de los seniors, pero si no están en un archivo que el proceso de review comprueba activamente, son invisibles para el proceso.

    El agentic code review resuelve los tres. No se cansa. No autocompleta. Y si defines tus reglas en CLAUDE.md, las comprueba en cada PR sin excepción.

    Cómo integrarlo en tu workflow real

    El punto de entrada más simple es a nivel local, en tu flujo individual:

    # 1. Terminas de implementar un feature
    git add .
    git commit -m "feat: add OAuth flow"
    
    # 2. Abres el PR en GitHub
    gh pr create --title "Add OAuth flow" --body "..."
    
    # 3. Ejecutas el agentic review antes de pedir revisión humana
    /code-review --comment
    

    El agente revisa el PR y posta el comentario. Tú ves los issues, los corriges en una nueva commit, y solo entonces pides revisión humana. Tu reviewer llega a un PR que ya ha pasado por un filtro.

    El segundo nivel es definir qué reglas quieres que el agente compruebe en cada review. Eso va en tu CLAUDE.md:

    ## Code Review Standards
    
    - Always handle async errors with try/catch — no unhandled promises
    - Use camelCase for functions, PascalCase for classes
    - No direct DOM manipulation in Angular components
    - Every public method must have JSDoc if it's part of a service API
    - No hardcoded strings — use i18n keys or constants
    

    A partir de ese momento, el agente comprueba estas reglas en cada PR de forma automática. Cada regla que documentas elimina una categoría entera de errores que antes dependían de que alguien se acordara de revisarlos.

    Puedes encontrar más recursos sobre cómo estructurar CLAUDE.md para workflows de IA en el canal de YouTube de Dominicode, donde cubrimos este tipo de setups en profundidad. Y la documentación oficial del sistema está en docs de Claude Code de Anthropic.

    Agentic vs. manual: la comparativa real

    Code review manual Agentic code review
    Consistencia Varía por persona y momento Idéntica en cada PR
    Velocidad Minutos u horas Segundos
    Contexto histórico Solo si el reviewer conoce el historial Analiza git blame automáticamente
    Reglas del equipo Depende de la memoria Lee CLAUDE.md siempre
    Falsos positivos Bajos (humano con criterio) Filtrados por threshold de confianza
    Escala Limitada por tiempo humano Ilimitada

    La conclusión no es "reemplaza el code review humano". Es "llega al code review humano con el trabajo sucio ya hecho".

    El reviewer humano aporta lo que el agente no puede: criterio de producto, contexto de negocio, decisiones de arquitectura que van más allá del diff. Pero no necesita gastar ese criterio en detectar que falta un try/catch. Para eso está el agente.

    El skill personalizado: más allá del comando base

    El /code-review base es el punto de partida. Pero el sistema de skills de Claude Code te permite ir más lejos: crear un skill de revisión de código adaptado exactamente a tu stack y tus estándares.

    Un skill personalizado vive en .claude/skills/review.md y puede definir categorías de severidad propias:

    ## Review Categories
    
    ### Critical (must fix before merge)
    - Security vulnerabilities (SQL injection, XSS, exposed secrets)
    - Data loss risks
    - Breaking changes sin deprecation notice
    
    ### Important (should fix)
    - Missing error handling in async operations
    - N+1 queries en loops
    - Estado mutable compartido sin sincronización
    
    ### Suggestions (nice to have)
    - Naming improvements
    - Refactoring opportunities
    - Test coverage gaps
    

    Esto no es documentación para humanos. Es el contrato que el agente respeta en cada revisión.

    Si quieres explorar este nivel de customización con casos reales de producción, en el curso Construye con IA vemos exactamente cómo construir este tipo de workflows: desde el skill de review hasta la integración completa en el ciclo de desarrollo.

    Lo que el agentic code review no puede hacer (todavía)

    Hay que ser honestos sobre los límites.

    El agente revisa el diff, no el sistema. Si tu PR introduce un cambio correcto en aislamiento pero que rompe un contrato implícito con otro módulo que no está en el diff, el agente no lo va a ver. Para eso necesitas tests de integración, no un reviewer.

    Tampoco detecta problemas de producto. Un endpoint que técnicamente funciona pero que resuelve mal el problema del usuario es invisible para el agente. Ese criterio es humano, siempre.

    Y los falsos negativos existen. Un confidence threshold de 80 elimina el ruido, pero también puede silenciar algún hallazgo real que el agente no puntúa con suficiente confianza. No es el 100% de los problemas. Es el 80% de los problemas que más tiempo consumen en reviews manuales.

    Con esos límites claros, el agentic code review es una de las adiciones más baratas y de mayor impacto que puedes añadir a tu workflow hoy.

    Empieza con esto

    Si tienes Claude Code instalado, el punto de entrada es inmediato:

    # En un repo con un PR abierto
    /code-review
    

    Si quieres que el agente comprenda las reglas de tu proyecto, el segundo paso es crear o mejorar tu CLAUDE.md con las convenciones que quieres que compruebe.

    Y si quieres ver esto aplicado a un proyecto real — con las decisiones de qué documentar, cómo estructurar el skill y cómo encajarlo en un pipeline de CI — en Dominicode Labs tienes el proyecto de referencia con el setup completo que usamos en producción.


    FAQ — Preguntas frecuentes sobre agentic code review

    ¿El agentic code review reemplaza completamente al code review humano?

    No, y no debería. El agente es muy eficaz detectando problemas técnicos concretos: errores de manejo de excepciones, violaciones de convenciones, memory leaks en el diff. El reviewer humano aporta criterio de producto, arquitectura y contexto de negocio. La combinación de ambos es más potente que cualquiera de los dos solos.

    ¿Necesito una configuración especial de GitHub o CI para usar /code-review --comment?

    El flag --comment requiere que tu implementación del skill incluya la lógica para postear via gh CLI con acceso al repo. Si ya tienes Claude Code configurado con acceso al repositorio de GitHub, el skill puede activar el comentario sin pasos adicionales. El agente detecta el PR activo del branch actual.

    ¿Qué pasa si el agente no tiene acceso a mi CLAUDE.md?

    Sin un CLAUDE.md, el agente solo puede revisar bugs genéricos y problemas obvios del diff. Las reglas específicas de tu equipo — convenciones de naming, patrones de arquitectura, estándares de seguridad — no se comprueban. El CLAUDE.md es lo que convierte el agentic code review de "útil" a "imprescindible".

    ¿Puedo ajustar el threshold de confianza para que reporte más o menos problemas?

    Sí. El threshold lo defines tú en la implementación del skill. El valor 80 es el habitual en setups de referencia, pero puedes bajarlo (por ejemplo, a 60) para ver más hallazgos con posibles falsos positivos, o subirlo (a 90+) para ver solo los problemas con certeza casi absoluta. Para proyectos maduros con buenas convenciones documentadas, un threshold alto es lo más productivo.

    ¿El agente revisa el codebase completo o solo los cambios del PR?

    Solo los cambios del PR — el diff. Esto es una decisión de diseño deliberada: el agente no está ahí para auditar toda la deuda técnica del proyecto, sino para asegurarse de que los cambios nuevos no introducen problemas. La deuda existente es otra conversación.

    ¿Funciona con cualquier lenguaje o framework?

    El /code-review base analiza el código con el modelo de Claude, que entiende prácticamente cualquier lenguaje. Para revisiones especializadas en un framework concreto (Angular, React, NestJS), un skill personalizado en .claude/skills/review.md con reglas específicas de ese stack da resultados significativamente mejores.


    El code review manual no va a desaparecer. Pero el 70% del trabajo que hoy consume ese proceso puede delegarse a un agente que lo hace mejor, más rápido y sin quejarse de que el PR llegó el viernes por la tarde.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Vibe coding sin sistema: por qué tu proyecto con IA se rompe

    Vibe coding sin sistema: por qué tu proyecto con IA se rompe

    La primera semana fue increíble.

    Abriste Claude Code, describiste la idea a grandes rasgos, y el proyecto arrancó. En dos horas tenías rutas funcionando. En cuatro tenías la autenticación. En un día, un prototipo que podías enseñar. Sentiste que habías desbloqueado algo — que la IA era la ventaja que llevabas buscando.

    La segunda semana empezaron las grietas. Añadiste una feature nueva y rompiste una que ya funcionaba. Pediste al modelo que corrigiera el bug y generó código con una convención de nombres distinta a la del resto del proyecto. Abriste el archivo equivocado porque en una sesión le pusiste un nombre y en otra, otro.

    La tercera semana dejaste de entender tu propio proyecto.

    Esto no es un problema de la IA. Es el resultado predecible del vibe coding sin sistema — y hay una salida que no implica empezar desde cero.


    El ciclo que reconocerás si llevas más de dos semanas con IA

    El vibe coding tiene un patrón muy concreto. Arranca con energía, avanza rápido, y luego se convierte en deuda que nadie quiere pagar.

    Semana 1 — La euforia del prototipo. El modelo genera código que funciona. Tú describes lo que quieres, él lo construye. Cada sesión termina con algo nuevo encima de la mesa. Sientes que puedes construir cualquier cosa.

    Semana 2 — Los primeros síntomas. Añadir una feature empieza a costar más de lo esperado. El modelo genera código que no encaja del todo con lo que ya existe — naming diferente, estructura diferente, patrones distintos. Cada sesión nueva es ciega respecto a las decisiones de la anterior.

    Semana 3 — El colapso. El proyecto tiene capas que se contradicen entre sí. No puedes explicarle a nadie la arquitectura — ni siquiera a la IA que lo construyó. Cada sesión nueva te exige re-explicar el contexto desde cero. Y cuando lo haces, el modelo entiende una versión diferente de lo que tienes.

    Aquí hay dos salidas que la mayoría elige: abandonar el proyecto o empezar desde cero con la promesa de “esta vez lo haré mejor”. Ninguna funciona porque el problema no es el punto de partida. Es la ausencia de sistema.


    Por qué el vibe coding escala mal

    Por defecto, la IA no carga el estado de sesiones anteriores. Aunque herramientas como Claude Projects permiten persistir algo de contexto entre conversaciones, ese contexto no es estructurado — no sabe que decidiste usar repositorios en lugar de servicios directos, ni recuerda que el módulo de usuarios tiene una estructura específica, ni que descartaste la opción B el martes porque tenía un problema de concurrencia.

    Lo que el modelo construye en cada sesión es una respuesta razonable al contexto que le das en ese momento. Sin especificación, sin arquitectura documentada, sin contexto persistente, ese contexto siempre es incompleto. Y el modelo completa los huecos con sus propias suposiciones — razonables para un proyecto genérico, incorrectas para el tuyo.

    El resultado es código construido sobre arena. Cada sesión añade una capa nueva que puede o no ser compatible con lo que ya existe. Con el tiempo, la incoherencia se acumula hasta que el proyecto es incomprensible — no porque sea complejo, sino porque nadie tomó decisiones explícitas.

    Esto no es un defecto del modelo. Es una consecuencia directa de cómo usamos el modelo.


    Los 3 síntomas de que tu proyecto está en modo vibe

    Antes de hablar de la solución, vale la pena identificar dónde estás. Estos tres síntomas aparecen en orden: si tienes los tres, el proyecto ya necesita intervención.

    Naming inconsistente entre archivos. Un archivo se llama user-service.ts, otro usersService.ts, otro UserManager.ts. Las variables que representan el mismo concepto tienen nombres distintos según la sesión en que se crearon. El proyecto habla idiomas distintos en cada carpeta.

    Tests que no prueban lo que dicen. Los tests existen — el modelo siempre los genera cuando se los pides — pero prueban el código tal como fue escrito en ese momento, no el comportamiento que el sistema debería tener. Cuando el código cambia, los tests se rompen de formas que no esperabas. O peor: siguen en verde porque prueban implementación, no contrato.

    No puedes explicar la arquitectura de tu propio proyecto. Este es el síntoma definitivo. Si le preguntas al modelo “¿cuál es la arquitectura de este proyecto?” y la respuesta que genera no coincide con lo que tienes, tienes un problema de contexto. Si tú mismo no puedes describir en dos párrafos cómo fluyen los datos de principio a fin, el proyecto ya está en modo vibe terminal.

    Si reconoces los tres, no significa que tengas que tirar el código. Significa que tienes que añadir lo que falta: sistema.


    El sistema que reemplaza al vibe

    Pasar del vibe coding al desarrollo con sistema no es abandonar la IA. Es usarla de forma diferente — con estructura que la hace más efectiva, no más lenta.

    El sistema tiene cuatro piezas. No son opcionales entre sí.

    1. Spec antes de código (SDD)

    La especificación no es un documento burocrático. Es la respuesta a: ¿qué estoy construyendo exactamente, para quién, y cómo fluye la información?

    Con Spec-Driven Development, la spec se escribe antes de abrir el editor. No porque sea una regla, sino porque un modelo que recibe una spec bien escrita genera código diez veces más coherente que uno al que le describes la idea de viva voz. La spec define los contratos. El modelo los implementa. El espacio de decisión se reduce y el output es predecible.

    2. Contexto persistente (CLAUDE.md)

    El CLAUDE.md en la raíz del proyecto es el system prompt que Claude Code lee al inicio de cada sesión. Contiene el stack, las convenciones de naming, las restricciones explícitas y el estado actual del proyecto. No es documentación — es la memoria estructurada que el modelo necesita para ser consistente. En otros entornos como Cursor o Windsurf, el concepto equivalente existe con distintos nombres (.cursor/rules/, AGENTS.md).

    Sin este archivo, cada sesión es ciega. Con él, cada sesión arranca desde el mismo punto de partida. Las decisiones tomadas en día 1 siguen vigentes en día 30. Aquí tienes cómo estructurar este archivo paso a paso si quieres implementarlo hoy.

    3. Tareas pequeñas (chunking)

    “Implementa el sistema de autenticación completo” es el tipo de prompt que genera código plausible pero incoherente con tu proyecto. El modelo toma demasiadas decisiones implícitas porque el scope es demasiado amplio.

    La regla es: una tarea por sesión, un contrato por tarea. En lugar de pedir la autenticación completa, pides el esquema de usuario, luego el endpoint de login, luego el middleware de validación. Cuatro sesiones. Cuatro piezas que encajan porque cada una tiene un contexto explícito y un alcance controlado.

    4. Validación continua

    Al final de cada sesión, pides al modelo un resumen: qué se implementó, qué decisiones se tomaron, qué queda pendiente. Ese resumen va a un session-log.md con fecha. La sesión siguiente empieza con ese log como contexto. No empiezas desde cero — empiezas desde donde lo dejaste.

    El context engineering es la disciplina que une estas cuatro piezas. No es un concepto teórico — es la práctica concreta de gestionar qué información recibe el modelo en cada momento.


    Cómo hacer la transición sin empezar desde cero

    Este es el punto donde la mayoría para: “mi proyecto ya es un caos, tendría que reescribirlo todo”. No.

    La transición tiene cinco pasos y los puedes empezar hoy con el código que tienes.

    Paso 1 — Audita lo que existe. Antes de añadir nada, entiende el estado real del proyecto. Pídele al modelo que lea tu estructura de carpetas y te describa la arquitectura que ve. Compara esa descripción con lo que creías que habías construido. La brecha entre las dos es tu deuda de contexto.

    Paso 2 — Genera la spec retroactiva. No necesitas escribir la spec desde cero — puedes generarla a partir del código existente. Dale al modelo el contexto actual y pídele que genere una spec de lo que existe: entidades, contratos, flujos. Esa spec se convierte en la verdad oficial del proyecto, no el código.

    Paso 3 — Crea el CLAUDE.md. Con la spec en mano, crea el archivo de contexto persistente. Incluye el stack real (no el ideal), las convenciones que ya están en el código aunque no estuvieran documentadas, y las restricciones que te habría gustado tener desde el principio. Esto es lo que normaliza el naming y la estructura en todas las sesiones futuras.

    Paso 4 — Divide lo que queda en tareas pequeñas. El backlog de features pendientes deja de ser una lista de ideas y pasa a ser una lista de contratos. Cada tarea tiene una descripción concreta: qué recibe, qué devuelve, cómo interactúa con lo existente. El modelo implementa contratos, no ideas.

    Paso 5 — Valida antes de seguir. Antes de añadir la siguiente feature, escribe o genera los tests del contrato de la feature actual. No para cubrir el código — para verificar el comportamiento. Si el test falla cuando cambias algo que no debería afectarlo, el test te está diciendo que el contrato no estaba claro.

    Son cinco pasos que se pueden hacer en una tarde si el proyecto no es demasiado grande. El resultado no es un proyecto perfecto — es un proyecto con el que puedes volver a trabajar con confianza.


    La diferencia que importa en producción

    El vibe coding no es malo. Es la herramienta correcta para el momento incorrecto.

    Para validar una idea en 48 horas, el vibe coding es insuperable. Para construir algo que tendrás que mantener en semanas 4, 8 y 16, es un problema en espera de ocurrir.

    La diferencia entre un developer que usa IA con efectividad y uno que acaba atascado no es el modelo que usan, ni el IDE, ni los prompts. Es si tienen sistema o no. Si cada sesión nueva añade coherencia al proyecto o añade caos.

    El sistema no frena la velocidad de la IA. La mantiene en el tiempo.

    Si quieres ver esto aplicado en proyectos reales — desde la spec inicial hasta el producto funcionando, con CLAUDE.md, SDD y Claude Code — el curso Construye con IA: de la idea al producto cubre exactamente ese flujo. Y si quieres trabajar la transición con proyectos concretos y feedback en comunidad, en Dominicode Labs hacemos exactamente eso.


    FAQ

    ¿El vibe coding sirve para algo?

    Sí, y mucho. El vibe coding es la herramienta perfecta para prototipar ideas rápido — para validar si algo es técnicamente posible, para hacer demos, para explorar una API que no conoces. El problema no es el vibe coding en sí, sino usarlo para construir algo que vas a mantener durante semanas o meses. En ese contexto, la ausencia de sistema convierte la velocidad inicial en deuda que pagas después con intereses.

    ¿Cuándo está bien improvisar?

    Siempre que el objetivo sea explorar, no construir. Si abres una sesión nueva para entender cómo funciona un nuevo framework, para probar una librería, o para validar si tu idea de arquitectura tiene sentido — improvisa sin culpa. El momento en que decides que algo va a producción o que tendrás que volver a ello en una semana, el sistema tiene que entrar.

    ¿Tengo que empezar desde cero si mi proyecto ya es un caos?

    No. La spec retroactiva y el CLAUDE.md te permiten añadir estructura al código existente sin reescribirlo. El código puede quedarse como está mientras añades el sistema que le da coherencia hacia adelante. Lo que sí tendrás que hacer es tomar las decisiones que no tomaste al principio — naming, arquitectura, convenciones — y documentarlas. Eso es trabajo que tarda horas, no semanas.

    ¿El sistema con IA hace el desarrollo más lento?

    La percepción de velocidad que da el vibe coding es real — pero es velocidad a corto plazo. El sistema hace que la semana 3 sea igual de rápida que la semana 1, porque el contexto no se degrada. Sin sistema, la velocidad cae semana a semana conforme la deuda de contexto se acumula. Quien usa sistema tiene el mismo ritmo en el sprint 8 que en el sprint 1. Quien usa vibe coding puro, no.

    ¿Qué es lo primero que debo hacer si reconozco los síntomas?

    Crea el CLAUDE.md. Puedes tenerlo en quince minutos: descripción del proyecto, stack real con versiones, convenciones de naming que ya existen en el código (aunque estén implícitas), y las tres o cuatro restricciones que te habría gustado tener desde el principio. Ese archivo solo ya reduce la inconsistencia en las sesiones futuras. El resto del sistema puedes añadirlo gradualmente.

    ¿En qué se diferencia el vibe coding del agentic engineering?

    El vibe coding es un flujo de trabajo donde el developer describe ideas y el modelo decide cómo implementarlas. El agentic engineering es una disciplina donde el developer diseña el sistema — la spec, el contexto, los contratos, los límites — y delega la implementación de forma controlada. La diferencia no es la IA que usas sino quién toma las decisiones de diseño: tú o el modelo.


    *Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.*

  • Testing en Angular con IA: tests que protegen de verdad

    Testing en Angular con IA: tests que protegen de verdad

    Le pedí a Claude que escribiera los tests de un componente de login. Me devolvió 14 tests. Todos verdes. El CI pasó sin problema.

    Dos semanas después, un bug llegó a producción. El formulario aceptaba contraseñas vacías si el campo estaba touched pero sin valor. Ninguno de esos 14 tests lo detectó.

    Los tests no fallaron porque el bug no existía para ellos. Los tests comprobaban que el componente existía, que el formulario se renderizaba, que el método onSubmit() se llamaba. No comprobaban el comportamiento. Eran tests de que el código había sido escrito, no de que el código hacía lo correcto.

    Este es el problema número uno del testing en Angular con IA: la IA genera tests que pasan, no tests que protegen.


    El problema real de los tests generados por IA

    Cuando le das a un modelo un componente Angular y le pides “escribe los tests”, le estás pidiendo que haga ingeniería inversa de tu implementación. Y eso es exactamente lo que hace.

    Lee el código. Ve que hay un loginForm con dos controles. Ve que hay un método onSubmit(). Ve que hay un AuthService. Y escribe tests que verifican que esas cosas existen y se llaman entre sí.

    El resultado son tests acoplados a la implementación, no al comportamiento. Si renombras onSubmit() a handleSubmit(), los tests fallan. Si cambias el nombre de una variable interna, los tests fallan. Pero si introduces un bug lógico — como que el formulario se envíe con campos vacíos — los tests siguen verdes.

    Esto no es un fallo del modelo. Es un fallo del prompt. Le preguntaste lo que no debías preguntar.

    Sin contexto del comportamiento esperado, la IA no tiene forma de saber qué casos importan. No sabe cuándo debería bloquearse el submit. No sabe qué errores deben mostrarse. Así que copia lo que ve: la implementación.


    El cambio de mentalidad que lo arregla todo

    No le pidas a la IA que escriba tests. Pídele que te ayude a pensar qué testear.

    Son dos tareas completamente distintas. La primera produce código. La segunda produce criterios. Y los criterios son lo que hace que un test sea útil.

    Un test útil parte de una pregunta: “¿qué debería pasar cuando X?” No de “¿qué hace este código?”

    El flujo correcto es este:

    1. Describe el comportamiento, no el código. No copies el componente en el prompt. Describe qué hace desde fuera. Qué ve el usuario. Qué espera. Qué debe pasar si hace algo incorrecto.
    2. Pídele que liste los casos de test. Solo los casos, sin código todavía.
    3. Revisa y aprueba esa lista. Añades los que faltan. Eliminas los redundantes. Este paso es el más valioso de todo el flujo — y es el que la mayoría de devs salta.
    4. Pide el código de test para cada caso. Con Jest y Testing Library, una vez que los criterios están claros.

    Ejemplo práctico con Angular 22

    Este es el componente. Un formulario de login con Reactive Forms en Angular 22:

    // login.component.ts
    import { Component, inject, signal } from '@angular/core';
    import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
    import { Router } from '@angular/router';
    import { firstValueFrom } from 'rxjs';
    import { AuthService } from '../services/auth.service';
    
    @Component({
      selector: 'app-login',
      standalone: true,
      imports: [ReactiveFormsModule],
      template: `
        <form [formGroup]="form" (ngSubmit)="onSubmit()">
          <input formControlName="email" type="email" placeholder="Email" />
          <input formControlName="password" type="password" placeholder="Contraseña" />
          @if (errorMessage()) {
            <p class="error">{{ errorMessage() }}</p>
          }
          <button type="submit" [disabled]="form.invalid || isLoading()">
            {{ isLoading() ? 'Cargando...' : 'Entrar' }}
          </button>
        </form>
      `
    })
    export class LoginComponent {
      private fb = inject(FormBuilder);
      private auth = inject(AuthService);
      private router = inject(Router);
    
      form = this.fb.group({
        email: ['', [Validators.required, Validators.email]],
        password: ['', Validators.required]
      });
    
      errorMessage = signal('');
      isLoading = signal(false);
    
      async onSubmit() {
        if (this.form.invalid) return;
        this.isLoading.set(true);
        this.errorMessage.set('');
        try {
          await firstValueFrom(this.auth.login(this.form.value as { email: string; password: string }));
          this.router.navigate(['/dashboard']);
        } catch (err: any) {
          if (err.status === 401) {
            this.errorMessage.set('Credenciales incorrectas');
          }
        } finally {
          this.isLoading.set(false);
        }
      }
    }

    El prompt malo que genera tests inútiles:

    "Escribe los tests para este componente Angular."

    El prompt bueno, siguiendo el flujo de cuatro pasos:

    "Tengo un componente de login en Angular 22 con Reactive Forms.
    El comportamiento esperado es:
    - El botón está deshabilitado si el formulario es inválido o si está cargando
    - Al enviar credenciales válidas, se llama a AuthService.login()
    - Si AuthService lanza un error 401, se muestra 'Credenciales incorrectas'
    - Si tiene éxito, el router navega a /dashboard
    
    Lista primero los casos de test. Sin código todavía."

    Y estos son los tests resultantes con Jest y Testing Library para Angular:

    // login.component.spec.ts
    import { render, screen } from '@testing-library/angular';
    import userEvent from '@testing-library/user-event';
    import { LoginComponent } from './login.component';
    import { AuthService } from '../services/auth.service';
    import { provideRouter } from '@angular/router';
    import { of, throwError } from 'rxjs';
    
    describe('LoginComponent', () => {
      const mockAuthService = { login: jest.fn() };
    
      async function setup() {
        await render(LoginComponent, {
          providers: [
            { provide: AuthService, useValue: mockAuthService },
            provideRouter([{ path: 'dashboard', component: {} as any }])
          ]
        });
        return userEvent.setup();
      }
    
      beforeEach(() => jest.clearAllMocks());
    
      it('deshabilita el botón cuando el formulario está vacío', async () => {
        await setup();
        expect(screen.getByRole('button', { name: /entrar/i })).toBeDisabled();
      });
    
      it('deshabilita el botón con email inválido aunque haya contraseña', async () => {
        const user = await setup();
        await user.type(screen.getByPlaceholderText('Email'), 'no-es-email');
        await user.type(screen.getByPlaceholderText('Contraseña'), '123456');
        expect(screen.getByRole('button', { name: /entrar/i })).toBeDisabled();
      });
    
      it('habilita el botón con credenciales válidas', async () => {
        const user = await setup();
        await user.type(screen.getByPlaceholderText('Email'), 'user@test.com');
        await user.type(screen.getByPlaceholderText('Contraseña'), '123456');
        expect(screen.getByRole('button', { name: /entrar/i })).not.toBeDisabled();
      });
    
      it('llama a AuthService.login al hacer submit con datos válidos', async () => {
        mockAuthService.login.mockReturnValue(of({}));
        const user = await setup();
        await user.type(screen.getByPlaceholderText('Email'), 'user@test.com');
        await user.type(screen.getByPlaceholderText('Contraseña'), '123456');
        await user.click(screen.getByRole('button', { name: /entrar/i }));
        expect(mockAuthService.login).toHaveBeenCalledWith({
          email: 'user@test.com',
          password: '123456'
        });
      });
    
      it('muestra mensaje de error cuando el servicio responde 401', async () => {
        mockAuthService.login.mockReturnValue(throwError(() => ({ status: 401 })));
        const user = await setup();
        await user.type(screen.getByPlaceholderText('Email'), 'user@test.com');
        await user.type(screen.getByPlaceholderText('Contraseña'), 'wrong');
        await user.click(screen.getByRole('button', { name: /entrar/i }));
        expect(await screen.findByText('Credenciales incorrectas')).toBeInTheDocument();
      });
    });

    La clave está en userEvent.type en lugar de fireEvent.input — con Reactive Forms en Angular, solo userEvent actualiza el FormControl correctamente en el entorno de test. Y el mock usa of({}) y throwError() de RxJS porque AuthService.login() devuelve un Observable.

    Esto es exactamente el enfoque que trabajamos en el curso de Testing en Angular con Jest y Testing Library: probar comportamiento, no implementación.


    Tests de servicios con IA: qué mockear y cómo describirlo

    Los servicios son donde más fácil es equivocarse al usar IA para testing.

    El error más común: pedirle a la IA que mockee el propio servicio para testearlo. Si mockeas AuthService en el test de AuthService, estás probando el mock, no el servicio.

    Lo que debes describirle a la IA es esto:

    "Tengo un AuthService en Angular 22 que inyecta HttpClient.
    El método login() hace POST a /api/auth/login con email y password.
    Devuelve un Observable<User>. En caso de error HTTP lo relanza tal cual.
    Escribe los tests usando provideHttpClient() + provideHttpClientTesting() y HttpTestingController.
    No mockees el servicio. Mockea solo el HttpClient."

    Con ese prompt, la IA sabe exactamente qué nivel de la pila debe sustituir:

    // auth.service.spec.ts
    import { TestBed } from '@angular/core/testing';
    import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
    import { provideHttpClient } from '@angular/common/http';
    import { AuthService } from './auth.service';
    
    describe('AuthService', () => {
      let service: AuthService;
      let httpMock: HttpTestingController;
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          providers: [AuthService, provideHttpClient(), provideHttpClientTesting()]
        });
        service = TestBed.inject(AuthService);
        httpMock = TestBed.inject(HttpTestingController);
      });
    
      afterEach(() => httpMock.verify());
    
      it('hace POST a /api/auth/login con las credenciales', () => {
        const credentials = { email: 'user@test.com', password: '123456' };
        service.login(credentials).subscribe();
        const req = httpMock.expectOne('/api/auth/login');
        expect(req.request.method).toBe('POST');
        expect(req.request.body).toEqual(credentials);
        req.flush({ id: 1, email: 'user@test.com' });
      });
    
      it('devuelve el usuario cuando el servidor responde con éxito', () => {
        const mockUser = { id: 1, email: 'user@test.com' };
        let result: any;
        service.login({ email: 'user@test.com', password: '123456' })
          .subscribe(user => (result = user));
        httpMock.expectOne('/api/auth/login').flush(mockUser);
        expect(result).toEqual(mockUser);
      });
    
      it('relanza el error HTTP cuando el servidor responde 401', () => {
        let error: any;
        service.login({ email: 'user@test.com', password: 'wrong' })
          .subscribe({ error: err => (error = err) });
        httpMock.expectOne('/api/auth/login').flush(
          { message: 'Unauthorized' },
          { status: 401, statusText: 'Unauthorized' }
        );
        expect(error.status).toBe(401);
      });
    });

    La clave está en la instrucción: “mockea solo el HttpClient”. Esa precisión es lo que separa un prompt que genera tests útiles de uno que genera ruido.

    Si quieres ver cómo aplicar este patrón a servicios más complejos — con interceptores, state management y Signals — en el curso de Angular Moderno tienes la arquitectura base sobre la que todo esto encaja.


    Lo que la IA no puede hacer por ti

    La IA puede generar el código de test más rápido de lo que tú lo escribirías. No puede decirte qué casos importan en tu dominio de negocio.

    No sabe que en tu aplicación una contraseña vacía tiene un tratamiento especial. No sabe que hay un edge case cuando el usuario tiene sesión expirada y reintenta. No sabe que el botón de carga es crítico porque en producción la red va lenta y los usuarios hacen doble click.

    Ese conocimiento solo lo tienes tú. Tu trabajo es trasladarlo al prompt antes de pedir código. La IA amplifica lo que le das — si le das una descripción de comportamiento, amplifica eso. Si le das solo el código de implementación, amplifica eso.

    El flujo de cuatro pasos no es burocracia. Es el mínimo para que la IA genere tests que protejan algo.

    Si quieres llevar esta forma de trabajar más lejos — combinando especificaciones previas al código con IA para que los tests sean parte del diseño — eso es lo que construimos en el curso Construye con IA: de la Idea al Producto. Y si quieres acceso a los proyectos completos con suites de tests reales, los encontrarás en Dominicode Labs.


    FAQ

    ¿Puedo usar cualquier modelo de IA o Claude es el mejor para esto?

    El flujo de cuatro pasos funciona con cualquier modelo — Claude, GPT-4o, Gemini. La calidad del output depende mucho más de la calidad del prompt que del modelo. Dicho esto, Claude tiene ventaja en identificar casos borde cuando describes comportamientos complejos con muchas condiciones.

    ¿La IA puede generar tests TDD, es decir, antes de escribir el componente?

    Sí, y es el flujo ideal. Describes el comportamiento, pides los casos, apruebas la lista, pides el código de test — y luego le pides que implemente el componente para que esos tests pasen. Es TDD asistido por IA, y es especialmente potente para componentes nuevos.

    ¿Testing Library o Spectator para Angular?

    Testing Library porque te obliga a pensar en términos de comportamiento desde el principio. getByRole, getByPlaceholderText, findByText — todas esas queries buscan lo que el usuario ve, no lo que el código tiene internamente. Spectator facilita demasiado el acceso directo a la instancia del componente, lo que lleva a tests acoplados a implementación.

    ¿Cómo sé si un test generado por IA es bueno?

    Una heurística sencilla: introduce manualmente el bug más obvio en el componente y corre los tests. Si los tests siguen verdes, no valen nada. Por ejemplo, en el componente de login, pon if (true) return; al principio de onSubmit() — si el test de “llama a AuthService.login” sigue pasando, ese test no prueba nada. Esta técnica se llama mutation testing.

    ¿Vale la pena testear componentes de presentación puros?

    Depende de la complejidad. Un componente que solo muestra datos sin lógica condicional no necesita tests exhaustivos. Pero si tiene lógica de visualización — mostrar un badge según el estado, calcular clases CSS condicionalmente — esa lógica sí merece tests. Pregúntale a la IA: “¿qué comportamientos condicionales tiene este template que merecen ser testados?”


    *Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.*

  • MCP explicado para developers: conecta Claude a tus herramientas

    MCP explicado para developers: conecta Claude a tus herramientas

    Hace unos meses estaba trabajando con Claude Code en un proyecto con Supabase. Quería que el agente pudiese consultar la base de datos, leer el schema, revisar los registros. Lo normal cuando construyes algo de verdad.

    El problema: Claude no podía llegar a Supabase por sí solo. Necesitaba que yo le pasase el contexto a mano — copiar y pegar schema, copiar y pegar queries, copiar y pegar resultados. El LLM hacía el trabajo intelectual, pero la conexión a las herramientas era un cuello de botella manual y frustrante.

    Eso era la vida antes de MCP (Model Context Protocol).

    Hoy, con el servidor MCP de Supabase configurado en Claude Code, el agente puede leer tablas, ejecutar queries y revisar logs sin que yo mueva un dedo. La diferencia no es pequeña. Es el salto entre un asistente que responde preguntas y un agente que trabaja de verdad.


    El problema que MCP viene a resolver

    Antes de MCP, si querías conectar un LLM a una herramienta externa — GitHub, una base de datos, Slack, tu sistema de archivos — tenías que construir esa integración desde cero para cada caso.

    Cada proveedor de LLM tenía su forma de hacer “function calling”. OpenAI tenía la suya. Anthropic tenía la suya. Google tenía la suya. Y cada herramienta que querías conectar necesitaba código custom adaptado a ese proveedor específico.

    El resultado: ecosistemas fragmentados. Integraciones que había que reescribir al cambiar de modelo. Código duplicado en cada proyecto. Y una fricción enorme para cualquier developer que quisiese construir algo más allá del chat básico.

    MCP es la respuesta a ese problema. Un protocolo único, abierto y estandarizado para que cualquier LLM se comunique con cualquier herramienta. Escribe el servidor una vez. Funciona con cualquier cliente compatible.


    Qué es MCP exactamente

    Model Context Protocol es un protocolo abierto — especificación pública, SDK con licencia MIT — creado por Anthropic en noviembre de 2024 y adoptado por la industria. Define cómo los LLMs se comunican con herramientas y fuentes de datos externas.

    La arquitectura tiene dos piezas:

    1. Cliente MCP — la aplicación host que aloja al LLM (Claude Code, Claude Desktop). Es quien inicia la conexión, gestiona qué servidores están disponibles y enruta las llamadas del modelo a las herramientas.
    2. Servidor MCP — el servicio que expone las herramientas. Puede ser Supabase, GitHub, tu sistema de archivos, Notion, Slack, o cualquier cosa que hayas construido tú mismo.

    El flujo de una interacción con MCP es el siguiente:

    1. El usuario hace una petición a Claude: “¿Cuántos usuarios se registraron esta semana?”
    2. Claude detecta que necesita datos de la base de datos.
    3. La aplicación host enruta la llamada al servidor MCP de Supabase.
    4. El servidor ejecuta la query y devuelve los resultados.
    5. Claude recibe la respuesta y continúa la conversación con datos reales.

    Todo esto ocurre dentro de la misma sesión, de forma transparente para el usuario. La especificación completa del protocolo está disponible en modelcontextprotocol.io, mantenida como estándar abierto.


    MCP vs Function Calling: la diferencia que importa

    Si llevas tiempo trabajando con LLMs probablemente conoces el concepto de function calling — la capacidad de un modelo de invocar funciones definidas por el developer.

    La confusión es comprensible. MCP y function calling resuelven el mismo problema superficialmente. Pero hay una diferencia fundamental:

    Criterio Function Calling MCP
    Compatibilidad Propietario por proveedor Protocolo abierto
    Portabilidad Reescribir al cambiar de modelo Un servidor, cualquier cliente
    Mantenimiento Código duplicado por proveedor Único punto de actualización
    Adopción Fragmentada Claude Code, Cursor y más

    Function calling es propietario. La especificación de cómo defines una función para OpenAI no es la misma que para Anthropic. Si cambias de modelo, reescribes las integraciones.

    MCP es el estándar universal. El servidor MCP que escribas hoy para conectar Claude a tu base de datos funciona también con cualquier otro cliente MCP que aparezca mañana. El servidor no sabe ni le importa qué LLM hay al otro lado.

    Es la diferencia entre construir sobre propietario y construir sobre estándar. La misma diferencia que existe entre HTTP y el protocolo interno de un servicio concreto.

    Si estás construyendo herramientas que los LLMs van a usar en producción, MCP es la apuesta correcta. Es la razón por la que en el curso Construye con IA trabajamos con MCP desde el principio — no porque sea lo más nuevo, sino porque es lo que tiene sentido en un stack real.


    Casos de uso reales para developers

    Supabase MCP. Claude puede leer el schema de tu base de datos, ejecutar queries, revisar los logs de error, inspeccionar las políticas RLS. Cuando estás debuggeando un problema en producción, tener al agente con acceso directo a la base de datos no es un lujo — es lo que separa minutos de horas.

    GitHub MCP. Claude puede leer Pull Requests, crear issues, revisar el historial de commits, comentar en code reviews. Si trabajas en un equipo o gestionas un proyecto open source, esto te cambia el flujo de trabajo.

    Filesystem MCP. Claude puede leer y escribir archivos en tu proyecto directamente. Esto es lo que usa Claude Code por defecto — el acceso al sistema de archivos es un servidor MCP. Cuando le dices a Claude “edita este archivo”, hay un servidor MCP detrás gestionando esa operación.

    Notion o Confluence MCP. Claude puede leer tu documentación, buscar en tus notas, actualizar páginas. Útil si tienes tu spec o tus decisiones de arquitectura en Notion y quieres que el agente las tenga en contexto sin tener que copiarlas manualmente.

    Slack MCP. Claude puede leer canales, buscar mensajes, enviar notificaciones. Si construyes pipelines de automatización, esto es la pieza que conecta el agente con tu equipo.

    El patrón es siempre el mismo: en lugar de que tú seas el intermediario entre el LLM y la herramienta, el protocolo gestiona esa conexión. Tu rol pasa de “copy-paste operator” a alguien que define qué herramientas el agente puede usar y con qué permisos.


    Cómo configurar un servidor MCP en Claude Code

    La parte práctica. Hay dos formas de configurar servidores MCP en Claude Code:

    Opción 1 — Configuración global (claudedesktopconfig.json) Esta configuración aplica a todas tus sesiones de Claude Code. El archivo vive en:

    • macOS: ~/Library/Application Support/Claude/claudedesktopconfig.json
    • Windows: %APPDATA%\Claude\claudedesktopconfig.json

    Opción 2 — Configuración por proyecto (.mcp.json) Un archivo .mcp.json en la raíz de tu proyecto. Solo aplica a ese proyecto. Es la opción que recomiendo — el contexto de las herramientas debe ser específico al proyecto, no global.

    Ejemplo práctico: MCP de filesystem

    {
      "mcpServers": {
        "filesystem": {
          "command": "npx",
          "args": [
            "-y",
            "@modelcontextprotocol/server-filesystem",
            "/Users/bezael/projects/mi-proyecto"
          ]
        }
      }
    }

    Con esto configurado, Claude puede leer y modificar archivos dentro de la ruta que especifiques. No tiene acceso a nada fuera de ese directorio — los permisos los defines tú.

    Ejemplo: MCP de Supabase

    {
      "mcpServers": {
        "supabase": {
          "command": "npx",
          "args": ["-y", "@supabase/mcp-server-supabase@latest"],
          "env": {
            "SUPABASE_URL": "https://tu-proyecto.supabase.co",
            "SUPABASE_SERVICE_ROLE_KEY": "tu-service-role-key"
          }
        }
      }
    }

    Una vez que reinicias Claude Code con esta configuración, el agente tiene acceso a tu base de datos. Puedes pedirle que revise el schema, que ejecute una query, que busque errores en los logs.

    Qué ocurre cuando Claude usa una herramienta MCP

    Por defecto, Claude Code te muestra cada llamada MCP antes de ejecutarla. Verás algo como:

    Tool call: filesystem.read_file
    Arguments: { "path": "/src/components/UserCard.tsx" }

    Puedes aprobarla, rechazarla o configurar permisos permanentes por servidor. El flujo de trabajo es transparente — no hay caja negra.

    Esto conecta directamente con lo que explico en el post sobre Context Engineering para proyectos de IA: el contexto que tiene el agente determina la calidad de sus decisiones. MCP es una de las palancas más directas para darle al agente contexto real, no simulado.


    El ecosistema MCP hoy

    La adopción ha sido rápida. Hoy existen servidores MCP oficiales o comunitarios para:

    • Supabase, PostgreSQL, SQLite
    • GitHub, GitLab, Linear
    • Notion, Confluence, Obsidian
    • Slack, Discord
    • AWS, Google Cloud
    • Playwright (para automatizar navegadores)
    • Docker
    • Y decenas más

    El registro de servidores MCP crece cada semana. Si la herramienta que necesitas no tiene servidor MCP todavía, puedes construir el tuyo — el SDK oficial de Anthropic para TypeScript y Python hace que crear un servidor MCP básico sea trabajo de pocas horas.


    Por dónde empezar hoy

    Si nunca has configurado un servidor MCP, el camino más corto es este:

    1. Abre Claude Code en un proyecto real tuyo.
    2. Crea un archivo .mcp.json en la raíz con el servidor de filesystem apuntando a tu directorio de trabajo.
    3. Reinicia Claude Code.
    4. Pídele que liste los archivos del proyecto, que lea un componente específico, que analice la estructura.

    No necesitas construir nada. Solo configurar. En menos de 10 minutos tienes un agente que trabaja con el contexto real de tu proyecto en lugar de con lo que tú le describes.

    Si todavía no tienes configurado el contexto base de tu proyecto, el post sobre cómo estructurar tu CLAUDE.md es el punto de partida — MCP y CLAUDE.md son complementarios, no alternativos.

    El siguiente paso natural es conectar tu base de datos si usas Supabase, o GitHub si gestionas un repositorio con actividad. Cada servidor MCP que añades amplía lo que el agente puede hacer sin intervención tuya.

    Y si quieres entender la arquitectura completa — no solo el protocolo MCP sino todo el sistema que lo rodea, de la spec al producto funcionando — eso es exactamente lo que cubrimos en el curso Construye con IA. Si quieres explorar esto con otros developers y ver proyectos reales con MCP en acción, en Dominicode Labs revisamos este tipo de proyectos regularmente.


    FAQ

    ¿MCP es solo para Claude o funciona con otros LLMs?

    MCP es un protocolo abierto — no es propietario de Anthropic en el sentido de que solo funcione con Claude. Otros clientes MCP compatibles pueden usar los mismos servidores. La apuesta de Anthropic fue precisamente crear un estándar que la industria pudiese adoptar, no una ventaja competitiva cerrada. Hoy el ecosistema está centrado en Claude Code y Claude Desktop, pero la adopción por parte de otros clientes está creciendo.

    ¿Es seguro darle acceso a Claude a mi base de datos o sistema de archivos?

    Depende de cómo lo configures. El servidor MCP de filesystem solo puede acceder a las rutas que tú especifiques — no tiene acceso a toda tu máquina. Con Supabase, usas la service role key, que tiene permisos amplios, por lo que hay que ser cuidadoso con qué operaciones permites. Por defecto Claude Code te muestra cada llamada MCP antes de ejecutarla. La regla general: mínimo privilegio — dale al servidor MCP exactamente los permisos que necesita, no más.

    ¿Necesito saber TypeScript o Python para usar MCP?

    Para usar servidores MCP existentes, no. Solo necesitas editar un archivo JSON de configuración y tener Node.js instalado (para los servidores que usan npx). Para construir tu propio servidor MCP, el SDK oficial de Anthropic está disponible en TypeScript y Python, y el punto de partida es sencillo — un servidor básico son menos de 50 líneas.

    ¿Cuál es la diferencia entre MCP y un plugin de ChatGPT?

    Los plugins de ChatGPT fueron un intento propietario de conectar LLMs a herramientas externas, y OpenAI los deprecó en 2024. MCP es un protocolo abierto, no una feature de un producto específico. La diferencia práctica: un servidor MCP que construyas hoy puede ser usado por cualquier cliente MCP compatible mañana. Un plugin de ChatGPT solo funcionaba con ChatGPT, con las restricciones y cambios que OpenAI decidiera unilateralmente.

    ¿MCP reemplaza completamente el function calling tradicional?

    No exactamente. Function calling sigue siendo el mecanismo subyacente — MCP lo usa internamente. Lo que MCP añade es la capa de estandarización: define cómo se describen las herramientas, cómo se comunica el cliente con el servidor, cómo se gestionan los errores. Es más una capa de protocolo sobre function calling que un reemplazo.


    *Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.*

  • Context Engineering: proyectos con IA sin perder el hilo

    Context Engineering: proyectos con IA sin perder el hilo

    La primera vez que me pasó, pensé que era un fallo del modelo.

    Llevaba tres días construyendo una API con Claude Code. Arquitectura decidida, endpoints definidos, estructura de carpetas lista. Todo tenía sentido. Abrí una sesión nueva al cuarto día y le pedí que añadiera autenticación al módulo de usuarios.

    Me devolvió código que contradecía las decisiones que habíamos tomado el día anterior. Naming diferente. Patrón de errores distinto. Como si hubiera arrancado desde cero.

    No era un fallo del modelo. Era un fallo mío. No le había dado context engineering. Le había dado prompts.

    Lo que me faltaba tiene nombre. Y no es lo mismo que prompt engineering.


    El problema real: el modelo no sabe qué decidiste ayer

    Los LLMs no tienen memoria entre sesiones. Cada conversación nueva es, literalmente, una pizarra en blanco.

    Dentro de una misma sesión tienen una ventana de contexto — los modelos actuales manejan ventanas de entre 128k tokens (GPT-4o) y 200k tokens (Claude 3.5/3.7), cifras de junio 2026 que seguirán creciendo — pero esa ventana se llena. Y cuando se llena, el modelo empieza a “olvidar” las partes más antiguas de la conversación. Las decisiones de arquitectura que tomaste al principio. Las convenciones de naming que acordaste. El motivo por el que descartaste la opción B.

    El resultado es predecible: inconsistencia. Código que contradice decisiones previas. Respuestas que suenan razonables pero no encajan con el proyecto real. Y tú volviendo a explicar, sesión tras sesión, qué estás construyendo y cómo.

    Cualquier developer que haya usado IA durante más de dos semanas en un proyecto real lo ha vivido. La inconsistencia entre sesiones es la fricción número uno.


    Context engineering no es prompt engineering

    Mucha gente confunde los dos. No son lo mismo.

    Prompt engineering trata una sola interacción. Cómo formular la pregunta. Qué ejemplos incluir. Qué rol asignarle al modelo. Es útil, pero es táctica de un solo turno.

    Context engineering es la disciplina de estructurar y gestionar toda la información que recibe el modelo para que produzca resultados consistentes a lo largo de un proyecto completo. No en un prompt. En semanas de trabajo.

    La diferencia es la misma que hay entre saber hacer una buena pregunta en una entrevista y saber gestionar a un equipo durante un sprint.

    Prompt Engineering Context Engineering
    Alcance Un turno de conversación Un proyecto completo
    Problema que resuelve Calidad de una respuesta Consistencia entre sesiones
    Habilidad principal Redactar instrucciones claras Diseñar sistemas de información
    Cuándo falla Respuesta ambigua o incorrecta Proyecto incoherente en semana 3
    Herramienta clave El prompt en sí CLAUDE.md, specs, logs de decisiones

    Puedes ser un maestro del prompt engineering y aun así tener un proyecto que se rompe cada semana. El context engineering es lo que lo sostiene.


    Las 4 técnicas que uso en producción

    1. CLAUDE.md / AGENTS.md — la memoria persistente del proyecto

    Este es el punto de partida. Un archivo en la raíz del proyecto que le dice al modelo, al inicio de cada sesión, quién eres, qué estás construyendo y cómo trabajas.

    No es un README. Es un system prompt que el modelo lee antes de hacer nada.

    Lo mínimo que debe tener:

    • Descripción del proyecto en 2-3 líneas (qué es, para quién)
    • Stack técnico con versiones concretas
    • Convenciones de código que no se negocian
    • Lo que NO debe hacer el modelo (igual de importante)
    • Estado actual del proyecto — en qué fase estás

    Un ejemplo mínimo que uso en proyectos reales:

    # CLAUDE.md — API de Usuarios
    
    ## Proyecto
    API REST de gestión de usuarios para SaaS B2B.
    Stack: NestJS 10 + PostgreSQL + Prisma 5.
    
    ## Convenciones
    - Naming: camelCase para variables, PascalCase para clases, kebab-case para archivos
    - Errores: siempre usar HttpException con código y mensaje estructurado
    - No usar `any` en TypeScript — tipos explícitos o `unknown`
    
    ## NO hacer
    - No generar migraciones de Prisma automáticamente — las revisamos manualmente
    - No cambiar el schema sin actualizar architecture.md
    
    ## Estado actual
    Fase 2 — módulo de autenticación JWT. Ver tasks.md para detalle.
    

    Si usas Claude Code, este archivo es CLAUDE.md. Si usas Cursor o Windsurf, es __INLINE_PLACEHOLDER_0__ o __INLINE_PLACEHOLDER_1__ (__INLINE_PLACEHOLDER_2__ sigue siendo compatible pero es el formato legacy de Cursor). El nombre cambia. El concepto es el mismo.

    Ya escribí un post completo sobre cómo estructurar este archivo: CLAUDE.md: el system prompt de tu proyecto con Claude Code. Si no lo has leído, empieza por ahí.

    2. Archivos de estado — lo que el modelo no puede inferir

    El CLAUDE.md da el contexto estático: qué es el proyecto y cómo funciona. Pero los proyectos evolucionan. Necesitas capturar el estado dinámico.

    Yo mantengo tres archivos en cada proyecto:

    __INLINE_PLACEHOLDER_3__ — lista de tareas con estado (pendiente / en progreso / hecho). Una línea por tarea, fecha de última actualización. El modelo la lee y sabe exactamente dónde estás.

    __INLINE_PLACEHOLDER_4__ — log de decisiones arquitectónicas. Cada decisión con su fecha, la opción elegida y el motivo por el que se descartó la alternativa. Este archivo vale oro cuando vuelves a un proyecto tres semanas después.

    __INLINE_PLACEHOLDER_5__ — snapshot de la arquitectura actual. No el diagrama ideal. El diagrama real, con los módulos que existen ahora mismo. El modelo lo usa para no proponer soluciones que contradigan lo ya construido.

    Tres archivos. Ninguno supera las dos páginas. Pero juntos eliminan el 80% de la inconsistencia.

    3. Chunking de tareas — no pidas todo en un prompt

    Este error lo cometo yo también cuando tengo prisa.

    “Implementa el sistema de autenticación completo con JWT, refresh tokens, roles y middleware de autorización.”

    El modelo lo intenta. Genera código. Pero es código que asume cosas sobre tu proyecto que no conoce, o que contradice la arquitectura que ya tienes. Y cuando algo falla, el problema está distribuido en 400 líneas de código que no entiendes del todo.

    La regla que aplico: una tarea por sesión, una función por tarea.

    En lugar de pedir la autenticación completa, pido:

    1. Primero: el módulo de usuarios con su schema y validaciones
    2. Luego: la generación de JWT con los claims que necesito
    3. Luego: el endpoint de login que conecta ambos
    4. Luego: el middleware que verifica el token

    Cuatro sesiones. Cuatro archivos de contexto actualizados al final de cada una. Un sistema que entiendo porque lo construí pieza a pieza.

    El modelo produce mejor código cuando el scope es pequeño y el contexto es preciso. En la práctica, siempre.

    4. Resúmenes de sesión — el handoff entre el tú de hoy y el tú de mañana

    Al final de cada sesión de trabajo, antes de cerrar, escribo este prompt:

    “Resume lo que hemos hecho en esta sesión en 5-7 puntos: qué se implementó, qué decisiones se tomaron, qué problemas encontramos y qué queda pendiente para la siguiente.”

    Copio esa respuesta en un archivo __INLINE_PLACEHOLDER_6__ con la fecha.

    Cuando vuelvo al proyecto al día siguiente, la primera cosa que hago es darle ese log al modelo junto con el CLAUDE.md. El modelo arranca con el contexto exacto de donde lo dejé. Sin tener que re-explicar. Sin inconsistencias.

    Diez minutos al final de cada sesión que ahorran una hora al principio de la siguiente.


    Ejemplo práctico: un proyecto de tres semanas sin perder el hilo

    Semana 1 — Cimentar el contexto

    Antes de escribir una línea de código, genero la spec del proyecto con Spec-Driven Development: visión, usuarios, funcionalidades, arquitectura. Ese documento se convierte en la base del CLAUDE.md.

    Creo los tres archivos de estado vacíos: __INLINE_PLACEHOLDER_7__, __INLINE_PLACEHOLDER_8__, __INLINE_PLACEHOLDER_9__. El modelo los actualiza conforme avanzamos.

    Semana 2 — Construcción en chunks

    Cada sesión tiene una tarea concreta de __INLINE_PLACEHOLDER_10__. Arranca con el CLAUDE.md, el archivo de arquitectura y el log de la sesión anterior. Termina con el modelo actualizando el estado de la tarea y generando el resumen de sesión.

    Semana 3 — Cuando todo se complica

    En la semana 3 es cuando los proyectos sin sistema se rompen. El código empieza a contradecirse. Las decisiones del día 1 ya nadie las recuerda. Las nuevas funcionalidades no encajan con lo que ya existe.

    Con context engineering, la semana 3 es igual de fluida que la semana 1. Porque el modelo tiene, en cada sesión, el mismo nivel de contexto que tenías tú el primer día. El __INLINE_PLACEHOLDER_11__ le dice por qué tomaste las decisiones que tomaste. El __INLINE_PLACEHOLDER_12__ le muestra la estructura real. El log de sesión le dice dónde lo dejaste.

    No es magia. Es sistema.


    Lo que cambia cuando aplicas esto

    La diferencia no es velocidad. Es consistencia.

    Un developer sin context engineering puede ir rápido la primera semana. Pero en la semana 3, la deuda de contexto empieza a pasarle factura. Cada sesión nueva cuesta más porque hay que re-explicar más. Cada funcionalidad nueva tiene más probabilidad de romperse con algo anterior.

    Un developer con context engineering mantiene el mismo ritmo en la semana 8 que en la semana 1. Porque el contexto no es algo que se pierde — es algo que se gestiona.

    Esta es exactamente la mentalidad que enseño en el curso Construye con IA: de la idea al producto con Claude Code. No “cómo usar Claude”. Cómo construir con sistema.


    FAQ

    ¿El context engineering solo funciona con Claude Code?

    No. Los principios aplican a cualquier LLM y cualquier herramienta — Cursor, Windsurf, ChatGPT, Gemini. El CLAUDE.md tiene su equivalente en cada entorno: __INLINE_PLACEHOLDER_13__, __INLINE_PLACEHOLDER_14__, un system prompt inicial. La técnica de chunking y los resúmenes de sesión son agnósticos al modelo.

    ¿Cuánto tiempo añade a mi flujo de trabajo?

    En la práctica, entre 10 y 20 minutos al día. Cinco minutos actualizando el __INLINE_PLACEHOLDER_15__, diez minutos pidiendo y guardando el resumen de sesión. El retorno es que ahorras una o dos horas semanales de re-explicar contexto y corregir inconsistencias. La matemática es clara.

    ¿Necesito crear estos archivos manualmente desde cero?

    Puedes empezar con plantillas. En el curso Construye con IA incluyo las plantillas exactas de CLAUDE.md, __INLINE_PLACEHOLDER_16__ y __INLINE_PLACEHOLDER_17__ que uso en mis proyectos reales. Y si quieres la metodología de especificación completa, el libro SDD cubre el proceso de principio a fin.

    ¿Context engineering resuelve el problema de la ventana de contexto?

    Parcialmente. No puedes ampliar la ventana de contexto del modelo — eso lo determina el proveedor. Lo que puedes hacer es gestionar qué información entra en esa ventana en cada sesión. Context engineering te da control sobre eso: qué es esencial que el modelo sepa, qué puede inferir y qué no necesita en ese momento concreto. No elimina la limitación. La hace manejable.

    ¿Cuál es la diferencia entre context engineering y RAG?

    RAG (Retrieval-Augmented Generation) es una arquitectura técnica para recuperar información de fuentes externas y añadirla al contexto del modelo en tiempo de ejecución. Context engineering es una disciplina de trabajo que aplicas como developer para gestionar el contexto a lo largo de un proyecto. Son complementarios, no equivalentes. RAG es una herramienta. Context engineering es el sistema que decide qué información recuperar, cuándo y por qué.


    Si quieres profundizar en cómo aplicar estas técnicas con proyectos reales y ver el flujo en acción, en Dominicode Labs tenemos sesiones prácticas donde trabajamos esto con proyectos concretos de la comunidad.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Stack IA agéntica en 2026: qué usar, qué ignorar y cuál elijo

    Stack IA agéntica en 2026: qué usar, qué ignorar y cuál elijo

    El problema no es que falten herramientas para construir agentes de IA. Es que sobran.

    Hace unos meses, en una sesión de Dominicode Labs, me preguntaron cuál era el stack IA agéntica 2026 que recomendaba. Empecé a responder y me di cuenta de que tenía una respuesta para cada capa — pero no tenía una respuesta integrada. Llevo varios proyectos agénticos en producción en Dominicode y cada semana aparece un nuevo framework, un nuevo modelo, un nuevo “estándar imprescindible”.

    Qué modelo. Qué framework de orquestación. Qué hacer con la memoria. Cómo trazar lo que hace el agente. Dónde desplegarlo. Cada capa tiene sus propias opciones, sus propias compensaciones y su propio ecosistema de hype que no para de generar nuevas herramientas.

    Este post es mi respuesta integrada: el stack que yo uso, por qué elegí cada pieza y qué descarto con criterio. No es una lista de todas las herramientas que existen. Es una guía con tesis clara sobre qué funciona en producción cuando construyes con TypeScript, para un proyecto real, sin un equipo de 20 personas.


    Cómo pensar en el stack agéntico: capas, no herramientas

    Antes de hablar de herramientas específicas, el marco que uso para evaluar cualquier stack agéntico. Hay cinco capas y cada una resuelve un problema diferente:

    1. Modelo — el LLM que razona y toma decisiones
    2. Framework de agente — el runtime que envuelve el agentic loop
    3. Memoria y contexto — dónde vive la información entre sesiones y entre agentes
    4. Observabilidad — cómo ves qué está haciendo el agente
    5. Deployment — dónde corre el sistema en producción

    La mayoría de los posts sobre herramientas de IA mezclan estas capas y crean confusión. LangChain no compite con Claude — compite con el SDK de Anthropic. Langfuse no compite con Pinecone — resuelven problemas en capas completamente distintas.

    Cuando tienes claro qué capa resuelve cada herramienta, la decisión se vuelve mucho más simple. Si no tienes claro aún qué es el agentic loop y cómo funciona, empieza por aquí antes de elegir el stack.


    Capa 1: El modelo — quién razona

    La decisión más importante del stack y la que más gente toma al revés: eligen el modelo por el benchmark, no por el comportamiento en producción con herramientas.

    Los benchmarks de razonamiento abstracto no predicen bien si un modelo va a gestionar correctamente el agentic loop: respetar los límites de las herramientas, detectar cuándo ha completado el objetivo, no inventarse argumentos para las tool calls, pedir confirmación cuando tiene ambigüedad.

    Mi ranking para sistemas agénticos en 2026, basado en uso real:

    Claude Sonnet (Anthropic) — mi elección principal. La familia Claude 4.x lidera en comportamiento agéntico: sigue instrucciones complejas del sistema prompt con más fidelidad que los competidores, gestiona bien contextos de 200k tokens, y tiene el menor índice de “tool hallucination” — inventarse argumentos para herramientas que no existen o llamar a herramientas con parámetros incorrectos. Para proyectos donde el agente tiene acceso a herramientas reales con consecuencias (escritura a disco, llamadas a APIs, base de datos), esta fidelidad importa.

    Gemini 2.5 Pro (Google) — segunda opción para tareas de análisis. Tiene una ventana de contexto de 1M tokens que es genuinamente útil cuando el agente necesita procesar documentos grandes. El razonamiento es sólido. La API tiene más latencia que Anthropic en llamadas con herramientas. Lo uso puntualmente para tareas de análisis de documentos extensos, no como backbone de un sistema agéntico.

    GPT-4o (OpenAI) — bueno, pero no es mi primera elección para agentes. Excelente en tareas de generación pura. En agentic loops de más de 15 iteraciones, he visto más context drift que con Claude. Para proyectos que ya tienen infraestructura en el ecosistema OpenAI, es perfectamente válido.

    Llama 3.x local (Meta) — para casos específicos, no como base. Los modelos locales tienen su lugar: privacidad total, sin costos por token, sin latencia de red. Pero para sistemas agénticos complejos, la diferencia en calidad de razonamiento con los modelos de frontera es demasiado grande hoy. Los uso para tareas de clasificación simple o cuando los datos no pueden salir del entorno.

    La conclusión práctica: empieza con Claude Sonnet. Si los costos escalan y la tarea lo permite, evalúa migrar partes del sistema a modelos más baratos para subtareas que no requieren razonamiento complejo.


    Capa 2: El framework de agente — quién orquesta el loop

    Aquí está la decisión que más polémica genera, porque hay muchas opciones y cada una tiene su comunidad apasionada.

    Mi posición es clara: el framework que elijas debería desaparecer de tu código. Si tu lógica de negocio está mezclada con abstracciones del framework, tienes un problema de arquitectura, no de elección de herramienta.

    Vercel AI SDK — mi elección para TypeScript

    Para proyectos TypeScript, el Vercel AI SDK es el estándar más sólido hoy. Tiene tres propiedades que importan:

    Primero, la abstracción es mínima. generateText, streamText, generateObject — funciones que hacen lo que dicen, con un tipo de retorno predecible. Puedes leer el código del SDK y entender qué ocurre.

    Segundo, es agnóstico al proveedor. El mismo código funciona con Claude, GPT-4o y Gemini. Cambias el adaptador, no la lógica. En un año donde los modelos evolucionan rápido, esto no es un detalle menor.

    Tercero, tiene soporte nativo para tool use, streaming de respuestas y generateObject con schemas Zod — lo que significa que puedes hacer que el modelo devuelva JSON tipado sin analizadores de texto frágiles.

    import { generateText } from "ai";
    import { anthropic } from "@ai-sdk/anthropic";
    import { z } from "zod";
    
    

    const result = await generateText({ model: anthropic("claude-sonnet-4-6"), // verifica el modelo vigente en docs.anthropic.com/models tools: { readFile: { description: "Lee el contenido de un archivo del proyecto", parameters: z.object({ path: z.string() }), execute: async ({ path }) => fs.readFile(path, "utf-8"), }, }, messages: [{ role: "user", content: userQuery }], maxSteps: 15, // límite de iteraciones del loop });

    El parámetro maxSteps es el límite de iteraciones del agentic loop. No lo omitas nunca. Un agente sin límite de pasos en producción es un bug esperando a ocurrir.

    LangGraph — cuando necesitas flujos con estado y ramificaciones

    LangGraph (de LangChain) resuelve un problema diferente: orquestación de flujos donde el camino de ejecución no es lineal. Si tienes un sistema donde el agente puede ir por diferentes ramas según el resultado de un paso anterior, donde necesitas estado persistente entre sesiones, o donde hay handoffs entre múltiples agentes con condiciones complejas — LangGraph tiene primitivas para eso.

    No es mi primera elección para proyectos simples porque añade complejidad conceptual. Pero para sistemas multi-agente con lógica de routing elaborada, es genuinamente más potente que construir esa lógica a mano.

    SDK de Anthropic directo — para control total

    Cuando necesito control máximo sobre cada llamada a la API, uso el SDK de Anthropic directamente. Sin abstracciones intermedias. El agentic loop lo implemento yo, con la lógica exacta que necesito.

    Esto es lo que haría si estuviera construyendo el loop desde cero con el SDK directo — el mismo patrón que cubro en detalle en el curso Construye con IA:

    import Anthropic from "@anthropic-ai/sdk";
    
    

    const client = new Anthropic();

    async function runAgentLoop(userMessage: string, tools: Tool[]) { const messages: Anthropic.MessageParam[] = [ { role: "user", content: userMessage }, ];

    let iterations = 0; const maxIterations = 20;

    while (iterations < maxIterations) { const response = await client.messages.create({ model: "claude-sonnet-4-6", // verifica en docs.anthropic.com/models max_tokens: 4096, tools, messages, });

    // Si el modelo no llama a ninguna herramienta, ha terminado if (response.stop_reason === "end_turn") { return extractTextResponse(response); }

    // Procesa las tool calls y añade los resultados al contexto const toolResults = await executeToolCalls(response.content); messages.push({ role: "assistant", content: response.content }); messages.push({ role: "user", content: toolResults });

    iterations++; }

    throw new Error(Agente excedió el límite de ${maxIterations} iteraciones); }

    Lo que no uso: CrewAI, AutoGen, AgentGPT ni la mayoría de frameworks Python-first para proyectos TypeScript. No porque sean malos — CrewAI tiene ideas interesantes sobre roles y colaboración entre agentes — sino porque añadir Python al stack cuando ya tienes TypeScript es complejidad operacional que no se justifica en la mayoría de casos. Si tu equipo es Python, la ecuación cambia.


    Capa 3: MCP — el protocolo que está cambiando todo

    El Model Context Protocol (MCP) merece su propio apartado porque no es un framework de agentes. Es un estándar de comunicación — el equivalente a REST para que los agentes consuman herramientas y contexto de fuentes externas de forma estandarizada.

    Antes de MCP, cada herramienta que querías darle a un agente requería código de integración específico. Con MCP, una herramienta bien construida se puede conectar a cualquier agente que soporte el protocolo — Claude Code, Cursor, tu propio agente custom.

    Las implicaciones son grandes: en lugar de construir integraciones punto a punto, construyes servidores MCP reutilizables. Ya existe un ecosistema de servidores MCP públicos para GitHub, bases de datos, sistemas de archivos, APIs populares.

    // Un servidor MCP mínimo con el SDK oficial
    import { Server } from "@modelcontextprotocol/sdk/server/index.js";
    import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
    import { ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
    
    

    const server = new Server( { name: "dominicode-tools", version: "1.0.0" }, { capabilities: { tools: {} } } );

    server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: "get_post_metrics", description: "Obtiene métricas de un post del blog por slug", inputSchema: { type: "object", properties: { slug: { type: "string" } }, required: ["slug"], }, }, ], }));

    const transport = new StdioServerTransport(); await server.connect(transport);

    En 2026, si construyes herramientas para agentes y no las expones como servidores MCP, estás construyendo para un solo cliente. El ecosistema ya se está moviendo en esta dirección — Anthropic, OpenAI, Google y la mayoría de los frameworks de agentes tienen soporte nativo para MCP.


    Capa 4: Memoria y contexto persistente

    El problema de la memoria en agentes agénticos tiene tres dimensiones distintas y cada una necesita una solución diferente.

    Memoria conversacional (corto plazo) — el historial de mensajes de la sesión actual. La gestión correcta es mantenerlo en el contexto de la llamada al LLM. El truco está en la truncación inteligente: cuando el contexto se acerca al límite, no cortes los mensajes más antiguos a ciegas — resume las iteraciones antiguas y mantén los más recientes completos.

    Memoria semántica (búsqueda por similaridad) — para cuando el agente necesita recuperar información relevante de una base de conocimiento grande. Las opciones que uso:

    • pgvector — extensión de PostgreSQL. Si ya tienes Postgres en el stack (y probablemente lo tienes), añadir pgvector es añadir una extensión. No necesitas otra base de datos. Para la mayoría de proyectos con menos de diez millones de embeddings, pgvector es suficiente y elimina complejidad operacional.
    • Pinecone — la opción gestionada cuando el volumen es grande o quieres zero-ops. Más caro, más simple. Para proyectos en fases tempranas con presupuesto ajustado, pgvector primero.
    • Supabase pgvector — pgvector sobre Supabase. La que uso en proyectos nuevos porque ya tengo Supabase en el stack para auth y database.

    Memoria episódica (estado entre sesiones) — lo que el agente recuerda de sesiones anteriores con un usuario específico. Esto no es búsqueda vectorial: es estado estructurado que guardas en una tabla normal. El patrón que funciona es guardar un JSON con los hechos relevantes del usuario o proyecto y cargarlo al inicio de cada sesión como parte del system prompt.

    // Carga el estado de memoria al inicio de la sesión
    async function buildSystemPromptWithMemory(userId: string): Promise<string> {
      const memory = await db.query<UserMemory>(
        "SELECT facts FROM agent_memory WHERE user_id = $1",
        [userId]
      );
    
    

    const memoryContext = memory.rows[0]?.facts ? \n\nContexto previo del usuario:\n${JSON.stringify(memory.rows[0].facts, null, 2)} : "";

    return Eres un asistente técnico de Dominicode.${memoryContext}; }


    Capa 5: Observabilidad — ver lo que hace el agente

    Sin observabilidad, un agente en producción es una caja negra que factura. Ya hay un post completo en este blog sobre cómo instrumentar tus agentes con Langfuse y OpenTelemetry, así que aquí voy directo a las decisiones de stack:

    Langfuse — la elección por defecto. Open source, autohospedable, SDK para TypeScript con integración nativa en el Vercel AI SDK. Con un experimental_telemetry en la llamada tienes trazas completas:

    const result = await generateText({
      model: anthropic("claude-sonnet-4-6"), // verifica el modelo vigente en docs.anthropic.com/models
      messages,
      tools,
      experimental_telemetry: { // en Vercel AI SDK v4+ puede ser telemetry sin el prefijo
        isEnabled: true,
        metadata: { userId, sessionId, operationType: "support-agent" },
      },
    });

    OpenTelemetry GenAI — si ya tienes infraestructura OTEL en la empresa, las semantic conventions para IA generativa te permiten integrar las trazas de tus agentes en Grafana, Datadog o Honeycomb sin añadir otra plataforma.

    Helicone — proxy sin código si necesitas observabilidad inmediata sin instrumentar. Un cambio de base URL y tienes dashboards. Útil para proyectos donde no puedes tocar el código de integración.


    Capa 6: Deployment — dónde vive el agente en producción

    Las opciones razonables en 2026, con criterio claro sobre cuándo usar cada una:

    Railway — mi primera opción para agentes con estado o procesos de larga duración. Soporta WebSockets, procesos persistentes y tiene buena DX con Docker. Para agentes que necesitan mantener conexiones abiertas o procesar en background, Railway es más natural que Vercel.

    Vercel — ideal para agentes stateless que responden a webhooks o peticiones HTTP. La integración con el Vercel AI SDK es perfecta — maxDuration hasta 300 segundos en planes Pro es suficiente para la mayoría de las respuestas agénticas. Para workflows que duran minutos, necesitas otra opción.

    Cloudflare Workers + Durable Objects — la opción de mayor rendimiento para agentes edge. Durable Objects resuelve el problema de estado en entornos serverless de forma elegante. La curva de aprendizaje es mayor, pero el resultado en latencia y coste a escala es difícil de igualar.

    Docker + VPS — cuando necesitas control total, costos predecibles a escala media y no quieres depender de plataformas específicas. Es lo que uso para los agentes internos de Dominicode que corren de forma continua.

    Una regla práctica: si el agente responde en menos de 30 segundos y no necesita estado entre llamadas, serverless es suficiente. Si el agente trabaja durante minutos, mantiene conexiones o necesita acceso a recursos locales, necesitas un proceso persistente.


    Mi stack en Dominicode: la versión concreta

    Sin rodeos. Esto es exactamente lo que uso:

    Capa Herramienta Por qué
    Modelo principal Claude Sonnet (Anthropic) Mejor comportamiento en agentic loops, 200k contexto
    Modelo para análisis Gemini 2.5 Pro Contexto 1M para documentos grandes
    Runtime Bun Arranque más rápido, compatibilidad TS nativa, fetch nativo
    Framework de agente Vercel AI SDK Tipado TS sólido, agnóstico al proveedor, maxSteps nativo
    Herramientas custom MCP servers propios Reutilizables entre agentes, estándar abierto
    Memoria semántica Supabase + pgvector Postgres ya en el stack, zero overhead operacional
    Memoria episódica Postgres (tabla JSON) No necesita búsqueda vectorial, estado estructurado
    Observabilidad Langfuse cloud Open source, free tier generoso, integración VAISDK
    Deployment (agentes web) Vercel Integración natural con el SDK
    Deployment (procesos) Railway + Docker Agentes de larga duración, procesos internos
    Validación Zod Schemas para tool inputs y outputs tipados

    La parte que más me preguntan es el runtime: por qué Bun y no Node. La respuesta corta: en scripts de agentes que arrancan y terminan frecuentemente, la diferencia de arranque es perceptible. El soporte nativo de TypeScript elimina el paso de transpilación en scripts de herramientas. Y fetch nativo sin polyfills simplifica el código de integración con APIs externas.


    Lo que descarto y por qué

    LangChain (la librería base) — demasiada abstracción sobre abstracciones. El problema no es que sea mala herramienta: es que cuando algo falla en un agente LangChain, la pila de herencia de clases hace que depurar sea más difícil que si hubieras implementado el loop a mano. LangGraph tiene más sentido para flujos complejos, pero la librería base la evito.

    AutoGen (Microsoft) — interesante para investigación, inconsistente en producción. El modelo de conversación entre agentes es elegante en teoría, pero en proyectos reales he visto bucles de conversación que consumen tokens sin converger. Puede mejorar, pero hoy no lo usaría para un sistema que atiende usuarios reales.

    Pinecone como primera opción — no porque sea malo, sino porque pgvector en Postgres elimina una dependencia externa para la mayoría de los casos de uso. Cuando el volumen de embeddings supere los diez millones o necesites búsquedas en milisegundos a escala muy alta, Pinecone tiene sentido. Antes, no.

    Modelos locales como backbone — la brecha de calidad con los modelos de frontera es demasiado grande para sistemas agénticos complejos. Para clasificación de intenciones sencillas o filtros de moderación, tiene sentido. Para el loop principal de un agente que toma decisiones consecuentes, no lo haría hoy.


    El stack no es el problema

    La decisión de stack importa — pero menos de lo que sugiere el volumen de contenido que se publica sobre herramientas de IA cada semana.

    He visto proyectos con el stack perfecto que fallaban en producción por falta de observabilidad. He visto proyectos con stacks “incorrectos” que funcionaban perfectamente porque el equipo entendía qué estaba haciendo.

    El stack es el entorno. Lo que importa es entender cómo funciona el agentic loop, cómo diseñar herramientas que el modelo pueda usar de forma predecible, y cómo instrumentar el sistema para ver qué ocurre cuando algo falla.

    Si quieres construir esto desde cero con criterio — desde el primer loop hasta el sistema completo en producción — en el curso Construye con IA cubrimos exactamente estas decisiones: qué stack elegir para cada tipo de proyecto, cómo estructurar el código para que sea mantenible, y cómo pasar de prototipo a sistema que funciona cuando no estás mirando.

    Y si quieres el marco metodológico para especificar el sistema antes de escribir una línea de código — evitar construir el agente equivocado — el libro de Spec-Driven Development es la guía que yo sigo antes de abrir el editor.


    FAQ — Preguntas frecuentes sobre el stack de IA agéntica

    ¿Qué framework de agentes es mejor en 2026: Vercel AI SDK, LangGraph o el SDK directo de Anthropic?

    Depende de la complejidad del sistema. Para la mayoría de proyectos TypeScript con flujos lineales, el Vercel AI SDK ofrece el mejor equilibrio entre abstracción mínima y productividad: tipado sólido, soporte nativo para tool use y streaming, y compatibilidad con múltiples proveedores. LangGraph añade valor cuando el flujo tiene ramificaciones complejas, estado persistente entre pasos o múltiples agentes con routing condicional. El SDK directo de Anthropic tiene sentido cuando necesitas control total sobre cada llamada o cuando las abstracciones intermedias ocultan comportamiento que necesitas ver.

    ¿Necesito una base de datos vectorial para construir un agente?

    No necesariamente. La memoria vectorial solo es necesaria cuando el agente necesita recuperar información relevante de un corpus grande de documentos. Si el agente trabaja con un contexto fijo que cabe en la ventana de contexto del modelo (y con 200k tokens de Claude, cabe mucho), no necesitas embeddings ni búsqueda vectorial. Cuando el corpus supera lo que cabe en contexto, empieza por pgvector en Postgres antes de añadir Pinecone u otra base de datos vectorial externa.

    ¿Qué es MCP y por qué debería importarme en 2026?

    El Model Context Protocol es un estándar abierto que define cómo los agentes de IA consumen herramientas y contexto de fuentes externas. Su importancia práctica: en lugar de construir integraciones específicas para cada agente que quieras conectar a una herramienta, construyes un servidor MCP una vez y cualquier agente compatible puede usarlo. Claude Code, Cursor y la mayoría de los IDEs con IA ya soportan MCP. Si construyes herramientas para agentes hoy, exponerlas como servidores MCP multiplica su utilidad sin trabajo adicional.

    ¿Puedo usar Python para construir el stack agéntico si ya soy developer Python?

    Sí, y tiene sentido si Python es tu lenguaje principal. El ecosistema de agentes en Python es más maduro en algunos aspectos: LangChain, AutoGen, CrewAI y la mayoría de frameworks de referencia nacieron en Python. Lo que pierdes en TypeScript: algunas integraciones no tienen SDK Python equivalente al mismo nivel de calidad. Lo que ganas: ecosistema de ML más rico y más documentación de referencia. La decisión debe estar en el lenguaje que dominas, no en el que tiene más hype.

    ¿Cómo elijo entre Railway y Vercel para desplegar un agente?

    La regla práctica: si el agente responde a peticiones HTTP en menos de 60 segundos y no necesita mantener estado entre llamadas, Vercel Functions es suficiente y más simple. Si el agente trabaja en procesos de larga duración (más de un minuto), necesita WebSockets, mantiene conexiones persistentes, o accede a recursos locales del servidor, Railway con un contenedor Docker es la opción correcta. Cloudflare Workers + Durable Objects es la tercera opción para máxima performance edge cuando el coste a escala importa.

    ¿Qué herramienta de observabilidad recomendarías empezar primero?

    Langfuse. El plan gratuito en cloud cubre 50.000 observaciones al mes, la integración con el Vercel AI SDK es de una línea de código (el parámetro experimental_telemetry), y si en algún momento necesitas privacidad total de los datos, puedes autohospedarlo con Docker. Si ya tienes infraestructura OpenTelemetry en la empresa, las semantic conventions GenAI de OTEL te permiten integrar sin añadir otra plataforma.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.