DEV Community

Cover image for Uso adversarial de IA: el patrón para no perder criterio técnico
lu1tr0n
lu1tr0n

Posted on • Originally published at elsolitario.org

Uso adversarial de IA: el patrón para no perder criterio técnico

Hay una ansiedad silenciosa que circula entre equipos de desarrollo en 2026: ¿me estoy volviendo dependiente de la IA? ¿Se está atrofiando mi criterio técnico? La pregunta es legítima, pero quizás esté mal formulada. La respuesta corta es que el problema no es usar IA; es cómo la usás. Y el patrón que separa a un modo del otro tiene nombre: uso adversarial de IA.

Este artículo es sobre ese patrón concreto, por qué funciona, cómo aplicarlo a tu workflow diario con Claude Code, Cursor o Copilot, y por qué la habilidad real que vas a necesitar en cinco años no es prompting bonito sino lectura escéptica.

TL;DR

  • La crítica común dice que la IA hace perezosos a los ingenieros — el verdadero problema es la abdicación, no la pereza.
  • Uso adversarial significa tratar el output de la IA como borrador de un junior brillante pero sobreconfiado.
  • El patrón clave: pedirle a la IA que argumente contra su propia respuesta antes de aceptarla.
  • Generar → interrogar → revisar es el bucle donde vive el criterio técnico.
  • La habilidad real del futuro no es prompting: es hacer las preguntas escépticas correctas a cualquier output generado.
  • El criterio no se erosiona con la IA; se erosiona con el uso pasivo. La distinción está bajo tu control.

El problema mal diagnosticado: no es pereza, es abdicación

La crítica habitual contra los asistentes de código actuales suena así: vuelven perezosos a los ingenieros. Después de más de un año conviviendo con estas herramientas en producción, esa lectura empieza a parecer floja. La pereza es voluntad; lo que pasa con la IA mal usada es otra cosa.

El problema real no es pereza. Es abdicación. Cuando aceptás una solución generada sin interrogarla, no estás ahorrando tiempo: estás difiriendo una deuda técnica que acumula intereses compuestos. La diferencia importa porque sugiere soluciones distintas.

El ingeniero que copia y pega un middleware de autenticación generado por IA sin leerlo no está siendo más rápido. Está siendo más rápido ahora y mucho más lento cuando ese middleware falle silenciosamente en un edge case de producción a las 2 AM. Velocidad aparente versus velocidad real: dos curvas que divergen brutalmente con el tiempo.

Y acá viene la opinión que importa: la solución no es usar menos IA. Es usarla adversarialmente. Reducir el uso de IA en 2026 es renunciar a un multiplicador real de productividad sin atacar la causa del problema. Lo que hay que cambiar es el modo, no la cantidad.

Qué significa uso adversarial de IA

El uso adversarial de IA se basa en una premisa simple: tratá el output del modelo como un primer borrador de un ingeniero junior brillante pero sobreconfiado. No lo rechaces por reflejo. No lo aceptes en bloque. Lo interrogás.

El junior brillante puede tener razón. Muchas veces la tiene. Pero también puede haber asumido cosas que no se sostienen en tu contexto, ignorado restricciones específicas de tu sistema, o resuelto el problema equivocado con elegancia. Tu trabajo como senior —y ahora todos somos, de alguna manera, seniors revisando código generado— es detectar esos casos antes de que crucen el merge.

Este patrón cambia tu relación con la herramienta. Pasás de consumidor pasivo a colaborador escéptico. Y ese cambio tiene implicaciones cognitivas importantes: estás ejercitando exactamente el músculo que la crítica original temía que se atrofiara. El criterio se entrena con preguntas, no con respuestas. La IA te da respuestas; tu trabajo es generar las preguntas correctas sobre esas respuestas.

💭 Clave: El criterio técnico no se atrofia con la IA. Se atrofia con el uso pasivo de IA. La diferencia está enteramente bajo tu control.

El patrón: prompt de auto-interrogación

