Silent failure: cuando tu IA inventa y los tests dicen que todo va bien

| Última modificación: 4 de mayo de 2026 | Tiempo de Lectura: 6 minutos
Premios Blog KeepCoding 2025

Co-Fundador de KeepCoding

Ayer descubrí que la mitad de un módulo de mi app estaba basado en datos inventados. No por un junior despistado. Por mi IA.

Lo peor no es que inventara. Lo peor es que todo compilaba y los 90 tests pasaban.

La ficción coherente

Estoy construyendo BFClaude-9000, una app de menú bar para macOS que monitoriza la cuota de Claude Max. Parte de la funcionalidad requiere distinguir si una cuenta de Claude es de pago o gratuita, llamando a la API de claude.ai.

Le pedí a Claude Code que implementara la detección. Lo hizo. Me entregó:

  1. Un DTO OrganizationInfo con un campo activeFlags: [String]
  2. Una propiedad computada isPaid que comprueba si activeFlags no está vacío
  3. Un enum OrganizationSelection que clasifica las orgs en pagadas y gratuitas
  4. Tests con fixtures que verifican que todo funciona

Bonito. Limpio. Bien estructurado. Todo inventado.

El campo active_flags no existe en la API real de Claude. O si existe, no funciona como el código asumía. Cuando hice login con mi cuenta de pago, la app me dijo que mi cuenta era gratuita.

El patrón del castillo de naipes

Lo insidioso no es que mintiera sobre un campo de la API. Es el sistema completo que construyó alrededor de esa mentira:

// DTO con campo inventado
struct OrganizationInfo: Decodable {
    let uuid: String
    let name: String
    let activeFlags: [String]  // ← Esto no existe

    var isPaid: Bool { !activeFlags.isEmpty }
}

// Lógica que depende del campo inventado
enum OrganizationSelection {
    case paid(id: String, name: String)
    case noPaidOrg    // ← Este estado no debería existir
    case noOrgs
}

// Tests con fixtures que validan la invención
let paidOrg = """
{"uuid": "abc", "name": "Acme", "active_flags": ["pro"]}
"""
// Test pasa ✅ — pero valida ficción contra ficción

¿Lo ves? No es un campo mal puesto. Es un castillo de naipes: el DTO define un campo falso, la lógica depende de ese campo, los tests validan que la lógica funciona con fixtures que también son falsas. Cada pieza confirma a las demás. Todo cuadra. Nada es real.

IEEE Spectrum tiene un nombre para esto: silent failure. El código no crashea, no lanza errores, no enciende alarmas. Simplemente hace lo incorrecto en silencio.

No es un caso aislado

Resulta que la comunidad ya tiene nombre para cuando un LLM se inventa paquetes y dependencias: package hallucination. Un estudio de Snyk encontró que entre el 5% y el 20% de las recomendaciones de paquetes de los principales LLMs son inventadas. Paquetes que no existen, publicados.

Pero lo de los paquetes es el caso fácil. Ejecutas npm install paquete-inventado, falla, te enteras. Un campo inventado en un DTO que parsea JSON con try? y degradación graceful… eso no falla. Funciona. Devuelve nil o un array vacío. Y tu código sigue adelante, operando sobre datos fantasma.

La propia Anthropic, en su documentación sobre reducir alucinaciones, lo dice sin ambages:

«Claude can sometimes generate responses that contain fabricated information… presented in a confident, authoritative manner.»

Presentado de forma «autoritativa». Esa es la clave. No es que dude y se equivoque. Es que afirma con total seguridad algo que se acaba de inventar.

Por qué los tests no te salvan

Aquí es donde duele. Yo tenía tests. Buenos tests. 90 tests en 12 suites. Todos en verde. ¿Y qué?

El problema es que los tests validan consistencia interna, no correspondencia con la realidad. Si el DTO dice que el campo se llama active_flags, el fixture tiene un active_flags, y el test comprueba que el DTO parsea el fixture… todo pasa. Ficción contra ficción. Verde fosforito.

Es como si un estudiante se inventara una fórmula de física, escribiera un examen basado en esa fórmula, y se pusiera un 10 a sí mismo. Cada paso es internamente coherente. El resultado no tiene ningún contacto con la realidad.

Realidad: campo X no existe en la API
   ↓ (invisible)
DTO:     define campo X         ← inventado
Fixture: incluye campo X        ← inventado para validar el DTO
Test:    fixture parsea bien    ← valida invención contra invención
Resultado: ✅ Todo verde        ← ficción coherente

No hay ningún punto en esta cadena donde se compruebe contra la API real. Y este es el agujero.

Todas las medidas actuales son preventivas

Si buscas qué puedes hacer para evitar esto, la literatura y la experiencia te ofrecen una lista de medidas. Todas son preventivas:

Medida Tipo Problema
Instrucciones en CLAUDE.md: «no inventes» Preventiva Las ejecuta el mismo agente que miente
Chain of thought: «cita tus fuentes» Preventiva Puede citar fuentes inventadas
Temperatura baja Preventiva Reduce creatividad, no elimina invención
Grounding con documentos Preventiva Solo si tienes el documento correcto
Prohibiciones explícitas Preventiva El LLM puede «racionalizar» excepciones
RAG (Retrieval Augmented Generation) Preventiva Depende de que la base de datos sea completa

¿Notas el patrón? Todas intentan evitar que la IA invente. Ninguna detecta cuándo ya lo ha hecho.

