Logotipo de ConstructiCat
CodeBust.
Explorar la sección ▾

API alucinada.

Código generado por IA que llama a funciones, métodos, parámetros, claves de configuración o paquetes que parecen plausibles pero que no existen en la versión real de la biblioteca de la que dependes.

##Signos y síntomas

Un revisor detecta una API alucinada cuando el código se lee con fluidez y "parece" un uso idiomático de una biblioteca, pero la llamada, opción o importación concreta no aparece en la API real de esa biblioteca. Señales reveladoras:

  • Un método u opción cuyo nombre es demasiado conveniente: hace exactamente lo que pedía el prompt, con un nombre que mezcla dos APIs reales (p. ej. findLastWhere, includesAll, parseDateSafe).
  • Parámetros inventados sobre una función real (la variante peligrosa: a menudo compila y solo falla en tiempo de ejecución, o ignora la opción en silencio).
  • Una import de un paquete que no está en package.json / requirements.txt, o una importación con nombre que el módulo nunca exporta.
  • Formas de API que mezclan versiones: una firma de la v2 invocada sobre un cliente de la v5, o un método eliminado/renombrado hace varias versiones.
  • Comentarios en línea confiados que afirman que la llamada es correcta ("// devuelve el cargo reembolsado").
// Generado por IA — fluido, plausible y erróneo
import { formatRelative } from 'date-fns';

// `roundingMethod` está inventado aquí — formatRelative no acepta esa opción (es de formatDistanceStrict), así que se ignora en silencio
const label = formatRelative(date, new Date(), { roundingMethod: 'floor' });

// `findLastWhere` no existe en Array — TypeError en tiempo de ejecución
const lastActive = items.findLastWhere(i => i.active);

// Método de SDK inventado: stripe-node no tiene refunds.createForCharge — la llamada real es stripe.refunds.create({ charge, amount })
await stripe.refunds.createForCharge(chargeId, { amount: 500 });

Una heurística rápida: si no puedes señalar la entrada de documentación o la definición de tipo de una llamada de terceros en menos de un minuto, trátala como alucinada hasta que se demuestre lo contrario.

##Causas del problema

Por qué los modelos lo producen

  • Plausibilidad del siguiente token, no búsqueda. Un LLM predice la continuación estadísticamente más probable, que es en la práctica el promedio de todas las APIs similares que ha visto. Ese promedio a menudo es un método que debería existir: el modelo emite "el nombre conveniente" en lugar del real. En un estudio sobre recomendación de APIs para Java 8 (JRE), entre el 58,1 % y el 84,1 % de las APIs recomendadas por tres modelos no existían en la biblioteca indicada, y la mayoría de los errores eran nombres de métodos inexistentes (arXiv 2409.15228).
  • Mezcla de versiones. Los corpus de entrenamiento mezclan muchas versiones de una biblioteca, así que el modelo fusiona las firmas de la v2 y la v5 en una que no coincide con ninguna. Los conflictos de conocimiento de API, como llamar con un parámetro inexistente, son una categoría documentada de alucinación a nivel de repositorio (Zhang et al., ISSTA 2025), y los autores señalan que algunas alucinaciones pueden superar los análisis estáticos y todos los casos de prueba.
  • Desactualización por la fecha de corte del entrenamiento. El modelo usa con total seguridad APIs renombradas, obsoletas o eliminadas desde su fecha de corte, y recurre a lo que más aparecía en su corpus de entrenamiento, que puede ser una versión de la biblioteca más antigua que la que tienes instalada.
  • Sin contexto de repositorio/dependencias. Sin tu package.json ni el código fuente real del módulo, el modelo inventa ayudantes que "parecen" pertenecer a tu stack.
  • Adulación / afán de responder. El asistente casi nunca dice "no estoy seguro de que ese método exista": produce código confiado y de aspecto ejecutable, lo que rebaja la sospecha del revisor.
  • El determinismo lo hace explotable. La alucinación de paquetes no es ruido aleatorio: en 16 modelos y 576 000 muestras de código (2,23 millones de referencias a paquetes), el 19,7 % de las referencias a paquetes eran alucinadas (205 474 nombres únicos inexistentes), y el 58 % de los paquetes alucinados se repitió más de una vez en 10 ejecuciones del mismo prompt (Spracklen et al., USENIX Security 2025; resumen de SecurityWeek).