El núcleo del uso adversarial es un prompt que ejecutás después de cualquier respuesta no trivial del modelo. La idea es forzar al modelo a argumentar contra su propia respuesta. Acá va el patrón base que podés copiar tal cual y empezar a usar hoy:

Aquí está la solución que propusiste:

[pegar el código o la respuesta original]

Ahora argumentá en contra. ¿Qué edge cases no maneja?
¿Qué supuestos hiciste sobre el input o el entorno que
podrían no sostenerse en producción? ¿Qué cambiarías si
supieras que este código va a ser revisado por un
ingeniero senior en una auditoría de seguridad?
Listá los problemas en orden de severidad.
Enter fullscreen mode Exit fullscreen mode

Corré esto después de cualquier solución generada que vaya a producción. Lo que vuelve es casi siempre útil: estados de error que el modelo omitió, supuestos implícitos sobre la forma del input, superficie de seguridad que pasó por alto, dependencias no declaradas, manejo deficiente de concurrencia. Críticamente, ahora estás pensando junto a la herramienta, no consumiendo su output.

Ese bucle —generar, interrogar, revisar— es donde vive el criterio. Es donde te mantenés afilado. Sin él, sos un router que pasa tokens del modelo al editor sin procesarlos.

El bucle generar-interrogar-revisar mantiene el criterio activo en cada iteración.

Ejemplo: middleware de autenticación interrogado

Veamos cómo funciona en concreto. Supongamos que le pediste a Claude que escriba un middleware de autenticación para Express. El modelo responde con algo así:

// middleware/auth.js
const jwt = require('jsonwebtoken');

function authMiddleware(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];

  if (!token) {
    return res.status(401).json({ error: 'No token' });
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
}

module.exports = authMiddleware;
Enter fullscreen mode Exit fullscreen mode

Se ve razonable. En modo pasivo, lo aceptás y seguís. En modo adversarial, le pegás el código de vuelta al modelo y le pedís que argumente en contra. La respuesta típica trae cosas como:

  • No valida el algoritmo del JWT: vulnerable al ataque clásico de cambiar el header a none o a un algoritmo simétrico cuando esperabas asimétrico. Hay que pasar la opción algorithms: ['RS256'] explícita a jwt.verify.
  • No diferencia entre token expirado y token inválido: el cliente no puede saber si debe pedir refresh o reautenticar. Hay que inspeccionar err.name === 'TokenExpiredError' y devolver un código distinto.
  • No maneja el caso Bearer con capitalización inconsistente: si el cliente manda bearer xxx en minúsculas, el split sigue funcionando pero podés perder el prefijo esperado en logs aguas abajo.
  • No verifica audience ni issuer: cualquier token firmado con esa clave es aceptado, aunque haya sido emitido para otro servicio. Hay que pasar audience e issuer explícitos.
  • No registra intentos fallidos: imposible detectar credential stuffing o token replay sin instrumentación mínima de errores.

Cinco problemas reales en quince líneas. Sin la interrogación, llegan a producción. Con la interrogación, llegan a tu pull request donde podés decidir cuáles importan y cuáles no para tu caso. Algunos serán críticos, otros aplicarán solo en un setup específico que no tenés. Tu trabajo es discriminar — exactamente la habilidad que la crítica original temía perder.

💡 Tip: Guardá el prompt de interrogación como snippet o alias en tu editor. La fricción de tener que recordarlo es la diferencia entre usar el patrón siempre y usarlo solo cuando te acordás.

El bucle generar → interrogar → revisar

El uso adversarial no es un evento único; es un bucle que repetís hasta que el output sobrevive tu propio escrutinio. Visualizado:

graph LR
  A["Generar solución"] --> B["Pegar respuesta"]
  B --> C["Pedir auto-crítica"]
  C --> D{"¿Dudas?"}
  D -->|"Sí"| E["Revisar con cambios"]
  E --> B
  D -->|"No"| F["Revisión humana final"]
  F --> G["Aceptar o descartar"]
