Del mismo modo que cuando me encontré por primera vez con un LLM (en los tiempos de GPT-2 y AIDungeon) me quedé anonadado dudando si era la víctima de una especie de broma ultraelaborada, también hay un momento en el que, si trabajas lo suficiente con modelos de lenguaje, la ilusión se deshace.
No es un momento espectacular ni mediático, no tiene nada que ver con prompts ingeniosos ni con benchmarks, ni con alucinaciones sorprendentes. Es el encuentro con errores garrafales y a primera vista incomprensibles.
Estos fracasos absolutos de los LLMs los he encontrado con problemas más estructurales de lo habitual. Por ejemplo, un generador procedural para niveles en un roguelike tratando que respete ciertas invariantes. O un sistema de combate en el que se tengan en cuenta flanqueos y restricciones geométricas, donde intervienen ángulos y estados simultáneos. Ha sido aquí cuando he encontrado que el modelo empezaba a producir resultados absolutamente incoherentes. Y no es que falle en un detalle, es que pierde por completo el hilo del sistema.
A partir de ahí, lo interesante no es la frustración. Cuando tu perfil es técnico y no le fías el futuro a la ruleta del llamado «vibe coding», tienes recursos de sobra, y de hecho a menudo tardas tanto en programar como en escribir un prompt que capture la lógica de negocio apropiada. Lo interesante, como digo, es la pregunta: ¿qué tipo de inteligencia es esta realmente, y por qué colapsa precisamente en estos dominios?

A primera vista, diría que el problema es que es probabilístico y no determinista. La respuesta es correcta pero se me hace insuficiente, la estructura del problema es más profunda. Creo que lo que muestran estos límites con una enorme claridad es que un LLM no ejecuta algoritmos en tiempo de inferencia ni mantiene estados explícitos, verificables y estables bajo transformación; lo que hace es generar secuencias de texto que son plausibles dadas las anteriores.
Cuando escribimos código, e incluso cuando estamos todavía en la fase mental previa, operamos con una noción de estado que, aunque sea incompleta o borrosa, tiene continuidad. Podemos imaginar un grid, colocar elementos, recorrer iteraciones, detectar inconsistencias, retroceder. Si estamos creando un RPG por turnos y con casillas, antes de programarlo podemos ejecutarlo en nuestra imaginación y considerar los resultados de nuestras decisiones de diseño. No es necesario que esa simulación interna sea perfecta para que sea útil, pero sí necesita una cierta estabilidad, una capacidad de mantener relaciones entre elementos a lo largo del tiempo. Eso es justo lo que permite que podamos diseñar algoritmos que respeten invariantes globales, porque aunque no ejecutemos literalmente el código en nuestra cabeza, sí estamos constantemente contrastando lo local con lo global.
El modelo de lenguaje, al contrario que nosotros, no hace nada de eso. No tiene una representación persistente del estado que está describiendo, ni un mecanismo interno que le obligue a respetar invariantes a lo largo de una secuencia. Cada token que genera está condicionado por los anteriores, sí, pero esa “memoria” se parece más a un eco estadístico. No es un estado estructurado. Por eso puede producir código que localmente parece razonable pero que se rompe globalmente. El LLM no tiene nuestra capacidad para operar con el sistema que describe, lo que hace es improvisar una narración coherente sobre cómo debería comportarse ese sistema, está generando una descripción plausible de su ejecución.
Esto se vuelve especialmente evidente en cuanto uno se sale de los dominios donde la tolerancia al error es alta. En tareas tipo CRUD, scripting sencillo o integración de APIs, donde los patrones están hiperestandarizados y los fallos no tienen efectos sistémicos graves, el modelo funciona sorprendentemente bien, porque basta con que la solución se parezca a algo correcto, y además las soluciones correctas se parecen mucho entre sí. Es decir, en dominios hiperestandarizados, la distribución de soluciones correctas es estrecha y está densamente representada en el entrenamiento, con lo que la aproximación probabilística converge fácilmente a algo válido. Pero en cuanto entramos en espacios discretos con restricciones duras, la distribución de soluciones correctas es un conjunto de medida insignificante dentro del espacio de respuestas plausibles. Y en cuanto hay que contar elementos, mantener conectividad en un mapa, garantizar que un conjunto de condiciones se cumple en todos los casos,… ahí la aproximación probabilística deja de ser suficiente. Hay dominios en los que no hay margen para la plausibilidad. O hay diez elementos, o no los hay. O el grafo es conexo, o no lo es.
El ejemplo de contar es particularmente didáctico al respecto. Una de las labores más difíciles que se le pueden pedir a un modelo es que cuente, y hemos tenido buena cantidad de memes al respecto. Tanto que hay que parchearlos desde fuera para que lo hagan, da igual lo complejo que sea el LLM. Y esto nos dice mucho acerca de su funcionamiento interno. Contar requiere mantener un estado discreto, incrementarlo de forma fiable y verificar al final que la cardinalidad es la esperada. Un modelo de lenguaje no funciona así: genera una secuencia que “suena como” alguien listando elementos, pero no tiene ningún contador interno que garantice nada. Funciona en casos cortos porque ha visto millones de ejemplos y los patrones están muy marcados, pero no hay ninguna garantía estructural detrás.
Obviamente, en 2026 el ejemplo del conteo es trivial en cuanto que cada vez tenemos menos «LLMs puros» y más «LLMs con herramientas«. Los sistemas desplegados en producción no son solo transformers autoregresivos; son sistemas aumentados con ejecución de código, bucles agénticos, feedback de resultados externos y verificación iterativa. Cuando un modelo con acceso a un intérprete Python necesita contar elementos, simplemente escribe y ejecuta len(lista). Pero indico el ejemplo del conteo precisamente para destacar problemas que son estructurales a los LLM.
Si volvemos a problemas más cercanos al diseño de sistemas, como la generación procedural de una ciudad dividiendo el espacio en bloques o el cálculo de bonificadores en combate en función de ángulos y posiciones relativas, aparece exactamente el mismo fenómeno en otra escala. Cuando se le hace preguntas generales, el modelo puede sugerir algoritmos conocidos (por ejemplo, un BSP para dividir el espacio) porque eso entra dentro de su capacidad de recuperación de patrones, pero cuando se le pide que instancie ese algoritmo en un contexto concreto, con unas restricciones específicas y un resultado coherente globalmente, deja de operar sobre una estructura y vuelve a operar sobre palabras. El resultado acaba siendo una descripción que puede parecer un algoritmo, pero que no se va a comportar adecuadamente.
Se puede argumentar que el límite de lo posible pueda ser mejorado con las herramientas externas y agentes mencionados, pero delegar la ejecución en sistemas deterministas solo externaliza el problema en lugar de eliminar la limitación. Además, el coste de esa orquestación puede superar con creces al de una implementación directa.