Por qué resulta perjudicial

  • Corrección. Los parámetros inventados y las opciones silenciosamente ignoradas producen comportamientos incorrectos en rutas de código que las pruebas rara vez cubren; el fallo aflora en producción, no en tiempo de compilación.
  • Seguridad / cadena de suministro. Un nombre de paquete alucinado es un objetivo de registro: los atacantes publican malware con el nombre predicho, así que el siguiente desarrollador que acepta la sugerencia lo instala: el ataque de slopsquatting (término acuñado por Seth Larson, de la PSF). La variante de desactualización reintroduce en silencio APIs obsoletas o con CVE.
  • Carga de revisión. El código plausible traslada a los revisores la carga de verificar cada llamada desconocida contra la documentación; la prosa fluida hace que esa verificación sea menos probable.
  • Acumulación de deuda técnica. Los desarrolladores suelen pegar el stub alucinado "casi funcional" y parchear a su alrededor en lugar de corregir la llamada raíz, alimentando la tendencia general de la era de la IA de aumento del copiar/pegar y caída de la refactorización (GitClear 2025: líneas movidas/refactorizadas, del 25 % (2021) a menos del 10 % (2024); copiadas/pegadas, del 8,3 % al 12,3 %; bloques duplicados de 5+ líneas, ~8× en 2024).

##Tratamiento

Tácticas de proceso y de prompting

  • Basa el modelo en la API real. Pega en el contexto los stubs de tipos reales, la página de documentación pertinente o el código fuente de la versión instalada, o usa una herramienta de recuperación de documentación (estilo Context7 / RAG). Indícale las versiones exactas de las dependencias de tu lockfile.
  • Exige citas. Pide al modelo que nombre la entrada oficial de documentación o la firma de tipo de cada llamada de terceros que use. Regla práctica: toda llamada a un método de una biblioteca de terceros debe poder rastrearse hasta su entrada de documentación antes de aprobar el PR.
  • Hazlo ejecutar, en el bucle. Exige que pasen tsc / mypy / pylint / la compilación y la batería de pruebas, y haz que el agente realmente ejecute npm install / pip install para que un paquete alucinado falle rápido en lugar de llegar a la revisión.
  • Pídele que reutilice, no que invente. Aliméntalo con un grep del módulo existente e indícale que llame a los ayudantes existentes (reutiliza los ayudantes de utils/http.ts) en lugar de conjurar nuevos: esto también contrarresta el olor de duplicación de ayudante reinventado.
  • Controla las dependencias. Usa un lockfile + una lista de permitidos de instalación y un escáner de cadena de suministro (Socket/Snyk) antes de añadir cualquier paquete nuevo, para que no se cuelen nombres con slopsquatting.

La refactorización del código

Reemplaza la llamada inventada por la real verificada. Si de verdad quieres la comodidad que imaginó el modelo, impleméntala una sola vez contra la API real detrás de un envoltorio creado con Extraer método en lugar de esparcir la llamada falsa.

// Antes — método de SDK inventado + valor de opción no válido
async function refundLast(chargeId: string) {
  // `stripe.refunds.createForCharge` no existe y 'requested' no es un motivo de reembolso válido
  return stripe.refunds.createForCharge(chargeId, { amount: 500, reason: 'requested' });
}

// Después — verificado contra los tipos/documentación del SDK de Stripe instalado,
// y la "comodidad" envuelta una sola vez para no repetir la API real
async function refundCharge(chargeId: string, amountCents: number) {
  return stripe.refunds.create({
    charge: chargeId,
    amount: amountCents,
    reason: 'requested_by_customer',
  });
}

Para la variante de desactualización, trata una llamada obsoleta señalada como una tarea real de actualización: pásate a la API actual y fija la versión, en lugar de silenciar la advertencia.

Límites. Los verificadores de tipos y los resolvedores detectan el subconjunto resoluble (objetos tipados, importaciones no resueltas). El resto dinámico/sin tipos —opciones inventadas sobre any, claves de configuración en cadenas, campos de payload REST— no tiene un detector automatizado fiable y debe verificarlo una persona contra la documentación real.

##Detectado por