Enter fullscreen mode Exit fullscreen mode

Cada iteración suele tardar entre 30 segundos y 2 minutos en runtime. Comparado con depurar un bug en producción tres semanas después, es trivial. Comparado con un postmortem por una brecha de seguridad porque alguien aceptó un middleware sin validar audience, es regalado.

La señal de que el bucle terminó es simple: el modelo pasa tres iteraciones sin producir críticas sustantivas nuevas. En ese punto, o la solución es robusta o hay problemas que solo un humano con contexto del sistema puede detectar. Ese humano sos vos en la revisión final.

La habilidad real no es prompting

Hay mucho discurso alrededor de prompt engineering como la habilidad del futuro. Vale la pena cuestionarlo de frente.

Los ingenieros que van a ser peligrosos con IA en cinco años no son los que memorizaron los mejores templates de prompts. Son los que pueden mirar cualquier output generado —código, diagrama de arquitectura, especificación, suite de tests, documento de diseño— y formular inmediatamente las preguntas escépticas correctas. "¿Qué supuso este modelo sobre el orden de las operaciones?" "¿Esta función asume idempotencia que el caller no garantiza?" "¿Por qué eligió este algoritmo y no el otro?"

Esa habilidad se construye con práctica deliberada. El prompting adversarial es justamente eso: una forma de practicarla de manera intencional en vez de accidental. Cada vez que interrogás el output del modelo, estás entrenando ese músculo. Cada vez que aceptás sin interrogar, lo dejás dormir un poco más.

El paralelo histórico es claro. Cuando llegaron las calculadoras de bolsillo en los 70, hubo pánico de que la gente perdería capacidad aritmética. Lo que pasó en realidad fue una bifurcación: algunos usaron la calculadora como muleta y nunca desarrollaron intuición numérica; otros la usaron como amplificador y desarrollaron intuiciones más profundas sobre órdenes de magnitud, plausibilidad de resultados y casos límite. La calculadora no es el factor que define el resultado; el modo de uso, sí. Con la IA estamos en el mismo punto de inflexión, solo que con más estakes.

Dos modos de usar la misma herramienta producen ingenieros radicalmente distintos en cinco años.

Cómo instalar el hábito en tu equipo

Para equipos en LATAM que están adoptando Claude Code, Cursor, Copilot y similares a buen ritmo, el uso adversarial puede convertirse en práctica cultural si lo institucionalizás. Sin rituales, el patrón se diluye en dos semanas. Algunas ideas concretas que ya están funcionando en equipos que conozco:

  • Snippet compartido en el repo: el prompt de interrogación va versionado en .claude/prompts/adversarial.md o equivalente. Que esté a un atajo de distancia y se actualice como cualquier otra herramienta.
  • PRs con sección "Auto-crítica": un campo en el template del pull request donde el autor pega el resultado de haberle pedido al modelo que argumente contra su propio output. No es para que nadie lo lea necesariamente; es para forzar el ejercicio mental.
  • Pair programming con IA como tercero: dos personas, una IA, una conversación. El segundo humano se especializa en hacer las preguntas escépticas. Rotás roles cada 30 minutos para que ambos practiquen.
  • Demos internas con pregunta obligatoria: cuando alguien presenta una feature implementada con asistencia de IA, una pregunta del equipo siempre: "¿qué te pidió la IA que asumieras y qué decidiste vos?". Si la respuesta es "nada, lo acepté", hay una conversación pendiente.
  • Onboarding adversarial: a los nuevos integrantes del equipo, mostrales el patrón en vivo el primer día con un ejemplo real del repo. Que vean cómo emergen los problemas. La curva de aprendizaje es de dos o tres sesiones.

Estos rituales suenan pequeños. La diferencia que hacen en seis meses, observable en la calidad del código que llega a producción y en la cantidad de incidentes evitados, es enorme.

⚠️ Ojo: No transformes el patrón en burocracia. Si convertís la auto-crítica en un checkbox del PR que nadie lee, perdiste el punto entero. El valor está en el pensamiento, no en el ritual.