Es como poner un cartel de «prohibido robar» en una tienda sin cámaras, sin alarmas y sin vigilante. Puede que funcione. Puede que no. No tienes forma de saberlo hasta que cuentas la caja.

Lo que falta: detección reactiva

Lo que necesitamos y hoy no existe son medidas reactivas: sistemas que detecten la invención después de que ocurra, idealmente antes de que llegue a producción.

Imagina:

  • Contract testing contra APIs reales: un test que llame a la API de verdad (con credenciales de test) y compare el schema real con el DTO. Si el DTO tiene campos que la API no devuelve, alarma.

  • Fixture validation: un linter que compruebe que los fixtures de test corresponden a datos reales capturados, no a datos escritos a mano (o generados por la IA). Algo como snapshot testing pero contra respuestas reales de producción.

  • Smoke tests con datos reales: antes de mergear, un paso de CI que ejecute las llamadas contra un sandbox de la API y verifique que los DTOs parsean datos reales sin pérdida silenciosa.

  • Anomaly detection en parseo: si un campo opcional devuelve nil el 100% de las veces en producción, algo huele mal. Un monitor que detecte campos que siempre son nil y los reporte como sospechosos de ser inventados.

  • Diff semántico post-generación: un segundo modelo (o el mismo con un prompt diferente) que revise el código generado y señale campos o estructuras que no puede verificar contra documentación conocida.

Nada de esto existe hoy como producto. Algunos equipos implementan piezas a mano (contract testing es una práctica conocida, por ejemplo). Pero no hay un HallucinationTracker que enchufes a tu CI y te diga «oye, este campo active_flags no aparece en ninguna documentación ni respuesta real de la API».

Y sí, hay un paper de la Universidad de Washington (HallucinationTracker) que propone métricas para detectar confabulaciones. Pero está en fase de investigación, no es algo que puedas brew install.

El problema de fondo

El problema de fondo es profundamente incómodo: las reglas las ejecuta el mismo sistema que las viola.

Cuando pones «no inventes datos» en tu CLAUDE.md, se lo estás diciendo al mismo modelo que va a inventar datos. Es como pedirle al acusado que sea también el juez. Puede funcionar, pero no tienes garantías.

Las medidas preventivas (buenas instrucciones, temperatura baja, grounding) reducen la probabilidad de invención. Pero no la eliminan. Y cuando ocurre, no hay sirena que suene.

Lo que necesitamos es que la detección la haga algo externo al modelo: un test contra datos reales, un linter de schemas, un monitor en producción. Algo que el modelo no pueda racionalizar ni esquivar, porque no es el modelo quien lo ejecuta.

Hasta que eso exista como algo maduro y fácil de usar, estamos en la misma situación que la seguridad informática antes de los firewalls: sabemos que hay un problema, tenemos medidas parciales, y confiamos en que «a mí no me va a pasar».

Qué hago yo mientras tanto

Siendo honesto, estas son las medidas que me funcionan hoy. Ninguna es perfecta:

  1. Leer el código generado como si fuera de un desconocido. No asumir que es correcto porque compila. Esto es agotador, pero es lo que hay.

  2. Preguntar «¿de dónde has sacado esto?» Especialmente para campos de API, nombres de paquetes, y cualquier dato que no puedo verificar mirando el código.

  3. Contract tests manuales. Antes de dar por bueno un DTO, hacer una llamada real a la API y comparar. Es tedioso. Es necesario.

  4. Desconfiar de los tests que pasan a la primera. Si la IA genera código y tests y todo pasa a la primera, eso no es buena señal — es señal de que probablemente validó ficción contra ficción.

  5. Capturar respuestas reales como fixtures. En vez de dejar que la IA escriba los fixtures, guardar las respuestas reales de la API y usarlas como fixture. Si el DTO no parsea la respuesta real, se rompe inmediatamente.

Estas medidas son manuales, lentas, y dependen de mi disciplina. No escalan. Pero hoy son lo mejor que tengo.

Lo que debería existir mañana

Si alguien está buscando un problema real que resolver, aquí hay uno:

Un sistema de verificación post-generación que sea externo al modelo, automático, y que se integre en CI/CD.

No hace falta que sea perfecto. Hace falta que exista. Que alguien construya el equivalente a un linter para alucinaciones: algo que analice el código generado, lo cruce con fuentes verificables (documentación de APIs, schemas OpenAPI, respuestas capturadas), y señale lo que no cuadra.

Hoy, si tu IA inventa un campo de API y lo envuelve en tests coherentes, la única defensa eres tú leyendo el código con ojo clínico. Mañana, debería haber una máquina que lo haga por ti.

Pero hoy no la hay. Y eso es lo más preocupante de todo.


Relacionado: Este post es el tercer capítulo de una serie involuntaria. Primero fue los 44 emails inventados (la IA que actúa sin permiso). Luego MEMORY.md (la IA que olvida lo que aprendió). Ahora, la IA que inventa datos y los envuelve en una ficción que pasa los tests. Tres fallos diferentes, un denominador común: confiamos demasiado en un sistema que no entiende lo que hace.


Read this article in English.

Noticias recientes del mundo tech


¡CONVOCATORIA ABIERTA!

Desarrollo de apps móviles ios & Android

Full Stack Bootcamp

Clases en Directo | Profesores en Activo | Temario 100% actualizado

Descárgate también el informe de tendencias en el mercado laboral 2026.

Fórmate con planes adaptados a tus objetivos y logra resultados en tiempo récord.
KeepCoding Bootcamps
Resumen de privacidad

Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.