Aquí hay un matiz importante que tampoco podemos ignorar, y es que el rol del LLM es diferente al que intuitivamente se le quiere asignar. Es muy bueno explorando espacios de posibilidades, sugiriendo enfoques, señalandotrade-offs o incluso detectando inconsistencias locales en un código ya escrito. Es decir, funciona bien en todo lo que tiene que ver con expandir y tensionar el espacio de ideas. Lo que no hace bien es cerrar ese espacio garantizando que una solución concreta cumple todas las condiciones impuestas. Por esto mismo es por lo que en el desarrollo serio de software se utiliza para crear prototipos funcionales, pero se atasca y deja de ser útil cuando hay una lógica de negocio compleja hacia la que tenemos que converger: en ese punto, describir cada pequeño detalle para que el LLM genere un código que cumpla las especificaciones puede suponer perder el tiempo.
Esto explica también otro fenómeno bastante común, y es que cuando se le piden ideas para ampliar un videojuego o un sistema relativamente definido, el LLM tiende a proponer cosas que, aunque suenan interesantes, son inviables en la práctica. Produce ideas que están completamente desacopladas de las restricciones reales del sistema. El modelo no entiende el coste de implementación, ni la complejidad emergente, ni las dependencias que introduce cada nueva pieza. Opera en un espacio de conceptos donde añadir “facciones dinámicas con IA emergente” en un videojuego es una variación más dentro de un género, no una reescritura de la arquitectura.
La brecha entonces la hallamos entre trabajar en un espacio de palabras y trabajar en un espacio de sistemas. En el primer caso, las combinaciones se evalúan por su plausibilidad y su novedad, y en el segundo, por su viabilidad y su coherencia interna. El desarrollador humano, incluso de forma implícita, está constantemente proyectando ideas sobre un sistema concreto y evaluando su encaje. El modelo, si no se le obliga explícitamente, no tiene ese anclaje. Carece de un mecanismo de grounding en un estado externo verificable.
De todo esto se desprende una forma bastante más útil de entender los límites de los LLM en arquitectura de software, así como establecer cuál es su uso adecuado. Más allá de optimizar plausibilidad en lugar de corrección formal, su uso depende de si el problema que tenemos delante requiere exploración o garantía. Cuando es importante abrir el espacio de soluciones, cuestionar supuestos o encontrar enfoques alternativos, el modelo puede actuar como un amplificador de pensamiento sorprendentemente potente. Pero allá donde lo que está en juego es mantener invariantes, asegurar comportamientos globales o trabajar con estructuras discretas sin margen de error, la responsabilidad tiene que recaer en sistemas deterministas.
Esto no es una limitación accidental que vaya a desaparecer con modelos más grandes. No es cuestión de escala, es cuestión de arquitectura. Un modelo autoregresivo que no ejecuta código ni interactúa con un estado externo difícilmente puede garantizar invariantes globales, por mucho que aumente su tamaño. Y aquí es donde me planto respecto a la idea de que la programación o la arquitectura de software vaya a dejar de existir, como quisieran los CEOs de las compañías de IA y otras que ya han visto los desastres derivados de dejar en manos de sus LLMs sus repositorios o su correo electrónico. Los límites de los LLMs a este respecto no son una cuestión de falta de potencia: son estructurales y se deben a su naturaleza más interna. ¿Significa esto que van a desaparecer? ¡No, sin duda que no! Solo que, como suele suceder, el hype no entiende lo que está pasando realmente. Comprender cuáles son las limitaciones de los LLMs nos puede ayudar a refinar su uso, tal como en los casos que he descrito resulta extremadamente útil en la generación de posibilidades, pero muestra ser un sistema profundamente inadecuado cuando se orienta a la validación de realidades.