Trampas comunes del uso adversarial

El patrón tiene fallas si no estás atento. Algunas que vale la pena vigilar:

  • El modelo se contradice por defecto: si le decís "argumentá en contra", lo hará incluso cuando la solución original era correcta. Tu trabajo es evaluar cuáles críticas son reales y cuáles son ruido educado. Confiar a ciegas en la auto-crítica es el mismo problema que confiar a ciegas en el output original, solo que con un paso extra.
  • Infinitas iteraciones: podés caer en un bucle de revisión sin fin donde cada respuesta genera más críticas. Definí un criterio de parada explícito: "tres preguntas escépticas respondidas sin nuevos problemas significativos" o "el costo marginal de seguir excede el costo del riesgo residual".
  • Falsa sensación de cobertura: que el modelo no encuentre problemas no significa que no haya problemas. Mantené la revisión humana, especialmente para código de seguridad, pagos, manejo de PII o transacciones críticas. La IA no reemplaza la responsabilidad de quien hace el merge.
  • Adversarial fatigue: si interrogás absolutamente todo —incluso un script de migración trivial—, no interrogás nada. Reservá el patrón para código no trivial. El boilerplate puede pasar directo si lo entendés a primera vista.
  • Contexto perdido entre iteraciones: si la conversación se vuelve muy larga, el modelo pierde el hilo. Empezá sesiones nuevas cuando notes degradación de calidad, pegando solo el código relevante.

📖 Resumen en Telegram: Ver resumen

Preguntas frecuentes

¿Vale la pena el tiempo extra del uso adversarial?

Casi siempre, para código que llegará a producción. Lo que ahorrás en debug, rollbacks y deuda técnica supera con creces los 1-2 minutos extras por iteración. Para scripts descartables, código exploratorio o pruebas locales rápidas, no es necesario y agrega fricción innecesaria.

¿Funciona con todos los modelos? ¿Claude, GPT, Gemini, Llama?

Sí, el patrón es agnóstico al modelo. Funciona mejor con modelos grandes (Claude Sonnet 4.6+, Claude Opus 4.7, GPT-5, Gemini Pro) porque sus auto-críticas son más sustantivas y menos genéricas. Con modelos más chicos las críticas tienden a ser superficiales, pero el ejercicio sigue siendo útil para vos como ingeniero porque te fuerza a pensar el problema dos veces.

¿No es lo mismo que pedirle code review a la IA?

Hay overlap, pero no es idéntico. El code review pide opinión general. La auto-interrogación es más estructurada: forzás al modelo a justificar supuestos específicos, listar edge cases concretos, considerar el contexto de auditoría. Es un subset más quirúrgico del code review, enfocado en encontrar fallos en la respuesta misma del modelo.

¿Cómo enseño esto a juniors en mi equipo?

Hacelo en vivo. Sentate con un junior, pediles que generen una solución con IA y mostrales el segundo prompt en pantalla compartida. Que vean qué tipo de problemas emergen. En dos o tres sesiones lo internalizan y empiezan a aplicarlo solos. La transferencia funciona mejor por demostración que por documentación.

¿Esto reemplaza tests, linters, type checking?

No. Es complementario y va antes —al momento de generar el código. Los tests, linters y type checking siguen siendo obligatorios. La auto-interrogación captura clases de problemas que esas herramientas no detectan: supuestos implícitos sobre el dominio, decisiones de diseño cuestionables, omisiones de contexto que ningún linter puede inferir.

¿Hay riesgo de que el modelo invente fallos que no existen?

Sí, sucede regularmente. El modelo puede listar problemas que en tu contexto no aplican o que ya están manejados aguas arriba. Por eso el patrón requiere criterio humano: no aplicás todas las correcciones que el modelo sugiere; las evaluás. Si terminás aplicando todo lo que dice sin filtrar, volviste al modo pasivo desde el otro lado del flujo.

Referencias

📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.

Top comments (0)