<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Joaquin Jose del Cerro Murciano</title>
    <description>The latest articles on Forem by Joaquin Jose del Cerro Murciano (@jjdelcerro).</description>
    <link>https://forem.com/jjdelcerro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3673726%2F8655382d-4cf9-4a98-9b8f-732506bddfc8.png</url>
      <title>Forem: Joaquin Jose del Cerro Murciano</title>
      <link>https://forem.com/jjdelcerro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jjdelcerro"/>
    <language>en</language>
    <item>
      <title>Noema: cuando el patio de juegos no viene de serie</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Sun, 29 Mar 2026 23:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/noema-cuando-el-patio-de-juegos-no-viene-de-serie-4ljo</link>
      <guid>https://forem.com/jjdelcerro/noema-cuando-el-patio-de-juegos-no-viene-de-serie-4ljo</guid>
      <description>&lt;p&gt;Hola,&lt;br&gt;
llevo meses escribiendo sobre arquitecturas de agentes. Sobre cómo un agente debería percibir su entorno, gestionar sus sensores, priorizar eventos, y recordar no como una lista de hechos sino como una historia con intencionalidad y trazabilidad. Ha sido un viaje conceptual en su mayor parte honesto: cada artículo describía ideas que estaba explorando, no sistemas que ya funcionaban.&lt;/p&gt;

&lt;p&gt;Pero había algo que no contaba. Que mientras escribía esos artículos, también estaba intentando construir el laboratorio donde probarlos.&lt;/p&gt;

&lt;p&gt;Este artículo es sobre ese laboratorio. Se llama Noema.&lt;/p&gt;

&lt;p&gt;Noema no es un producto. No es una herramienta lista para que cualquiera la use. Es mi &lt;em&gt;patio de juegos de IA&lt;/em&gt;. Un agente conversacional autónomo que he ido construyendo durante los últimos meses para validar si las ideas que publicaba aguantaban el paso a la realidad. Memoria narrativa trazable, sensores con filtrado inteligente, control voluntario de la percepción. Todo eso que sonaba tan bonito en los artículos, tenía que ver si se podía articular en un agente.&lt;/p&gt;

&lt;p&gt;Y como suele ocurrir cuando bajas de la teoría al código, el camino no fue el que esperaba.&lt;/p&gt;

&lt;p&gt;El propósito de este artículo no es contar cómo lo hice. Eso se puede mirar en los fuentes y en el &lt;a href="https://github.com/jjdelcerro/io.github.jjdelcerro.noema" rel="noopener noreferrer"&gt;README&lt;/a&gt; del repositorio. Tampoco es un tutorial paso a paso. Es una &lt;em&gt;presentación honesta&lt;/em&gt; de lo que encontré cuando intenté convertir mis propias ideas en algo que se pudiera ejecutar, probar y romper.&lt;/p&gt;

&lt;p&gt;Porque &lt;strong&gt;Noema está roto en muchos sitios&lt;/strong&gt;. Lo digo explícitamente en el repositorio. Pero hay cosas que ya funcionan. Y lo que funciona son precisamente parte de las piezas que más me interesa ir probando.&lt;/p&gt;

&lt;p&gt;Así que esto es lo que pasa cuando dejas de escribir sobre un sistema y te pones a construirlo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Un laboratorio que no viene de serie
&lt;/h2&gt;

&lt;p&gt;Todo empezó de forma engañosamente sencilla. Quería validar la idea central del sistema de memoria narrativa: que un LLM comprende mejor su historial si se le presenta como una crónica fluida, con citas a los turnos originales, que si se le pasa un resumen convencional.&lt;/p&gt;

&lt;p&gt;Para probar eso no necesitaba mucho, en teoría. Un bucle que leyese líneas de consola, las procesase, y de vez en cuando compactase la conversación en un "Punto de Guardado". Unas horas de código y listo.&lt;/p&gt;

&lt;p&gt;Lo que no calculé es que para validar si la compactación narrativa &lt;em&gt;funciona de verdad&lt;/em&gt;, no valen dos inputs de prueba. Necesitas conversaciones reales, densas, de varios mensajes, con cambios de tema, retomando hilos de hace una hora. Las preguntas triviales no estresan el sistema. Y esas conversaciones largas, con una interfaz de consola básica, eran un suplicio. Cada error, cada fallo en la compactación, tiraba por tierra una sesión de prueba de varias horas. Volver a empezar desde cero, una y otra vez.&lt;/p&gt;

&lt;p&gt;Así que empecé a añadir funcionalidad de configuración. Guardar el estado de la sesión entre reinicios. Poder ajustar parámetros sin tocar el código. Pequeñas cosas al principio. Pero la consola seguía siendo un obstáculo, sobre todo en la parte de configuración.&lt;/p&gt;

&lt;p&gt;Llegó un momento en que la interfaz de consola se me quedó corta y me dije que tocaba pasar a una GUI. Días enteros para montar la parte gráfica de la configuración, el diálogo de inicio, el sistema de selección de modelos. Nada de eso tenía que ver con probar la memoria narrativa. Era pura fontanería. Pero sin ella, las pruebas seguían siendo un caos.&lt;/p&gt;

&lt;p&gt;Cuando por fin tenía algo usable, empecé a darle capacidades reales al agente. Acceso al sistema de ficheros. Acceso a mis artículos y borradores. Y en cuanto me descuidé, el agente modificó algo que no debía. Perdí trabajo. Así que me detuve, estudié el problema, e implementé un mecanismo de control de versiones para cada escritura. Cada vez que el agente escribe en disco, queda un commit en el histórico. No estaba en el plan original. Pero después de perder ese trabajo, no podía seguir sin él.&lt;/p&gt;

&lt;p&gt;Este patrón se repitió varias veces. Cada problema real que aparecía en las pruebas generaba una necesidad de infraestructura que no estaba en el diseño inicial. La GUI, el sistema de configuración, el versionado, el scheduler, el control de acceso al sistema de ficheros. Capas y capas de fontanería que no aparecen en los artículos sobre arquitectura de agentes, pero sin las cuales el experimento no puede ejecutarse.&lt;/p&gt;

&lt;p&gt;Lo curioso es que esa fontanería no es un añadido accidental. Acabó siendo parte de la definición de Noema. Un agente que puede corromper tus archivos necesita un sistema de commits automáticos. Un agente con el que quieres conversar largamente necesita persistencia de estado. Un agente que accede a tus documentos necesita controles de acceso estrictos. Lo que empezó como una molestia se convirtió en un requisito arquitectónico.&lt;/p&gt;

&lt;p&gt;Al final, el laboratorio no vino de serie. Tuve que construirlo pieza a pieza, dejando que cada fallo me enseñara qué faltaba. Y lo que resultó no es solo el sistema que quería probar, sino también toda la infraestructura que lo hace posible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que Noema implementa (y lo que no)
&lt;/h2&gt;

&lt;p&gt;Así que después de algunas semanas de fontanería, de añadir GUI, persistencia, control de versiones y capas de seguridad, he acabado con un sistema sobre el que por fin parece que puedo probar las ideas que me habían llevado hasta allí. Un laboratorio con sus andamios puestos, listo para ser sometido a conversaciones reales.&lt;/p&gt;

&lt;p&gt;Noema implementa, en su estado actual, tres bloques conceptuales que ya había explorado en artículos anteriores. No son funcionalidades aisladas. Son las piezas que me interesaba validar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memoria narrativa trazable.&lt;/strong&gt;&lt;br&gt;
El corazón del sistema es un &lt;code&gt;MemoryService&lt;/code&gt; que genera lo que llamo "Puntos de Guardado". Este mecanismo, que describí en detalle en "&lt;a href="https://jjdelcerro.github.io/es/blog/disenando-memoria-narrativa-trazable-para-agentes-conversacionales/" rel="noopener noreferrer"&gt;Diseñando memoria narrativa trazable para agentes conversacionales&lt;/a&gt;", es lo que permite que Noema mantenga conversaciones que duran semanas sin perder el hilo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Percepción proactiva y filtrado sensorial.&lt;/strong&gt; &lt;br&gt;
Implementa la capacidad de reaccionar al entorno sin esperar a que el usuario pregunte. Actúa como el sistema nervioso autónomo del agente: recibe eventos de múltiples fuentes y los procesa antes de que lleguen al LLM.&lt;br&gt;
Este filtrado, que exploré en "&lt;a href="https://jjdelcerro.github.io/es/blog/como-gestionar-la-observacion-proactiva/" rel="noopener noreferrer"&gt;Control proactivo de la percepción en agentes de IA&lt;/a&gt;", evita que el agente se ahogue en su propia capacidad de escucha.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Seguridad y autonomía.&lt;/strong&gt;&lt;br&gt;
De la parte de seguridad no reflexioné en ninguno de mis artículos, pero fue haciendose necesaria con forme iba dándole al agente capacidades de interactuar con el entorno. Un agente con capacidad de escribir archivos y ejecutar comandos puede hacer mucho daño si se descuida. Esta capa de seguridad no es un añadido cosmético. Es lo que permite que el agente tenga autonomía real sin que cada interacción sea un riesgo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lo que no funciona.&lt;/strong&gt;&lt;br&gt;
Sería deshonesto no decirlo. Hay partes de Noema que están simplemente "dejadas caer", o directamente rotas.&lt;/p&gt;

&lt;p&gt;El servicio de documentos no está operativo. El cliente de correo y el bot de Telegram existen en el código pero no se han probado. La ejecución de comandos de shell utilizando &lt;code&gt;firejail&lt;/code&gt; está pendiente de testing. La búsqueda web depende de una API key que aún no he configurado nunca.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noema es un prototipo de investigación, no un producto&lt;/strong&gt;. Prefiero publicar un sistema con partes marcadas como "no funciona" que esperar a tenerlo todo pulido. Porque si espero a que esté perfecto, nunca lo publicaría.&lt;/p&gt;

&lt;p&gt;Con estas piezas funcionando ya tengo suficiente para ir probando lo que me interesaba. El resto puede esperar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por qué está construido así
&lt;/h2&gt;

&lt;p&gt;Cuando comente sobre Noema a algunos colegas, la primera pregunta solía ser: "¿Por qué Java?" En un mundo donde los prototipos de IA se escriben en Python con tres líneas de LangChain, volver a Swing y a compilaciones estáticas parece una rareza.&lt;/p&gt;

&lt;p&gt;La respuesta no es nostalgia. Es consecuencia directa de cómo creció el proyecto.&lt;/p&gt;

&lt;p&gt;Noema no fue diseñado de arriba abajo. Creció a &lt;em&gt;estirones&lt;/em&gt;. Cada nueva idea que quería probar, la memoria narrativa, los sensores, el filtrado de eventos, me obligaba a reestructurar partes profundas del sistema. En un lenguaje dinámico, esos cambios habrían sido una apuesta. En Java, el compilador actuaba como mi red de seguridad. Si después de una refactorización masiva el código compilaba, tenía una garantía razonable de que los contratos básicos seguían intactos.&lt;/p&gt;

&lt;p&gt;Esa necesidad de contratos claros se convirtió en un principio de diseño. Cada servicio en Noema está definido por una interfaz. No es burocracia. Es la única forma de mantener la coherencia cuando el sistema lleva ocho semanas cambiando cada fin de semana.&lt;/p&gt;

&lt;p&gt;El momento más duro llegó cuando decidí implementar el &lt;code&gt;SensorsService&lt;/code&gt; como una pieza de primera clase. Había escrito el artículo sobre cancelación y priorización de eventos, y sabía cómo quería que funcionase. Pero llevarlo al código implicó tocar casi todos los servicios existentes. Durante días, el proyecto ni siquiera compilaba. Horas y horas de ajustar dependencias, redefinir responsabilidades, mover lógica de un sitio a otro.&lt;/p&gt;

&lt;p&gt;Ese es el coste que no se menciona cuando se habla de "arquitectura limpia". El precio de ir de un sistema que funciona a medias pero compila, a uno mejor diseñado que de momento solo compila. Pero cuando al final todo encajó, la estructura resultante era más sólida que antes. El compilador había sido mi auditor, asegurándose de que ningún contrato se rompiera en el camino.&lt;/p&gt;

&lt;p&gt;JavaRCS es otro ejemplo de esta filosofía. Cuando el agente rompió mi primer borrador, busqué soluciones. Lo obvio era usar Git. Pero integrar Git habría significado una dependencia externa, romper la portabilidad del JAR, y añadir un sistema pensado para repositorios compartidos en un contexto de commits automáticos por cada escritura.&lt;/p&gt;

&lt;p&gt;Así que escribí mi propio sistema de control de versiones. Un RCS minimalista, implementado íntegramente en Java, que hace commit automático antes de cada modificación del agente. Fueron tres días peleándome con un bug en el parser de diferencias. Pero al final, conseguí que cada escritura de la IA dejara una traza recuperable, sin depender de nada que no estuviera dentro del propio JAR.&lt;/p&gt;

&lt;p&gt;El resultado es un Fat JAR. Un único archivo ejecutable que contiene el agente, sus dependencias, las bases de datos embebidas y el sistema de control de versiones. No necesita Docker. No necesita servicios externos. Solo Java 21. Puedo llevarlo a cualquier máquina, ejecutarlo, y tener un agente autónomo con memoria persistente, sensores y capacidad de razonamiento. Esa autonomía era el objetivo.&lt;/p&gt;

&lt;p&gt;Hay algo que no quiero ocultar. Noema no lo construí solo. Gemini me acompañó en todo el trayecto. No quiere decir que lo hiciese todo. De hecho, era un peligro dejarle hacer cosas por su cuenta. Solía no entender bien la arquitectura. Cuando algo no debía hacerse de cierta forma porque se acoplaba con otra funcionalidad... discutíamos. A veces durante horas, antes de consensuar y empezar a escribir una línea de código.&lt;/p&gt;

&lt;p&gt;Recuerdo los días en que definimos &lt;code&gt;ReasoningService&lt;/code&gt; y &lt;code&gt;Session&lt;/code&gt;: un tira y afloja hasta que las responsabilidades quedaron claras. Al final, después de dos días de discusión y varios intentos fallidos, implementé yo mismo el diseño de arriba abajo y se lo mostré: "ves, esto es lo que quería". Solo entonces entendió por qué lo quería así.&lt;/p&gt;

&lt;p&gt;El resultado de ese método, sin embargo, era otro que normalmente no se cuenta. Cuando el diseño estaba consensuado y le daba las guías, el código generado &lt;em&gt;casi siempre iba&lt;/em&gt;. La depuración se hacía sobre el &lt;em&gt;plano&lt;/em&gt;, no en &lt;em&gt;obra&lt;/em&gt;. Y aunque repasaba el código, el compilador actuaba como auditor final.&lt;/p&gt;

&lt;p&gt;Por eso Noema tiene esta forma. No es el camino más corto. Es el que me permitió construir un sistema complejo, mutarlo sin miedo, y tener la certeza de que cuando decía "funciona", era verdad.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por qué lo publico ahora
&lt;/h2&gt;

&lt;p&gt;Durante semanas me dio reparo publicar el repositorio. Un código a medias, con deuda técnica visible, con partes rotas documentadas sin pudor. No parecía "presentable".&lt;/p&gt;

&lt;p&gt;Le he dado vueltas y creo que ese reparo estaba equivocado.&lt;/p&gt;

&lt;p&gt;Lo que Noema tiene ahora, con todas sus imperfecciones, es algo interesante por si mismo. Una implementación real, funcional en sus partes centrales, de las ideas que describo en los artículos. No es un tutorial. No es un repositorio de ejemplo con datos limpios y un caso de uso simplificado. Es el sistema con el que trabajo, con su complejidad real, su deuda técnica real y sus decisiones de diseño documentadas tal como surgieron.&lt;/p&gt;

&lt;p&gt;Si los artículos describen el &lt;em&gt;por qué&lt;/em&gt; y el &lt;em&gt;cómo&lt;/em&gt; de estas arquitecturas, Noema es el &lt;em&gt;esto es lo que encontré cuando intenté construirlo&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Creo que hay un valor en mostrar los &lt;em&gt;andamios&lt;/em&gt; antes de que la obra esté terminada. Quizá más que en esperar a que todo esté perfecto, porque en un proyecto de investigación personal esa perfección nunca llega. Siempre hay un servicio más que implementar, un bug que corregir, una optimización que añadir. Si espero a que esté listo, nunca publicaría nada.&lt;/p&gt;

&lt;p&gt;Así que ahí está. El código, el README, y los andamios puestos.&lt;/p&gt;

&lt;p&gt;Para quien quiera entender la arquitectura en detalle, el punto de entrada es el &lt;a href="https://github.com/jjdelcerro/io.github.jjdelcerro.noema" rel="noopener noreferrer"&gt;README&lt;/a&gt; del repositorio. Ahí encontrará también enlaces a los artículos de la serie y una descripción honesta de lo que funciona y lo que no.&lt;/p&gt;

&lt;p&gt;El siguiente paso es seguir probando. Ahora que la fontanería parece que aguanta, toca ver si las ideas de verdad funcionan cuando se enfrentan a la realidad. Lo que tengo ya es suficiente para poner a prueba las piezas que más me interesaban: la consolidación narrativa y el filtrado sensorial. El resto de servicios irán madurando según los necesite. Ya tengo el patio de juegos montado, así que a jugar.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>java</category>
      <category>architecture</category>
      <category>ai</category>
    </item>
    <item>
      <title>Cuando la proactividad de un agente requiere cancelar y priorizar en su percepción</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Mon, 23 Mar 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/cuando-la-proactividad-de-un-agente-requiere-cancelar-y-priorizar-en-su-percepcion-2o0f</link>
      <guid>https://forem.com/jjdelcerro/cuando-la-proactividad-de-un-agente-requiere-cancelar-y-priorizar-en-su-percepcion-2o0f</guid>
      <description>&lt;p&gt;Hola,&lt;br&gt;
en el artículo anterior, "&lt;a href="https://jjdelcerro.github.io/es/blog/como-gestionar-la-observacion-proactiva/" rel="noopener noreferrer"&gt;Control proactivo de la percepción en agentes de IA&lt;/a&gt;", vimos que teniamos la necesidad de filtrar y procesar los eventos del exterior. Pero proteger al LLM de la sobrecarga no basta si el entorno envía información más rápido de lo que el LLM puede procesar. Necesitamos procesar la entrada de información, a gestionar "turnos", y decidir cuándo un evento merece interrumpir el dialogo con el LLM.&lt;/p&gt;

&lt;p&gt;Sin embargo, cuando sacas el patrón &lt;em&gt;pool_event&lt;/em&gt; del laboratorio y lo enfrentas a un sistema real, la arquitectura empieza a sufrir. Porque la proactividad no es solo un problema de atención; es, sobre todo, un problema de &lt;strong&gt;gestión de turnos&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  La ventanilla única del razonamiento síncrono
&lt;/h3&gt;

&lt;p&gt;Recordemos el patrón &lt;em&gt;pool_event&lt;/em&gt;. Es un "hack" elegante que permite al entorno hablar insertando un evento en el historial, simulando que el LLM lo había pedido. Funciona bien mientras el mundo ocurra a un ritmo pausado. Pero tiene una limitación estructural ya que convierte el historial en una &lt;em&gt;ventanilla única&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Si el LLM está inmerso en un diagnóstico complejo, el evento debe esperar en la cola. El problema es que el ciclo conversacion con el LLM es intrínsecamente síncrono y costoso, mientras que el &lt;em&gt;orquestador&lt;/em&gt; recibe estímulos de forma asíncrona y potencialmente masiva.&lt;/p&gt;

&lt;p&gt;Esta asincronía es, precisamente, la que en el artículo anterior dotamos de &lt;em&gt;inteligencia fisiológica&lt;/em&gt;. Ese &lt;em&gt;sistema nervio autonomo&lt;/em&gt; que tenía que filtrar, agregar y fusionar eventos para proteger al LLM de la saturación. Ahora nos enfrentamos a un problema de &lt;em&gt;turnos&lt;/em&gt;, no de volumen. El SNA puede tener la bandeja de eventos perfectamente ordenada y hasta cierto punto comprimida, pero si el LLM tarda diez segundos en responder, los eventos seguirán acumulándose. Cuando el LLM termine su ciclo, recibirá una descarga concentrada de eventos que, aunque bien empaquetada, puede llegar demasiado tarde o desbordar su capacidad de atención inmediata.&lt;/p&gt;

&lt;p&gt;Cuando los eventos llegan más rápido de lo que el LLM puede procesarlos, el sistema se ahoga en su propia cola. La información se vuelve obsoleta antes de ser atendida. Habíamos creado un sistema que podía escuchar, pero que se bloqueaba si el entorno hablaba demasiado rápido.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clasificar el caos mediante una taxonomía de urgencia
&lt;/h3&gt;

&lt;p&gt;Para que el agente no sea una víctima pasiva de esta cola, el &lt;em&gt;orquestador&lt;/em&gt;, el cuerpo del agente, debe dejar de ser un mero mensajero y convertirse en un componente inteligente. Si en el artículo anterior clasificamos los eventos por su &lt;strong&gt;naturaleza de tratamiento&lt;/strong&gt; (cómo se digieren, discretos, agregables, fusionables, de estado), ahora necesitamos clasificarlos por su &lt;strong&gt;grado de urgencia&lt;/strong&gt; (cuándo se atienden). Ambas taxonomías son complementarias. Una define la &lt;em&gt;fisiología&lt;/em&gt; de la percepción, la otra su &lt;em&gt;prioridad temporal&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;El primer paso es, por tanto, establecer una &lt;strong&gt;taxonomía basada en la urgencia y el impacto&lt;/strong&gt; que permita al orquestador decidir qué estímulos merecen interrumpir el curso del pensamiento. Podríamos empezar por una clasificación simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Eventos normales.&lt;/em&gt; Son el ruido de fondo o las actualizaciones de estado no críticas. El orquestador los acumula y, al final del ciclo de razonamiento actual, los inyecta como un bloque de información cohesivo. No interrumpen, no alteran el flujo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Eventos prioritarios.&lt;/em&gt; Indican que algo relevante ha ocurrido y debería atenderse en el próximo ciclo. Aquí el orquestador debe evaluar si es &lt;em&gt;"seguro"&lt;/em&gt; interrumpir. Podemos considerar que un ciclo es "seguro" para cancelar si el &lt;em&gt;LLM&lt;/em&gt; aún &lt;em&gt;no ha ejecutado ninguna herramienta con efectos secundarios&lt;/em&gt; (como escribir en un fichero o modificar una base de datos). Si es seguro, el orquestador puede cancelar el &lt;em&gt;pensamiento en curso&lt;/em&gt; de forma transparente y da paso a la nueva información. Si no es seguro, el evento prioritario espera su turno, igual que uno normal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Eventos urgentes.&lt;/em&gt; Estos justifican interrumpir el pensamiento a medias &lt;strong&gt;en cualquier instante&lt;/strong&gt;, independientemente de lo que esté haciendo el agente. Una alerta crítica de seguridad, una orden de parada de emergencia o un cambio de estado que invalida completamente la acción en curso. Para estos, no hay evaluación de "seguridad". El orquestador toma el mando y aborta la operación inmediatamente.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Observa lo que ocurre aquí: la decisión de &lt;strong&gt;cuándo&lt;/strong&gt; un evento merece interrumpir no la toma el LLM, sino el orquestador. Este evalúa la urgencia, consulta su registro de herramientas ejecutadas y decide si puede aplicar una cancelación limpia o debe notificar la interrupción. El LLM ni siquiera es consciente de que esta deliberación está ocurriendo. Para él, la realidad es que un evento ha llegado en el momento justo. Esta &lt;em&gt;soberanía del orquestador sobre la agenda del LLM&lt;/em&gt; es lo que permite que el sistema responda con &lt;em&gt;"reflejos"&lt;/em&gt;, sin esperar a que el LLN "pueda prestar atención".&lt;/p&gt;

&lt;p&gt;Esta taxonomía traslada, por tanto, la carga de la decisión del "pesado" LLM al orquestador, normalmente mas ágil en la toma de decisiones. Define una política clara: &lt;strong&gt;qué puede esperar, qué debería adelantarse si es posible y qué debe pararlo todo sin contemplaciones.&lt;/strong&gt; Y lo hace respetando la jerarquía que establecimos en el artículo anterior. El LLM puede ejercer un control voluntario sobre sus sentidos (mediante herramientas como &lt;code&gt;sensor_stop&lt;/code&gt;), pero el orquestador tiene siempre la autoridad para inyectar un evento clasificado como prioritario o urgente, saltándose cualquier filtro activo si las reglas de criticidad del sistema así lo requieren. La autonomía del agente en la gestión de su atención está, por tanto, acotada por la soberanía del sistema que lo alberga.&lt;/p&gt;

&lt;h3&gt;
  
  
  Los dos mecanismos de interrupción
&lt;/h3&gt;

&lt;p&gt;Una vez clasificado un evento como prioritario o urgente, el &lt;em&gt;orquestador&lt;/em&gt; debe materializar esa prioridad interrumpiendo el ciclo actual del LLM. Pero no todas las interrupciones son iguales. Distinguimos dos mecanismos fundamentales, basados en un único criterio: &lt;strong&gt;si el ciclo en curso ha ejecutado ya herramientas con efectos secundarios&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Cancelación segura.&lt;/em&gt;&lt;br&gt;
Se aplica cuando &lt;em&gt;no se ha ejecutado ninguna herramienta de escritura&lt;/em&gt;. El orquestador aborta la petición al LLM y realiza una "sanitización" del historial, eliminando por completo el último turno de conversación. A continuación, inyecta el nuevo evento (prioritario o urgente) y reinicia el ciclo.&lt;br&gt;
Como &lt;em&gt;Consecuencia&lt;/em&gt;, el LLM &lt;em&gt;nunca llega a enterarse&lt;/em&gt; de que fue interrumpido. Para él, es como si el evento hubiera llegado un instante antes de que empezara a pensar. Este mecanismo mantiene el historial limpio y coherente, y es la opción más eficiente en complejidad cognitiva, a costa de un consume extra de tokens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Cancelación insegura.&lt;/em&gt;&lt;br&gt;
Es la opción por defecto cuando &lt;em&gt;el ciclo ya ha ejecutado al menos una herramienta escritura&lt;/em&gt;, o cuando la política del sistema obliga a notificar una interrupción urgente. El orquestador aborta la petición, pero en lugar de borrar el turno, &lt;em&gt;inyecta una herramienta ficticia de consulta&lt;/em&gt; para informar al LLM. Como &lt;em&gt;Consecuencia,&lt;/em&gt; el LLM es &lt;em&gt;informado explícitamente&lt;/em&gt; de que sus operaciones fueron canceladas, y ve el motivo inmediatamente después. Esto preserva la coherencia narrativa a costa de un historial más largo y del coste de los tokens de la notificación.&lt;br&gt;
Este mecanismo asume que las herramientas de escritura ejecutadas dejan un estado que debemos aceptar. En futuras reflexiones sería interesante explorar cómo dotar a estas herramientas de mecanismos de compensación para aumentar la robustez del sistema frente a interrupciones.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En ambos casos, es el orquestador quien, basándose en su conocimiento del estado de ejecución, aplica la política de interrupción. El LLM simplemente &lt;em&gt;experimenta&lt;/em&gt; las consecuencias. En la cancelación segura, ni siquiera llega a saber que fue interrumpido, mientras que en la insegura, descubre &lt;em&gt;a posteriori&lt;/em&gt; que sus planes fueron abortados. Esta asimetría de información es precisamente la que permite agilizar los "reflejos". El orquestador no pide permiso, actúa.&lt;/p&gt;

&lt;p&gt;La elección entre un mecanismo y otro no es una decisión del LLM; es una &lt;em&gt;función de orquestación&lt;/em&gt; basada en su rastreo del estado del ciclo. Esta separación es lo que permite que un evento urgente sea a la vez &lt;em&gt;inmediato&lt;/em&gt; y &lt;em&gt;eficiente&lt;/em&gt; cuando la situación lo permite.&lt;/p&gt;

&lt;h3&gt;
  
  
  La herramienta de notificación de cancelación
&lt;/h3&gt;

&lt;p&gt;El mecanismo de &lt;em&gt;cancelación insegura&lt;/em&gt; requiere una forma elegante de comunicar la interrupción al LLM sin salirse del protocolo de herramientas. La solución es inyectar una herramienta ficticia: &lt;code&gt;haveCurrentOperationsBeenCancelled&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Esta herramienta no es un comando del sistema (como un &lt;code&gt;emergency_stop&lt;/code&gt;), sino una &lt;em&gt;consulta que simulamos que el propio LLM ha realizado&lt;/em&gt;. El orquestador la inyecta en el historial y proporciona inmediatamente la respuesta: &lt;code&gt;true&lt;/code&gt;. De este modo, el agente recibe una notificación en su propio lenguaje, y descubre que las operaciones que estaba realizando han sido canceladas.&lt;/p&gt;

&lt;p&gt;Sin embargo, esta notificación por sí sola podría llevar a un bucle patológico: si el LLM solo sabe que lo cancelaron, pero no el porqué, podría decidir reintentar la misma tarea, colisionando con la siguiente interrupción. Para evitarlo, el orquestdor &lt;em&gt;inyecta el evento urgente justo después de esta notificación&lt;/em&gt;. Así, el agente ve un flujo coherente: &lt;em&gt;"Mis operaciones fueron canceladas… porque ha ocurrido ESTO."&lt;/em&gt; Esta secuencia le permite reevaluar su plan anterior a la luz de la nueva emergencia y decidir racionalmente si reintentarlo o pasar a la nueva tarea.&lt;/p&gt;

&lt;p&gt;Esta herramienta es el pegamento que mantiene la coherencia narrativa en las interrupciones más disruptivas. Convierte un corte brusco en una transición gestionada, permitiendo que el LLM mantenga su sentido de la continuidad incluso cuando el orquestador ha tenido que tomar el control de manera abrupta.&lt;/p&gt;

&lt;h3&gt;
  
  
  El protocolo de interrupción para cancelar un pensamiento
&lt;/h3&gt;

&lt;p&gt;Con la taxonomía definida y los mecanismos de interrupción explicados, podemos ahora describir el protocolo concreto que el el orquestador, &lt;em&gt;el sistema nervioso autónomo&lt;/em&gt;, ejecuta cada vez que recibe un estímulo del entorno. Este no es un simple &lt;em&gt;if-else&lt;/em&gt;; es un algoritmo de gestión de estado que mantiene la coherencia entre el mundo asíncrono y el razonamiento síncrono del LLM.&lt;/p&gt;

&lt;p&gt;Flujo de decisión y acción del orquestador:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Recepción y clasificación.&lt;/em&gt; Al llegar un evento, el orquestador lo etiqueta como &lt;strong&gt;normal&lt;/strong&gt;, &lt;strong&gt;prioritario&lt;/strong&gt; o &lt;strong&gt;urgente&lt;/strong&gt;, según reglas preconfiguradas o políticas de la aplicación. Esta clasificación se basa en la taxonomía de urgencia, independientemente de la naturaleza del evento (discreto, agregable, etc.) que ya fue procesada en la capa fisiológica.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Evaluación del ciclo actual.&lt;/em&gt; El orquestador consulta su estado interno: &lt;em&gt;¿Se ha ejecutado ya alguna herramienta con efectos secundarios en este ciclo?&lt;/em&gt; La respuesta determina si el ciclo es &lt;em&gt;"seguro"&lt;/em&gt; para una cancelación transparente. Esta información la obtiene rastreando cada invocación de herramienta durante el ciclo en curso.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Aplicación de la política y selección del mecanismo&lt;/em&gt; 1:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si el evento es &lt;strong&gt;normal&lt;/strong&gt;, se añade a una cola de agregación para su procesamiento normal. El orquestador lo mantendrá en espera, posiblemente aplicando técnicas de empaquetado cuando llegue el momento de inyectarlo.&lt;/li&gt;
&lt;li&gt;Si el evento es &lt;strong&gt;prioritario&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Si el ciclo es &lt;em&gt;seguro&lt;/em&gt;, no han habido escrituras, se desencadena una &lt;em&gt;cancelación segura&lt;/em&gt;. El orquestador corta el flujo de tokens al LLM, sanitiza el historial eliminando el turno en curso y reintroduce el evento prioritario en un nuevo ciclo.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Si el ciclo &lt;em&gt;no es seguro&lt;/em&gt;, ya han habido escrituras, el evento se inyecta en la cola, pero no al final, si no como proximo evento a procesar, y espera al final del ciclo. El orquestador prioriza la integridad del estado sobre la inmediatez.&lt;/li&gt;
&lt;li&gt;Si el evento es &lt;strong&gt;urgente&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Si el ciclo es &lt;em&gt;seguro&lt;/em&gt;, se aplica una &lt;em&gt;cancelación segura&lt;/em&gt;, es la opción más eficiente y limpia.&lt;/li&gt;
&lt;li&gt;Si el ciclo &lt;em&gt;no es seguro&lt;/em&gt;, se aplica una &lt;em&gt;cancelación insegura&lt;/em&gt;. El orquesatdor aborta la petición, inyecta la herramienta &lt;code&gt;haveCurrentOperationsBeenCancelled&lt;/code&gt; con valor &lt;code&gt;true&lt;/code&gt;, inyecta inmediatamente el evento urgente a continuación, y reinicia el ciclo.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Ejecución y limpieza.&lt;/em&gt; Dependiendo del mecanismo seleccionado, el orquestador manipula el historial, gestiona las colas de eventos y, en el caso de la cancelación insegura, asegura que la secuencia de notificación y evento nuevo sea atómica dentro del historial. En todos los casos, el orquestador mantiene un registro de los eventos procesados para evitar bucles o reintentos infinitos.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Este protocolo hace explícito el compromiso entre capacidad de respuesta e integridad del estado. Toda cancelación tiene un coste inmediato: los tokens consumidos por el ciclo interrumpido se pierden. Sin embargo, una cancelación insegura añade capas de complejidad: el coste adicional de los tokens de notificación, la obligación de gestionar un estado potencialmente inconsistente y la posible necesidad de compensaciones futuras. Por el contrario, una cancelación segura es óptima en simplicidad: el sistema retorna a un estado conocido sin requerir ninguna intervención del LLM. La inteligencia del orquestador reside, por tanto, en maximizar las oportunidades para una cancelación segura, eligiendo ese camino siempre que la política (evento prioritario o urgente) y el estado (ciclo seguro) lo permitan.&lt;/p&gt;

&lt;p&gt;El orquestador se convierte así en un verdadero &lt;em&gt;sistema de control de ejecución&lt;/em&gt;. No es un mensajero, es un regulador que decide "rapidamente" si el LLM debe seguir pensando o si debe ser interrumpido. Es, en definitiva, la implementación de un &lt;em&gt;sistema nervioso autónomo artificial&lt;/em&gt; capaz de gestionar la agenda cognitiva del agente.&lt;/p&gt;

&lt;h3&gt;
  
  
  De mensajero a orquestador
&lt;/h3&gt;

&lt;p&gt;Este protocolo transforma al cliente de una librería de comunicación en un &lt;em&gt;controlador de estado con responsabilidades críticas&lt;/em&gt;. El orquestador, actuando como un &lt;em&gt;sistema nervioso autónomo&lt;/em&gt; asume funciones que van mucho más allá del simple encaminamiento de mensajes, así:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Mantiene la cola priorizada de eventos pendientes.&lt;/em&gt; No es una cola FIFO simple; es una estructura que respeta la taxonomía de urgencia, preserva el orden temporal dentro de cada categoría y aplica las políticas de agregación y fusión definidas por la naturaleza de cada sensor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Rastrea con precisión el estado de ejecución del ciclo.&lt;/em&gt; El orquestador debe saber, en cada momento, si el LLM ha ejecutado ya herramientas con efectos secundarios, cuántas lleva, y cuál es la última acción confirmada. Esta información es la que permite decidir entre cancelación segura e insegura.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Manipula el historial de conversación con precisión.&lt;/em&gt; Inserta o elimina turnos completos, inyecta herramientas ficticias, sanitizar el contexto sin romper la coherencia narrativa. Todo ello manteniendo la ilusión para el LLM de que la conversación fluye de forma natural.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Toma decisiones en milisegundos que equilibran urgencia e integridad.&lt;/em&gt; Cada evento entrante dispara un microciclo de evaluación ¿es normal, prioritario o urgente? ¿Es seguro cancelar? ¿Aplicamos cancelación limpia o notificamos la interrupción? Estas decisiones se toman por el orquestador, sin consultar al LLM, minimizando retrasos harian que la interrupción llegase demasiado tarde.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Empaqueta inteligentemente los eventos acumulados.&lt;/em&gt; Cuando el ciclo termina y toca inyectar los eventos normales o aquellos prioritarios que no pudieron adelantarse, el orquestador no hace un volcado bruto. Aplica técnicas de compresión semántica, como preservar los eventos más antiguos y los más recientes de una ráfaga, resumiendo el resto cuantitativamente, para que el LLM reciba un bloque de información cohesivo sin que su ventana de contexto se vea desbordada. Este "empaquetado sensorial" es la siguiente frontera en la gestión de la percepción, y apunta a resolver el problema de la inundación sin renunciar a la riqueza informativa.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Este es el "sistema nervioso" que estamos diseñando. Un orquestador de estado que media entre un mundo asíncrono y caótico y un razonamiento síncrono y pesado. Ya no estamos ante un chat que responde a comandos. Hemos diseñado los cimientos de un sistema reactivo autónomo, capaz de tomar el control de su propia percepción, priorizar el flujo del caos y, cuando la situación lo exige, abortar su propio proceso cognitivo para garantizar que la respuesta más crítica siempre llegue a tiempo.&lt;/p&gt;

&lt;p&gt;El siguiente paso sería explorar cómo dar robustez a esas herramientas que se quedan a medias, introduciendo mecanismos de compensación y transacciones. Pero esa, como suele decirse, será otra historia.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>agents</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Control proactivo de la percepción en agentes de IA</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Mon, 02 Mar 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/control-proactivo-de-la-percepcion-en-agentes-de-ia-2j2d</link>
      <guid>https://forem.com/jjdelcerro/control-proactivo-de-la-percepcion-en-agentes-de-ia-2j2d</guid>
      <description>&lt;p&gt;Hace unos meses publiqué un artículo, "&lt;a href="https://jjdelcerro.github.io/es/blog/agentes-de-ia-y-la-inyeccion-de-observaciones-proactivas-en-clientes-de-chat/" rel="noopener noreferrer"&gt;Agentes de IA y la inyección de observaciones proactivas en clientes de chat&lt;/a&gt;", donde presentaba el patrón &lt;code&gt;pool_event()&lt;/code&gt;, una forma de romper el ciclo reactivo de los LLMs permitiendo que el entorno "hable primero". Con esa arquitectura conseguimos que un agente pudiera recibir observaciones proactivas: mensajes de Telegram, alertas del sistema, correos electrónicos, todos ellos capaces de colarse en la conversación sin esperar a que el usuario preguntara. La idea funcionaba, y parecia hacerlo bien. El agente dejaba de ser un mero ejecutor de órdenes para convertirse en un sistema con capacidad de respuesta automática ante estímulos.&lt;/p&gt;

&lt;p&gt;Pero cada solución abre nuevas preguntas. La más inmediata saltó a la vista en cuanto empecé a simular escenarios con múltiples fuentes de eventos. Imaginemos un agente conectado a tres sensores: un lector de correo, un cliente de Telegram y un monitor de logs del sistema. Durante una hora de trabajo tranquilo, todo va bien. De repente, el servidor empieza a generar errores de conexión y los logs se disparan, cien eventos por segundo. El agente, fiel a su diseño, inyecta cada uno de esos eventos en el historial de chat. En pocos segundos la ventana de contexto se llena de basura técnica, el LLM pierde el hilo de la tarea que estaba realizando, el coste de tokens se dispara y el sistema se vuelve inútil justo cuando más se le necesita.&lt;/p&gt;

&lt;p&gt;Este escenario no es una rareza; es el riesgo natural de cualquier sistema abierto al entorno. Si dotamos a un agente de la capacidad de percibir, tenemos que dotarlo también de la capacidad de &lt;em&gt;gestionar&lt;/em&gt; lo que percibe. De lo contrario, su proactividad se convierte en un ataque de denegación de servicio autoinfligido.&lt;/p&gt;

&lt;p&gt;Las preguntas que guían este artículo es... &lt;em&gt;¿cómo diseñamos un agente que pueda recibir información del entorno sin ser desbordado por ella?&lt;/em&gt; ¿Qué mecanismos necesita para proteger su propia capacidad de razonamiento, para distinguir la señal del ruido y para decidir, de forma autónoma, cuándo debe escuchar y cuándo debe ignorar?&lt;/p&gt;

&lt;h2&gt;
  
  
  El sistema nervioso del agente
&lt;/h2&gt;

&lt;p&gt;Cuando nos enfrentamos al problema de la saturación sensorial, la tentación inmediata es buscar soluciones planas. Un filtro aquí o un límite de eventos por segundo allá. Pero la experiencia nos dice que los sistemas planos no escalan bien cuando la complejidad del entorno crece. Necesitamos una arquitectura con división de responsabilidades, y la biología nos ofrece ideas al respecto.&lt;/p&gt;

&lt;p&gt;En los organismos complejos, el sistema nervioso no es una masa homogénea que lo procesa todo con el mismo nivel de detalle. Está jerarquizado en dos grandes subsistemas que colaboran y se complementan.&lt;/p&gt;

&lt;p&gt;Por un lado está el &lt;strong&gt;Sistema Nervioso Central (SNC)&lt;/strong&gt;. Es el cerebro, la sede de la consciencia, el razonamiento y la voluntad. Cuando decidimos concentrarnos en leer un libro, es el SNC quien toma esa decisión. Pero el SNC tiene un coste energético alto y una capacidad de atención limitada. No puede procesar cada mínima variación del entorno.&lt;/p&gt;

&lt;p&gt;Por otro lado está el &lt;strong&gt;Sistema Nervioso Autónomo (SNA)&lt;/strong&gt;. Funciona en segundo plano, sin que tengamos que pensar en él. Regula el latido del corazón, la digestión y, lo que nos interesa aquí, filtra la información sensorial antes de que llegue a la consciencia. Cuando paseamos por una calle concurrida, el SNA procesa miles de estímulos y solo eleva a la consciencia aquellos que son relevantes. El claxon de un coche que se acerca o la voz de alguien que nos llama. El SNA protege al cerebro de la sobrecarga, permitiéndole dedicar sus recursos a lo que realmente importa.&lt;/p&gt;

&lt;p&gt;Esta división mas alla de ser un capricho es una necesidad arquitectónica que podemos trasladarla directamente al diseño de agentes de IA.&lt;/p&gt;

&lt;p&gt;En nuestro modelo, el &lt;em&gt;Sistema Nervioso Central&lt;/em&gt; del agente es el &lt;em&gt;LLM&lt;/em&gt;. Es la pieza capaz de razonar, planificar y mantener una conversación coherente. Pero también es la más cara y la que tiene un recurso escaso: la ventana de contexto. Cada token que ocupa un evento irrelevante es un token que roba a la capacidad de razonamiento. El SNC debería dedicarse a las tareas que realmente requieren inteligencia.&lt;/p&gt;

&lt;p&gt;El &lt;em&gt;Sistema Nervioso Autónomo&lt;/em&gt; del agente reside en el &lt;em&gt;orquestador&lt;/em&gt;, el código que gestiona la comunicación con el LLM, las herramientas y el estado interno. Es el cuerpo del agente. Su misión es recibir todos los estímulos del entorno en bruto y procesarlos antes de que lleguen al cerebro. No decide qué pensar, pero sí decide qué merece ser pensado. Puede aplicar reglas de filtrado, de agregación, de fusión. Puede mantener colas y estados. Puede, en definitiva, actuar como un guardián inteligente que protege al SNC de torrente sensorial.&lt;/p&gt;

&lt;p&gt;Un agente, por tanto, no es solo el LLM. Tampoco es solo el código que lo envuelve. Es el &lt;strong&gt;sistema completo&lt;/strong&gt;, la interacción entre un cerebro que razona y un cuerpo que percibe y filtra.&lt;/p&gt;

&lt;h2&gt;
  
  
  El procesamiento autónomo de la señal sensorial
&lt;/h2&gt;

&lt;p&gt;Una vez establecida la división entre sistema central y autónomo, toca descender al nivel del orquestador y preguntarnos ¿qué hace exactamente ese "cuerpo" del agente con los estímulos que recibe? La respuesta intuitiva sería "pasarlos al cerebro", pero eso es justo lo que nos mete en problemas. Un SNA que se limite a transmitir es un SNA que no cumple su función.&lt;/p&gt;

&lt;p&gt;El orquestador debe recibir los eventos en bruto y aplicar sobre ellos operaciones que reduzcan su volumen sin perder su significado. Eliminando redundancias sin sacrificar información crítica, y que entreguen al LLM un flujo depurado y contextualizado de eventos. Para ello, el SNA necesita conocer &lt;em&gt;la naturaleza de cada tipo de evento&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;No todos los estímulos son iguales. Un mensaje de Telegram no debe tratarse como un log del sistema, ni una alerta de correo como una lectura de sensor. Cada fuente de eventos tiene una semántica o una forma de ser interpretada propia. El SNA debe disponer de una suerte de &lt;em&gt;propiocepción&lt;/em&gt;: el conocimiento de sus propios sentidos y de las reglas que gobiernan su funcionamiento.&lt;/p&gt;

&lt;p&gt;Esta información puede estar codificada de diversas manera pero lo esencial es que el orquestador sepa, para cada evento que llega, a qué categoría pertenece y, por tanto, qué tipo de procesamiento debe aplicarle. Por ejemplo, el SNA "sabe" que los eventos procedentes de un monitor de logs son de naturaleza &lt;em&gt;agregable&lt;/em&gt;. Lo relevante no es cada línea individual, sino la frecuencia con la que aparecen y su distribución en el tiempo. También "sabe" que los mensajes de un chat son &lt;em&gt;fusionables&lt;/em&gt;: varios mensajes seguidos forman una única conversación, y deben presentarse juntos para conservar el sentido.&lt;/p&gt;

&lt;p&gt;Sobre esta base, el SNA puede aplicar una serie de operaciones sin que el LLM tenga que intervenir. Puede mantener colas por cada sensor, aplicar ventanas temporales, contar ocurrencias, concatenar textos con marcas de tiempo, descartar valores obsoletos. Todo ello ocurriendo en segundo plano, de forma continua, mientras el cerebro del agente está ocupado en tareas de razonamiento más profundas.&lt;/p&gt;

&lt;p&gt;Lo crucial es que estas operaciones no son arbitrarias. Responden a la naturaleza del sentido, no a una decisión momentánea del LLM. El SNA actúa como un sistema reflejo. Cuando llega un estímulo de cierto tipo, aplica la regla de tratamiento que su propia constitución le dicta. Estamos ante una &lt;em&gt;fisiología del agente&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taxonomía de tratamiento de eventos
&lt;/h2&gt;

&lt;p&gt;Una vez que el orquestador asume el rol de sistema nervioso autónomo, su primera tarea es comprender la naturaleza de los estímulos que recibe. No todos los eventos son iguales, ni deben ser tratados con las mismas reglas. Mezclarlos en un único flujo sin distinción es la receta perfecta para la confusión cognitiva. Necesitamos, por tanto, una &lt;em&gt;taxonomía de tratamiento&lt;/em&gt; que clasifique los eventos según su comportamiento semántico y permita al SNA aplicar la estrategia de procesamiento adecuada a cada uno.&lt;/p&gt;

&lt;p&gt;Esta clasificación emerge de la propia función que cada "sentido" del agente desempeña. Un sensor de logs no informa de lo mismo que un cliente de mensajería, y el SNA debe conocer esa diferencia. Podemos imaginar que cada fuente de eventos declara su naturaleza al orquestador, formando parte de esa "propiocepción" del sistema que mencionábamos antes. Con esa información, el SNA puede aplicar cuatro grandes modos de tratamiento:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Eventos discretos (el estándar).&lt;br&gt;
Son la categoría por defecto, la más simple y la que menos intervención requiere. Un evento discreto representa un hecho único. Su aparición es significativa por sí misma, y perder cualquier instancia supondría una pérdida de información crítica. El SNA los deja pasar sin transformación directamente al historial de conversación.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Eventos agregables (cuantificación).&lt;br&gt;
Hay situaciones en las que el valor informativo no reside en cada evento individual, sino en su frecuencia o volumen. Un monitor de logs del sistema puede generar cientos de entradas por segundo cuando algo empieza a ir mal. Si el SNA inyecta cada una de esas líneas en la conversación, en pocos segundos el LLM estará ahogado en un mar de texto repetitivo y el contexto habrá volado por los aires.&lt;/p&gt;

&lt;p&gt;Los eventos agregables son aquellos en los que podemos sustituir una secuencia de ocurrencias por un único evento que informe de la cantidad producida en un intervalo. El SNA los acumula en una ventana temporal, cuenta las ocurrencias y, transcurrido cierto umbral o cuando el LLM esté disponible, inyecta un mensaje del tipo: &lt;em&gt;"Se han producido 150 eventos de tipo 'error de conexión'"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Pero aquí hay un matiz crucial, y es el &lt;em&gt;tiempo&lt;/em&gt;. No es lo mismo recibir 150 errores en cinco minutos que en diez días. La misma cantidad puede significar cosas radicalmente distintas según la ventana en la que se produzca. La inyección debería ser algo así como: &lt;em&gt;"Se han registrado 150 eventos de tipo 'error de conexión' en los últimos 5 minutos (tasa media de 30 eventos/minuto)"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;El SNA, al agregar, no solo cuenta: añade contexto temporal. Convierte una avalancha de datos en un indicador de intensidad, preservando la información esencial sin saturar al cerebro.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Eventos fusionables (continuidad).&lt;br&gt;
Son otra familia de eventos tiene una naturaleza radicalmente distinta. Son los que forman parte de una secuencia narrativa. El ejemplo más claro es la mensajería instantánea. Cuando un usuario envía varios mensajes seguidos en un chat, cada mensaje individual es un evento, pero juntos constituyen una sola conversación. Si el SNA los inyecta por separado, el LLM recibirá algo como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mensaje 1: «Hola»&lt;/li&gt;
&lt;li&gt;Mensaje 2: «¿Estás?»&lt;/li&gt;
&lt;li&gt;Mensaje 3: «Necesito hablar contigo»&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esto fragmenta artificialmente lo que debería percibirse como un todo coherente. Además, multiplica innecesariamente el número de turnos en el historial.&lt;br&gt;
Los eventos fusionables permiten al SNA concatenar varios mensajes de una misma fuente en un solo bloque, preservando el orden y, lo que es más importante, las &lt;em&gt;marcas de tiempo individuales&lt;/em&gt;. El resultado sería algo así:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[10:05:01] Hola
[10:05:03] ¿Estás?
[10:05:07] Necesito hablar contigo
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;De este modo, el LLM recibe un paquete semántico completo, con toda la riqueza temporal de la secuencia, pero ocupando un solo "turno" en la conversación. El SNA ha realizado una fusión que respeta la naturaleza del sentido.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Eventos de estado / únicos (sustitución).&lt;br&gt;
Por último, tenemos eventos que representan una &lt;em&gt;condición&lt;/em&gt; más que una &lt;em&gt;ocurrencia&lt;/em&gt;. Pensemos en un sensor de correo electrónico. Cuando llega un nuevo mensaje, se genera un evento "tienes correo". Pero si mientras el LLM está procesando otra tarea llegan cinco correos más el LLM recibirá una secuencia de avisos redundantes y obsoletos en cuanto aparece el siguiente.&lt;/p&gt;

&lt;p&gt;Los eventos de estado (o eventos únicos) funcionan por &lt;em&gt;sustitución&lt;/em&gt;. El SNA mantiene internamente, para cada sensor de este tipo, el &lt;em&gt;último valor&lt;/em&gt; recibido. Cuando llega un nuevo evento, descarta el anterior de la cola (si aún no se había inyectado) y lo reemplaza por el nuevo. Así, cuando el LLM esté disponible para recibir información, solo verá el estado más actualizado: &lt;em&gt;"Tienes 6 correos sin leer"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Esta estrategia elimina la redundancia y evita que el agente actúe sobre información desactualizada. Es particularmente útil para sensores que notifican cambios de estado.&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Con esta taxonomía, el SNA dispone de un repertorio básico de operaciones para transformar el torrente sensorial en un flujo depurado y significativo. Cada evento, al llegar, es clasificado según su naturaleza y tratado con la estrategia correspondiente. El resultado es una reducción drástica del volumen de información que llega al LLM, sin pérdida de la riqueza semántica que cada tipo de evento requiere.&lt;/p&gt;

&lt;h2&gt;
  
  
  El control consciente de los sentidos
&lt;/h2&gt;

&lt;p&gt;Hasta ahora hemos reflexionado sobre como dotar al cuerpo del agente de la capacidad de procesar la señal sensorial de forma inteligente. El SNA sabe que los logs se agregan, que los mensajes de chat se fusionan, que los avisos de correo se sustituyen por su último valor. Todo esto ocurre en segundo plano, de forma refleja, sin que el cerebro tenga que intervenir. Es la fisiología del agente.&lt;/p&gt;

&lt;p&gt;Pero la autonomía real no se construye solo con reflejos. Un organismo que no puede controlar voluntariamente sus sentidos es un organismo esclavo de su entorno. Cuando necesitamos concentrarnos en una tarea compleja, cerramos los ojos o nos tapamos los oídos. Tomamos decisiones conscientes sobre qué estímulos merecen nuestra atención y cuáles deben ser ignorados, aunque estén presentes. Nuestro sistema nervioso central puede decirle al autónomo: "ahora silencia esto".&lt;/p&gt;

&lt;p&gt;Nuestros agentes necesitan esa misma capacidad. El LLM, como cerebro del sistema, debe poder ejercer su voluntad sobre los sentidos del cuerpo. Debe poder decir "durante los próximos treinta minutos, ignora todo lo que llegue de Telegram; estoy revisando un documento importante y no quiero distracciones". O bien: "reactiva el monitor de logs, necesito estar al tanto de cualquier error".&lt;/p&gt;

&lt;p&gt;Para ello, el orquestador expone un conjunto de herramientas que convierten el control sensorial en una acción más del repertorio del agente. Estas herramientas no actúan sobre el mundo exterior, sino sobre la propia arquitectura de percepción del sistema. Son herramientas de &lt;em&gt;metacognición&lt;/em&gt; que el agente usa para regular su propia actividad cognitiva.&lt;/p&gt;

&lt;p&gt;La primera de ellas, que ya presentamos en una sección anterior, es &lt;em&gt;&lt;code&gt;get_sensor_capabilities&lt;/code&gt;&lt;/em&gt;. A través de ella, el LLM puede obtener un inventario completo de sus sentidos: qué sensores están disponibles, a qué categoría pertenecen (discretos, agregables, fusionables, únicos), qué parámetros de configuración admiten y cuál es su estado actual. Es el equivalente a que un humano cierre los ojos y sienta su propio cuerpo. "Tengo ojos, los tengo abiertos; tengo oídos, los tengo tapados; tengo un sentido del equilibrio funcionando". Sin esta propiocepción, el control voluntario sería ciego.&lt;/p&gt;

&lt;p&gt;Sobre esa base, el LLM dispone de tres herramientas para la regulación activa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;code&gt;sensor_stop(channels, duration)&lt;/code&gt;&lt;/em&gt;. Ordena al SNA que suspenda temporalmente la recepción de eventos de uno o varios canales.  Durante ese período, el SNA descartará silenciosamente cualquier evento procedente de esos canales, como si el agente hubiera cerrado los párpados.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;code&gt;sensor_start(channels)&lt;/code&gt;&lt;/em&gt;. Reactiva los sensores previamente detenidos. Los eventos vuelven a fluir para su procesamiento habitual por parte del SNA.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;code&gt;sensor_status(channels)&lt;/code&gt;&lt;/em&gt;. Consulta el estado actual de uno o varios sensores. Devuelve información como: activo/inactivo, tiempo restante de desactivación (si la hay), estadísticas básicas de eventos recientes y cualquier otra métrica que el SNA haya ido acumulando. Esta herramienta permite al LLM tomar decisiones informadas. Antes de iniciar una tarea que requiera concentración, podría consultar qué sensores están especialmente ruidosos y decidir si conviene silenciar alguno.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Es importante notar que estas herramientas no modifican el comportamiento del SNA en lo que respecta al &lt;em&gt;tratamiento&lt;/em&gt; de los eventos. Cuando un sensor está activo, sus eventos siguen siendo procesados según su naturaleza: agregados, fusionados, convertidos a estado único, etc. La desactivación es una operación más drástica: es una compuerta que se cierra por completo. El SNA no acumula eventos mientras el sensor está detenido. Cuando se reactiva, el mundo sensorial vuelve a fluir desde cero, con el estado actual.&lt;/p&gt;

&lt;p&gt;Esta distinción entre &lt;strong&gt;procesamiento&lt;/strong&gt; (lo que hace el SNA siempre) y &lt;strong&gt;filtrado voluntario&lt;/strong&gt; (lo que ordena el SNC) es clave. El procesamiento es fisiológico, automático, basado en la naturaleza del sentido. El filtrado es voluntario, basado en las prioridades del momento.&lt;/p&gt;

&lt;h2&gt;
  
  
  De la reactividad a la autoregulación cognitiva
&lt;/h2&gt;

&lt;p&gt;Hemos recorrido un camino que empezó con una constatación incómoda: un agente capaz de percibir el entorno, pero sin control sobre esa percepción, es un agente condenado a la saturación. La misma proactividad que celebrábamos en el artículo anterior se convertía, en cuanto el entorno se volvía ruidoso, en una fuente de parálisis cognitiva. El agente escuchaba todo, pero precisamente por eso dejaba de entender nada.&lt;/p&gt;

&lt;p&gt;La solución no podía pasar por renunciar a la proactividad. Tenía que involucrar el dotar al agente de una arquitectura interna que le permitiera gestionar su propia percepción con la misma sofisticación con la que gestiona sus razonamientos. Inspirándonos en la biología, hemos propuesto una división fundamental entre dos sistemas que colaboran y se complementan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;El &lt;strong&gt;Sistema Nervioso Autónomo&lt;/strong&gt;, encarnado en el orquestador, actúa como el guardián fisiológico.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;El &lt;strong&gt;Sistema Nervioso Central&lt;/strong&gt;, el propio LLM, se reserva el control voluntario sobre esa percepción a través de herramientas como &lt;code&gt;sensor_stop&lt;/code&gt;, &lt;code&gt;sensor_start&lt;/code&gt; y &lt;code&gt;sensor_status&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esta separación cambia la naturaleza misma de lo que entendemos por "agente". Un agente ya no es un programa que reacciona a estímulos, ni siquiera un LLM con herramientas. Es un &lt;em&gt;sistema cognitivo complejo&lt;/em&gt;, con un cuerpo que filtra y procesa, y un cerebro que razona y decide. Entre ambos construyen lo que podríamos llamar &lt;em&gt;autoregulación cognitiva&lt;/em&gt;. La capacidad de mantener un equilibrio interno frente a las variaciones del entorno.&lt;/p&gt;

&lt;p&gt;Hemos puesto sobre la mesa los cimientos de esa autoregulación. Hemos definido una taxonomía de tratamiento que permite al cuerpo procesar la señal sin perder su significado. Y hemos dotado al cerebro de herramientas para regular su propia percepción. El agente que empieza a emerger de este diseño como un sistema con capacidad de autoprotección y con reflejos.&lt;/p&gt;

&lt;p&gt;Pero, como ocurre siempre en arquitectura, cada capa de solución revela una nueva capa de complejidad. Al dar al agente la capacidad de cerrar los ojos, hemos abierto una pregunta incómoda: &lt;em&gt;¿qué ocurre cuando, con los ojos cerrados, ocurre algo que no puede esperar?&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Al final, la autonomía real no es la capacidad de aislarse del entorno, sino la capacidad de relacionarse con él sin perderse a uno mismo. Y eso, como tantas cosas en la vida, es cuestión de equilibrio.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>Diseñando memoria narrativa trazable para agentes conversacionales</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Mon, 23 Feb 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/disenando-memoria-narrativa-trazable-para-agentes-conversacionales-14e9</link>
      <guid>https://forem.com/jjdelcerro/disenando-memoria-narrativa-trazable-para-agentes-conversacionales-14e9</guid>
      <description>&lt;p&gt;La semana pasada publiqué el artículo &lt;a href="https://jjdelcerro.github.io/es/blog/memoria-narrativa-o-resumen-para-un-llm/" rel="noopener noreferrer"&gt;"¿Memoria narrativa o resumen para un LLM?"&lt;/a&gt;. Contaba mi progresiva desilusión con los resúmenes como mecanismo para mantener conversaciones largas con un asistente de IA. Cómo, a fuerza de usarlos, empecé a notar que se perdía la intencionalidad de las decisiones, la cronología lógica de los razonamientos y los matices desaparecian en una simple lista de hechos. Contaba también que caí en la cuenta de que el problema no era cómo resumía, sino el hecho de resumir. Los LLMs, criaturas entrenadas con ingentes cantidades de prosa, narrativa y texto fluido, entienden mucho mejor cuando les das un texto con una narrativa fluida, cuando les cuentas una "historia".&lt;/p&gt;

&lt;p&gt;El artículo terminaba con el esbozo de una arquitectura de memoria de tres niveles, con un nivel medio, "El Viaje", que en lugar de ser un resumen era una "historia". Y con la idea de que si esa "historia" incorporara citas a los turnos originales, como las notas a pie de página en un artículo académico, podríamos tener lo mejor de los dos mundos. Por un lado la riqueza contextual de la narrativa y por otro la verificabilidad del dato.&lt;/p&gt;

&lt;p&gt;Pero una idea no es un diseño. Una intuición, por potente que sea, no se sostiene sin un protocolo que la haga funcionar de forma fiable, sin depender de que el LLM "tenga un buen día" o de que el prompt esté especialmente inspirado. Cuando llegué a esa conclusión, dediqué las siguientes semanas dedicado a convertir aquella sospecha en algo más sólido. Pasé de preguntarme "¿qué formato debería tener la memoria?" a preguntarme "¿cómo consigo que un LLM genere sistemáticamente ese formato?" Eso, como suele ocurrir cuando bajas al detalle, ha resultado ser un viaje con más recovecos de los que esperaba.&lt;/p&gt;

&lt;h2&gt;
  
  
  El falso amigo del resumen narrativo
&lt;/h2&gt;

&lt;p&gt;Una vez asumido que el resumen tradicional era un callejón sin salida, la siguiente tentación fue pensar que la solución era trivial. Si los resúmenes fallan, probemos con narrativa. En lugar de listas de puntos, pidámosle al asistente que nos cuente lo que hemos hablado como si fuera una historia.&lt;/p&gt;

&lt;p&gt;Así que lo intenté. Al final de varias sesiones, en lugar del habitual "resume esto", le pedí crónicas, relatos, narraciones que capturaran no solo los hechos sino también su evolución. Los resultados fueron desiguales. A veces obtenía textos excelentes, fluidos y matizados. Otras veces, la crónica era plana y desordenada o directamente incorrecta. Afiné los prompts, especifiqué con más detalle qué entendía por "historia". La tasa de aciertos mejoró ligeramente, pero la variabilidad se mantuvo. El modelo, sencillamente, no era fiable como cronista de sí mismo.&lt;/p&gt;

&lt;p&gt;Fue entonces cuando caí en la cuenta de que el problema no era de prompting, sino de fondo. Cuando yo le contaba a mi asistente lo que habíamos hablado, implícitamente le daba una estructura y una selección de lo relevante. En cambio, cuando le pedía al LLM que generara esa crónica a partir del historial crudo, le exigía que hiciera tres cosas a la vez, identificar lo relevante, ordenarlo causalmente y redactarlo con fluidez. Todo ello sin un esquema claro de qué esperaba. Era demasiado pedir.&lt;/p&gt;

&lt;p&gt;La conclusión a la que llegue fue que no basta con cambiar el prompt. La narrativa no puede ser un añadido cosmético sobre el mismo sistema de memoria. Para que funcione de forma fiable, necesita estar en el centro de la arquitectura, con un componente especializado y un protocolo bien definido. Dicho de otro modo, la intuición era correcta (los LLMs entienden mejor las historias), pero el camino para hacerla realidad no era pedirle al mismo modelo que además hiciera de cronista. Había que separar responsabilidades.&lt;/p&gt;

&lt;h2&gt;
  
  
  Los tres niveles de memoria
&lt;/h2&gt;

&lt;p&gt;Una vez aceptado que para resolver el problema tenia que repensar la arquitectura, empecé a dibujar esquemas. La idea de fondo era sencilla. Necesitamos separar aquello que es inmediato y volátil de aquello que es permanente y verificable, y en medio, algo que haga de puente. Lo que fue emergiendo es lo que ahora llamo los &lt;em&gt;tres niveles de memoria&lt;/em&gt;, y que ya anticipé en el artículo anterior, pero que aquí merece una explicación más detallada porque es la base de todo lo demás.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nivel 1: memoria de corto plazo (la sesión activa)
&lt;/h3&gt;

&lt;p&gt;Este es el más obvio y lo que cualquier chat hace por defecto: los últimos mensajes, el intercambio reciente, todo aquello que cabe en la ventana de contexto del modelo. Aquí no hay magia ni compactación. Es el historial crudo, tal como se produjo, con sus peticiones, sus respuestas, sus llamadas a herramientas y sus resultados. Su función es mantener la inmediatez. Permitir que el agente responda a lo que acaba de ocurrir sin necesidad de interpretar ni resumen. Es la memoria de trabajo, la que usamos mientras la conversación está caliente.&lt;/p&gt;

&lt;p&gt;En mis esquemas, este nivel acabo residiendo en una &lt;code&gt;Session&lt;/code&gt; que se mantiene en RAM y que se persiste en disco para sobrevivir a reinicios. Pero conceptualmente, es la parte más simple del sistema.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nivel 3: memoria de largo plazo (los turnos inmutables)
&lt;/h3&gt;

&lt;p&gt;En el extremo opuesto está la memoria permanente. Cada interacción, cada mensaje del usuario, respuesta del agente, llamada a una herramienta o resultado, se guarda en una base de datos. A cada uno de estos eventos se le asigna un identificador único, un &lt;code&gt;code&lt;/code&gt; (por ejemplo, &lt;code&gt;1042&lt;/code&gt;) que nunca cambia y que sirve como referencia canónica.&lt;/p&gt;

&lt;p&gt;Esta base de datos es la "fuente primaria". Contiene todo, pero es demasiado grande para leerla en cada interacción. Ahí están los datos originales, los números exactos, los fragmentos de código que se discutieron, las trazas de las herramientas. No se toca en el día a día, pero está disponible para cuando se necesita. Es, siguiendo la analogía del artículo académico, la biblioteca donde descansan las fuentes citadas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nivel 2: memoria de medio plazo ("El Viaje")
&lt;/h3&gt;

&lt;p&gt;Por otro lado, lo que fue emergiendo es lo que llamo el "&lt;em&gt;Punto de Guardado&lt;/em&gt;", un artefacto que actúa como la memoria consolidada del LLM. Su núcleo no es una lista de hechos, sino una sección llamada '&lt;em&gt;El Viaje&lt;/em&gt;', una crónica narrativa que cuenta la historia de la conversación desde la última compactación hasta el momento actual.&lt;/p&gt;

&lt;p&gt;Aquí es donde está la clave de todo. "El Viaje" &lt;em&gt;no es un resumen&lt;/em&gt;. No es una lista de puntos, una extracción de hechos o una versión comprimida y empobrecida de lo que pasó. Es una &lt;em&gt;crónica&lt;/em&gt;. Una narración que cuenta lo ocurrido preservando la intencionalidad, la evolución de las ideas, los giros conversacionales, los momentos de duda, las correcciones y el tono. Lo hace en el lenguaje que los LLMs entienden mejor. Una prosa fluida, con principio, desarrollo y, si procede, desenlace.&lt;/p&gt;

&lt;p&gt;Pero hay un matiz crucial. Esta crónica no es solo un ejercicio literario. En los puntos clave, allí donde una decisión se apoya en un dato concreto, donde un razonamiento cambia de dirección o donde aparece una idea que luego será relevante, la narrativa debe contener una &lt;em&gt;cita&lt;/em&gt; explícita al turno original (por ejemplo, &lt;code&gt;{cite: 1042}&lt;/code&gt;). Algo así:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;El usuario explicó que su sistema original no era un simple motor de reglas, sino que aprendía de un diccionario para construir una red semántica {cite: 6}. Fue entonces cuando surgió la pregunta clave: ¿era aquello una especie de LLM primitivo? {cite: 7}.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;De esta forma, "El Viaje" tiene lo mejor de ambos mundos. El LLM lee esta narrativa y se beneficia de su riqueza contextual. Entiende no solo qué pasó, sino por qué pasó, cómo se llegó a las conclusiones y qué matices hubo. Y si en algún momento necesita el detalle exacto puede seguir la cita, usar una herramienta especifica como &lt;code&gt;lookup_turn&lt;/code&gt; y recuperar el original de la base de datos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Por qué el nivel medio es el pegamento
&lt;/h3&gt;

&lt;p&gt;La metáfora que me ayudó a entenderlo vino del mundo académico. Un paper de investigación no incrusta las fuentes originales en el texto. Sería inmanejable. Lo que hace es contar una historia, la hipótesis, los experimentos y las conclusiones, y cuando necesita apoyarse en un resultado concreto, cita la fuente. El lector tiene así una experiencia de lectura fluida, pero con la seguridad de que, si quiere profundizar, puede acudir a la referencia.&lt;/p&gt;

&lt;p&gt;Eso es exactamente lo que hace "El Viaje". Es el texto del paper. Las citas son las notas al pie. Y la base de datos de turnos es la biblioteca.&lt;/p&gt;

&lt;p&gt;Con esta arquitectura, los tres problemas que identificaba en el artículo anterior se mitigan bastante:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;La &lt;em&gt;intencionalidad&lt;/em&gt; se conserva porque la narrativa explica no solo qué se hizo, sino por qué.&lt;/li&gt;
&lt;li&gt;La &lt;em&gt;cronología lógica&lt;/em&gt; se mantiene porque la historia respeta el orden causal de los acontecimientos.&lt;/li&gt;
&lt;li&gt;La &lt;em&gt;pérdida de detalle&lt;/em&gt; desaparece porque el dato, al compactarse, en lugar de perderse se cita. La narrativa puede permitirse el lujo de ser evocadora porque sabe que, si alguien necesita el dato exacto, tiene dónde encontrarlo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dicho de otro modo. El nivel medio es el pegamento que une la inmediatez del corto plazo con la permanencia del largo plazo. Es lo que permite que un agente tenga una conversación larga sin perder el hilo.&lt;/p&gt;

&lt;p&gt;Un detalle importante de esta arquitectura es su higiene. Cada vez que se genera un nuevo "Punto de Guardado", este sustituye tanto al anterior como al bloque de turnos que se acaba de compactar. De este modo, mantenemos el contexto limpio y predecible. En las sesiones futuras, el agente solo recibe el último "Punto de Guardado" y los nuevos mensajes que aún no han sido procesados, evitando que la ventana de contexto se sature de información redundante.&lt;/p&gt;

&lt;p&gt;Ahora bien, tener el esquema claro es una cosa. Conseguir que un LLM genere sistemáticamente "El Viaje" con la calidad y la precisión necesarias es otra muy distinta. Ahí es donde entra el &lt;em&gt;MemoryService&lt;/em&gt; y el protocolo que tuve que diseñar conseguir que hiciese lo que buscaba.&lt;/p&gt;

&lt;h2&gt;
  
  
  El arte de ser cronista
&lt;/h2&gt;

&lt;p&gt;Con los tres niveles de memoria ya definidos, la pregunta era quién y cómo generaba ese nivel medio, "El Viaje". Estaba claro que no podía ser el mismo modelo que llevaba la conversación diaria. Ya tenía bastante con razonar, responder y manejar las herramientas. Pedirle además que cada cierto tiempo, hiciera de cronista y condensara la historia en una narrativa coherente era sobrecargarlo. Y como ya había comprobado, pedirle que hiciera dos cosas a la vez rara vez sale bien.&lt;/p&gt;

&lt;p&gt;Necesitaba un componente especializado. Un servicio cuya única responsabilidad fuera la de tomar el historial reciente y el "Viaje" anterior, y generar un nuevo "Viaje" que integrara lo nuevo con lo antiguo de forma orgánica. En el esquema creció una nueva cajita, el &lt;em&gt;MemoryService&lt;/em&gt;. Probablemente con su propio modelo de lenguaje. En mis pruebas usé Gemini 2.5 Pro, pero podría ser cualquier LLM con suficiente capacidad.&lt;/p&gt;

&lt;p&gt;Tener un servicio dedicado no bastaba. Había que darle instrucciones muy precisas. Instrucciones que convirtieran la tarea vaga de "cuéntame lo que pasó" en un &lt;em&gt;protocolo&lt;/em&gt; con reglas claras y sobre todo, restricciones. Porque de lo contrario, el modelo haría lo que mejor hace, improvisar, inventar, resumir y su manera.&lt;/p&gt;

&lt;p&gt;Para que esto funcione, el Orquestador no le pasaria al LLM un volcado caótico de texto, sino una secuencia estructurada y eficiente de lo que llamo turnos atómicos, preparados para que el modelo pueda identificar los IDs de los turnos y su contenido y pueda procesarlos con el menor consumo de tokens posible.&lt;/p&gt;

&lt;h3&gt;
  
  
  El núcleo del protocolo
&lt;/h3&gt;

&lt;p&gt;El prompt que acabé construyendo después de muchas iteraciones se apoya en varios pilares que fui descubriendo sobre la marcha:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;1. "No me resumas, cuéntame la historia"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Puede parecer una perogrullada, pero es el primer filtro. El modelo tiende por naturaleza a la condensación, a la lista de puntos, al esquema. Hay que decirle explícitamente: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tu tarea TERMINA EXCLUSIVAMENTE cuando has capturado la atmósfera, las dudas y la evolución de las ideas. Si entregas una lista de puntos: HAS FALLADO. Si eres conciso: HAS FALLADO. Si narras la historia como un cronista detallado: HAS TENIDO ÉXITO.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Esta directiva, que en el prompt aparece con mayúsculas y cierto dramatismo, es la que marca la diferencia entre un resumen y una crónica.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;2. "Las citas van integradas, no al final"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Este fue uno de los aprendizajes más sutiles. Al principio, el modelo ponía las citas al final del párrafo, como una nota a pie. Pero eso rompe la fluidez y el lector (sea humano o LLM) no sabe qué punto exacto de la narración apoya la referencia. La directiva es clara:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Las citas deben integrarse en la narrativa para señalar el origen de una idea clave en el punto en el que aparezca la idea.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Y se muestra un ejemplo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✅ Correcto: &lt;code&gt;El punto de inflexión ocurrió cuando el usuario aclaró que su sistema aprendía del texto {cite: 6}, un detalle que cambió por completo la dirección de la conversación.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;❌ Incorrecto: &lt;code&gt;El punto de inflexión ocurrió cuando el usuario aclaró que su sistema aprendía del texto, un detalle que cambió por completo la dirección de la conversación. {cite: 6}&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;3. "Los flashbacks no son eventos nuevos"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Cuando el LLM usa una herramienta de memoria (&lt;code&gt;lookup_turn&lt;/code&gt; o &lt;code&gt;search_full_history&lt;/code&gt;) y recupera turnos antiguos, esos turnos se inyectan en la secuencia que recibe el MemoryService. Pero el modelo tiende a tratarlos como si fueran conversación nueva, perdiendo la noción de que son recuerdos. El protocolo le instruye:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No son eventos nuevos. Estos turnos son &lt;strong&gt;recuerdos&lt;/strong&gt;. El agente está releyendo su pasado en ese instante para informar su acción presente. ... Narra el acto de recordar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Y se le da un ejemplo de cómo debe quedar:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;El agente, para responder con precisión, &lt;strong&gt;consultó sus registros históricos&lt;/strong&gt; y recuperó la conversación original donde se detallaba la 'crisis de sentido' con SHRDLU {cite: 40}.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;4. "No alucines IDs"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Esta es una regla de hierro. El conjunto de identificadores &lt;code&gt;{cite:ID}&lt;/code&gt; que aparecen en el nuevo "Viaje" debe ser un subconjunto de los IDs que existen en la entrada (el "Viaje" anterior más los nuevos turnos). Si el modelo inventa una cita, todo el sistema de trazabilidad se viene abajo. El prompt lo dice sin ambages: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NO DEBES inventar, alucinar o modificar un ID.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Fragmentos reales del prompt
&lt;/h3&gt;

&lt;p&gt;Para que nos hagamos una idea, aquí dejo algunos fragmentos literales de cómo quedó el prompt después de muchas pruebas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## 2. Principios Fundamentales

Debes operar bajo los siguientes principios rectores:

*   **Principio de Coherencia Narrativa:** El nuevo Punto de Guardado debe leerse como una continuación lógica y natural del estado anterior.

*   **Principio de Trazabilidad Determinista:** Cada pieza de información significativa debe estar vinculada a su turno de origen mediante una referencia explícita (`{cite:ID}`).

*   **Principio de Fidelidad de Referencia:** El conjunto de todos los identificadores (`{cite:ID}`) presentes en el Punto de Guardado que generes **debe ser un subconjunto** del conjunto de IDs proporcionados en el contexto de entrada.
    *   **NO DEBES** inventar, alucinar o modificar un ID.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y más adelante, en la sección de calidad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**Directiva de Calidad Esencial para el Viaje**
Para esta sección, tu tarea **TERMINA EXCLUSIVAMENTE** cuando has capturado la atmósfera, las dudas y la evolución de las ideas.
*   Si entregas una lista de puntos: **HAS FALLADO** (Pérdida de contexto cognitivo).
*   Si eres conciso: **HAS FALLADO** (Pérdida de resolución).
*   Si narras la historia como un cronista detallado: **HAS TENIDO ÉXITO.**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Por qué este protocolo funciona
&lt;/h3&gt;

&lt;p&gt;Lo interesante de este enfoque es que no confía en la "bondad" del modelo. No le pide que sea creativo o que haga lo correcto porque sí. Le da un marco tan estricto que, aunque el modelo tienda a desviarse, las instrucciones actúan como una guía. Y cuando a pesar de todo se desvía (por ejemplo, inventando una cita), el orquestador tendrá que añadir una capa de validación posterior que lo detecta y lo rechaza.&lt;/p&gt;

&lt;p&gt;Esa capa de validación es la que comprueba que todas las citas del nuevo "Viaje" existen realmente en los datos de entrada. Si encuentra una cita huérfana, el proceso de compactación no ha sido correcto, habrá que ver que hacemos con esto, si se intenta de nuevo, o se marca el error para revisión. Es un mecanismo de seguridad que convierte una operación probabilística (un LLM generando texto) en un proceso determinista y verificable.&lt;/p&gt;

&lt;p&gt;Con el protocolo definido y el MemoryService funcionando, el siguiente paso era ponerlo a prueba con una conversación real. Y los resultados, como veremos, superaron mis expectativas.&lt;/p&gt;

&lt;h2&gt;
  
  
  La prueba de concepto
&lt;/h2&gt;

&lt;p&gt;Hasta aquí todo eran ideas. Pero una cosa es que algo funcione en la pizarra y otra muy distinta es que funcione cuando lo pones a prueba con una conversación real. Así que preparé un experimento.&lt;/p&gt;

&lt;p&gt;Cogí una conversación larga que había mantenido con mi asistente durante la preparación de un artículo. Una conversación que, además, tenía la particularidad de contener un &lt;em&gt;cambio de tema relevante&lt;/em&gt;. En un momento dado, pasamos de discutir los fundamentos de mi antiguo sistema de IA (algo muy personal y con mucho contexto acumulado) a adentrarnos en una exploración sobre lingüística y relativismo cultural. Exactamente el tipo de transición que pone a prueba la capacidad de un sistema de memoria para mantener la coherencia sin perder el hilo.&lt;/p&gt;

&lt;p&gt;Esa conversación la troceé en varios bloques, simulando el paso del tiempo y las compactaciones sucesivas. Estructure los turnos con sus códigos y luego invoqué al LLM (usando Gemini 2.5 Pro para las pruebas) siguiendo el protocolo que he descrito. El resultado fue el punto de guardado del que ahora os muestro un fragmento muy concreto. Justo el momento de la transición temática.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Con el proyecto ya bautizado y los fundamentos técnicos iniciales establecidos, la conversación tomó una nueva dimensión, alejándose momentáneamente de la implementación para sumergirse en las raíces mismas del lenguaje y el pensamiento. Esta fase comenzó con una pregunta clásica: ¿el lenguaje conforma nuestra manera de pensar o viceversa? {cite: 20}. La exploración concluyó que la visión más acertada es la de una influencia mutua y un ciclo de retroalimentación constante {cite: 24}.&lt;/p&gt;

&lt;p&gt;La indagación se profundizó, cuestionando si las categorías gramaticales que nos son familiares, como "sujeto que realiza una acción", son universales {cite: 21}. La revelación de la existencia de marcos conceptuales radicalmente distintos, como las lenguas ergativo-absolutivas que no se centran en el "sujeto" sino en el "agente" frente al "paciente", fue un punto clave {cite: 22}. Esto llevó a cuestionar directamente la hipótesis de una "estructura profunda común" o Gramática Universal chomskiana {cite: 23}. La conversación se inclinó hacia la idea de que la diversidad lingüística es genuina y no una mera variación superficial, reflejando distintas formas de categorizar la experiencia {cite: 26}.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fijaos en lo que tenemos aquí.&lt;/p&gt;

&lt;p&gt;Primero, la &lt;em&gt;fluidez narrativa&lt;/em&gt;. No hay un corte brusco, no hay un "cambio de tema" anunciado con un ladrillo. La transición se construye con un conector narrativo: &lt;em&gt;"Con el proyecto ya bautizado... la conversación tomó una nueva dimensión"&lt;/em&gt;. El lector (sea humano o LLM) percibe una continuidad, no una ruptura.&lt;/p&gt;

&lt;p&gt;Segundo, las &lt;em&gt;citas integradas&lt;/em&gt;. No están al final del párrafo. Están incrustadas en el momento exacto donde la idea aparece: &lt;code&gt;{cite: 20}&lt;/code&gt; junto a la pregunta sobre lenguaje y pensamiento, &lt;code&gt;{cite: 22}&lt;/code&gt; junto al descubrimiento de las lenguas ergativas, &lt;code&gt;{cite: 26}&lt;/code&gt; al final de la reflexión. El sistema de referencias no interrumpe la lectura, pero está ahí, disponible para quien quiera verificar o profundizar.&lt;/p&gt;

&lt;p&gt;Tercero, lo más importante: &lt;em&gt;verifiqué que todas las citas son reales&lt;/em&gt;. Cada uno de esos números corresponde a un turno que existía en los datos de entrada. El LLM no inventó ni una sola referencia. El principio de fidelidad se cumplió a rajatabla.&lt;/p&gt;

&lt;p&gt;Lo potente de este sistema no es solo que el asistente 'recuerde' el tema, sino que, gracias a esas citas, puede realizar una rehidratación de la memoria. Si en el futuro necesita recuperar el detalle técnico exacto de una discusión antigua, solo tiene que seguir el hilo de la cita para traer de vuelta el turno original de la base de datos.&lt;/p&gt;

&lt;p&gt;Un detalle. Ese hilo conversacional sobre lingüística no se quedó en una mera charla. Acabó formando parte de las notas con las que escribí el articulo "&lt;a href="https://jjdelcerro.github.io/es/blog/podemos-usar-la-gramatica-para-modelar-el-conocimiento/" rel="noopener noreferrer"&gt;¿Podemos usar la gramática para modelar el conocimiento?&lt;/a&gt;" unas semanas mas tarde.&lt;/p&gt;

&lt;p&gt;Ahora bien, conviene ser honesto sobre el alcance de esta prueba. Esto es una &lt;em&gt;validación conceptual&lt;/em&gt;, no una demostración de que el sistema funciona integrado en un agente real. Los puntos de guardado se generaron en un entorno controlado. Sin la complejidad de una sesión viva con herramientas, &lt;em&gt;eventos&lt;/em&gt; y &lt;em&gt;proactividad&lt;/em&gt;. El siguiente paso sería ver como integrar este mecanismo en un agente real.&lt;/p&gt;

&lt;p&gt;Pero lo que ya tenía era una base sólida. El protocolo funciona. Generaba narrativas coherentes, trazables y sin alucinaciones. El diseño había pasado la primera prueba.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que viene después
&lt;/h2&gt;

&lt;p&gt;Había recorrido un buen trecho desde aquella insatisfacción inicial con los resúmenes hasta el punto en que me encontraba ahora. Hemos visto por qué llegue a la conclusión de que la narrativa no es un simple cambio de prompt. Por qué necesitamos tres niveles de memoria. Y cómo el nivel medio, "El Viaje", actúa como pegamento entre la inmediatez del corto plazo y la permanencia del largo plazo. Hemos visto las ideas que hicieron que el protocolo permita a un LLM especializado generar esas crónicas con la precisión y la trazabilidad necesarias. Y hemos contemplado los resultados tangibles de ese protocolo: unos puntos de guardado reales, generados por Gemini 2.5 Pro, que demuestran que la idea es viable y que las citas se mantienen fieles a los turnos originales.&lt;/p&gt;

&lt;p&gt;Ahora tocaba ponerlo a prueba en el terreno, porque la verdadera validación de una idea ocurre cuando compila, se ejecuta y se enfrenta a la realidad. Integrar esta memoria narrativa en un agente y ver cómo se comporta cuando se enfrenta a herramientas, eventos y conversaciones largas. Contar esto será el siguiente viaje&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>llm</category>
      <category>architecture</category>
    </item>
    <item>
      <title>¿Memoria narrativa o resumen para un LLM?</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Mon, 16 Feb 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/memoria-narrativa-o-resumen-para-un-llm-5aeg</link>
      <guid>https://forem.com/jjdelcerro/memoria-narrativa-o-resumen-para-un-llm-5aeg</guid>
      <description>&lt;p&gt;Durante los últimos meses he mantenido una conversación continua con el mismo asistente de IA. No era un chat esporádico, de esos que se abren para una consulta rápida y se cierran para siempre. Era mi compañero de reflexiones. Un colaborador con el que discutía arquitectura de software, diseños de agentes, y a veces, fundamentos filosóficos de la inteligencia artificial.&lt;/p&gt;

&lt;p&gt;Pero había un problema. Los modelos de lenguaje tienen una ventana de contexto limitada. Pasados unos treinta o cuarenta intercambios, el principio de la conversación se desvanecía. Para un proyecto de larga duración, eso era un obstáculo continuo. Así que hice lo que muchos ya hacían y empecé a pedir resúmenes.&lt;/p&gt;

&lt;p&gt;Cada cierto tiempo, le solicitaba al asistente que condensara lo hablado en unos párrafos. Guardaba ese texto y lo inyectaba al inicio de la siguiente sesión. Durante un tiempo funcionó. O al menos, eso creía.&lt;/p&gt;

&lt;p&gt;Con el uso continuado, empecé a notar algo extraño. El asistente recordaba los hechos, sí. Pero las respuestas habían perdido matiz. Había decisiones que parecían flotar sin motivo, ideas que surgían sin contexto, y un tono general de "sé lo que pasó, pero no sé por qué pasó". Como si alguien hubiera resumido una novela unos pocos párrafos y luego pretendiera entender las motivaciones de los personajes.&lt;/p&gt;

&lt;p&gt;Al principio lo atribuí a mi técnica. Pensé que tenía que mejorar los prompts de resumen. Que tenía que ser más cuidadoso. Pero cuanto más afinaba el proceso, más evidente se hacía la sospecha de que el problema no era cómo resumía, sino que resumía.&lt;/p&gt;

&lt;p&gt;¿Y si la memoria para un LLM necesitaba ser otra cosa? ¿Y si el formato, y no la cantidad, era lo que estaba matando la continuidad?&lt;/p&gt;

&lt;h3&gt;
  
  
  Por qué el resumen es un placebo
&lt;/h3&gt;

&lt;p&gt;Durante meses perfeccioné mi técnica de resúmenes. Cada vez que la conversación se acercaba al límite de la ventana de contexto, pedía al asistente que condensara lo hablado. Guardaba ese texto, lo etiquetaba, y lo inyectaba al principio de la siguiente sesión. Era meticuloso. Y durante un tiempo, funcionó.&lt;/p&gt;

&lt;p&gt;O eso creía.&lt;/p&gt;

&lt;p&gt;Con el uso continuado, empezaron a aparecer grietas. Pequeñas al principio. Un matiz que se perdía. Una decisión que parecía menos justificada de lo que recordaba. Pero con el tiempo, las grietas se hicieron más grandes. Identifiqué tres fallos fundamentales que el resumen, por su propia naturaleza, no puede evitar.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;La pérdida de intencionalidad.&lt;/li&gt;
&lt;li&gt;El aplanamiento de la cronología lógica.&lt;/li&gt;
&lt;li&gt;El "efecto fotocopia".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Un resumen cuenta qué pasó. Muchas veces el valor no solo está en el qué, sino en el porqué. Una decisión arquitectónica rara vez es un hecho aislado. Es la consecuencia de un conjunto de restricciones, pruebas fallidas, e intuiciones. Cuando el resumen dice "se optó por memoria narrativa en lugar de resúmenes", está diciendo la verdad, pero no toda la verdad. La verdad completa es: "se optó por memoria narrativa porque los resúmenes provocan pérdida de contexto en las pruebas de rehidratación". Sin esa causa la decisión parece arbitraria. Y un agente que no entiende las causas de las decisiones está condenado a repetir errores o, peor aún, a deshacer lo que con tanto esfuerzo se construyó.&lt;/p&gt;

&lt;p&gt;Tanto en tareas de investigación como en el desarrollo de software el orden de los factores puede alterar el producto. No es lo mismo que una restricción aparezca antes o después de una decisión de diseño. El resumen trata los eventos como elementos intercambiables. Los ordena pero pierde la jerarquía causal. Un resumen típico diría: "Se descartó la opción A. Luego se implementó B". Pero lo importante es que B se implementó &lt;em&gt;porque&lt;/em&gt; A fracasó en el escenario X. Esa relación causal es la que da sentido al proceso. El resumen la reduce a una secuencia temporal plana.&lt;/p&gt;

&lt;p&gt;Además, cada vez que se resume un nuevo juego de turnos con su resumen inicial se pierde información. Es inevitable. Como las fotocopias sucesivas de un documento, la calidad se degrada. Los ejemplos concretos se convierten en generalidades, y las dudas pueden acabar convirtiéndose en afirmaciones rotundas. Al cabo de varias compactaciones, lo que queda es una sombra de lo que fue la conversación original. El agente no recuerda; sólo tiene una vaga impresión. Y muchas veces demasiado vaga.&lt;/p&gt;

&lt;p&gt;Hay un cuarto problema, más sutil, que sólo empecé a comprender cuando analicé cómo funcionan realmente los LLMs. Los resúmenes suelen adoptar la forma de listas de puntos o viñetas. Es un formato cómodo para los humanos, pero para un LLM es un ejercicio de traducción forzada. El modelo está entrenado con prosa, con narrativa y con texto fluido donde las ideas se entrelazan. Cuando le das una lista, le estás pidiendo que opere como un motor de reglas. Diciéndole que extraiga conclusiones de datos estructurados. No es que no pueda hacerlo, solo no es su fuerte, especialmente en tareas que requieren captar causalidad implícita, evolución de ideas o matices conversacionales. Es como pedirle a un novelista que escriba un informe de laboratorio. Puede hacerlo, pero no estás aprovechando su verdadera capacidad.&lt;/p&gt;

&lt;p&gt;Durante un tiempo confié en los resúmenes. Poco a poco noté que algo no funcionaba, pero lo atribuía a mi técnica, a mi forma de pedirlos o a la calidad del modelo. Hasta que un día, comparando dos sesiones separadas por varias semanas, caí en la cuenta. El resumen era un placebo. Me daba la tranquilidad de haber guardado algo, pero en realidad había perdido lo esencial.&lt;/p&gt;

&lt;p&gt;La pregunta entonces fue ¿qué formato debería tener la memoria de un cliente de LLM para que el LLM la entienda de verdad?&lt;/p&gt;

&lt;h3&gt;
  
  
  El LLM es un lector de historias
&lt;/h3&gt;

&lt;p&gt;La respuesta llegó por un camino inesperado. Un día tuve que recordarle lo que habíamos estado hablando unos días atrás para continuar donde nos quedamos. Me puse a escribir y &lt;em&gt;se lo conté&lt;/em&gt;. Captó la idea y pudimos continuar más o menos donde lo dejamos. Al finalizar la conversación le pedí el resumen y lo guardé. Unos días más tarde quise reanudar el estudio así que le pase el resumen a otro LLM y trate de continuar. Fue un caos. Me quedé pensando un rato... aún tenía la conversación de unos días antes... fui y la guarde, y me quede pensando que había pasado. &lt;/p&gt;

&lt;p&gt;Fue entonces cuando me di cuenta de la diferencia. Para poner en contexto al LLM le &lt;em&gt;habia contado&lt;/em&gt; lo que habíamos estado hablando. No le había pasado un resumen. Así que cogí la conversación, esa de la que había sacado un resumen y no había funcionado para poder seguir desde el, y me volví a escribir lo que se decía en ella, contándolo, sin resumen. Pasarle eso a un LLM para continuar donde lo dejamos funcionaba y el resumen no.&lt;/p&gt;

&lt;p&gt;Con los resúmenes, el asistente recuperaba los hechos, pero las respuestas eran mecánicas, como si alguien le hubiera dado una lista de ingredientes y esperara que adivinara la receta. Con las crónicas contadas de lo hablado el tono cambiaba. Las respuestas tenían matices, reconocían implícitamente el contexto, e incluso a veces añadían reflexiones que conectaban con ideas anteriores que yo mismo había olvidado.&lt;/p&gt;

&lt;p&gt;Empecé a preguntarme por qué.&lt;/p&gt;

&lt;p&gt;Los transformers, la arquitectura que sostiene a los LLMs actuales, se entrenan con cantidades ingentes de texto. Novelas, artículos, ensayos, conversaciones, documentación técnica redactada en prosa. La narrativa preserva relaciones causales implícitas mejor que las estructuras de listas. El modelo aprendido a predecir la siguiente palabra en secuencias que tienen ritmo y evolución de ideas. Aprende a detectar cuándo un personaje duda, cuándo un argumento se refuerza, cuándo una decisión es consecuencia de algo anterior.&lt;/p&gt;

&lt;p&gt;En otras palabras, el transformer está optimizado para entender historias.&lt;/p&gt;

&lt;p&gt;La evidencia empírica de mi propio experimento lo confirmaba. Cuando la memoria que inyectaba era una historia, con sus giros, sus momentos de duda, sus conclusiones, el tono, el asistente además de recordar &lt;em&gt;reconstruía&lt;/em&gt; el hilo de pensamiento. Podía referirse a problemas discutidos semanas atrás y tratarlos con la familiaridad de quien los ha vivido en primera persona.&lt;/p&gt;

&lt;p&gt;No hacía falta ser un investigador de IA para ver la diferencia. El LLM &lt;em&gt;entendía&lt;/em&gt; mejor cuando le hablaban en su idioma.&lt;/p&gt;

&lt;p&gt;Esa es la tesis que sostiene todo lo que vino después. La memoria para un agente no debe ser un archivo de datos, sino una narrativa viva. El modelo que va a leer esa memoria no es un procesador de registros. Es un lector de historias. Y como todo lector, cuando la historia está bien contada, se sumerge en ella y la hace suya.&lt;/p&gt;

&lt;p&gt;Aquí aparece todo un reto. Yo podía contar lo que habíamos estado hablando, pero si le pedía al LLM que lo contase... fallaba. Requirió bastantes intentos antes de conseguir la forma de pedirle al LLM que me contase lo que habíamos estado hablando, y no todos los modelos eran capaces de hacerlo. Resulta que hacer que un LLM sea un buen cronista de sí mismo requiere más sutileza de la que esperaba&lt;/p&gt;

&lt;h3&gt;
  
  
  La necesidad de trazabilidad
&lt;/h3&gt;

&lt;p&gt;A estas alturas, alguien podría objetar: "De acuerdo, la narrativa funciona mejor. Pero una historia, por bien contada que esté, siempre es una versión. Una interpretación. ¿Dónde quedan los datos originales? ¿Dónde queda el detalle exacto de aquella decisión, aquel resultado numérico, aquel fragmento de código que discutimos?"&lt;/p&gt;

&lt;p&gt;La objeción es legítima. Si nos quedamos sólo en la narrativa, cambiamos un problema por otro. El resumen pecaba de pobreza semántica; la narrativa sola podría pecar de imprecisión verificable. Necesitábamos un mecanismo que combinara lo mejor de ambos mundos: la riqueza contextual de la historia contada con la fiabilidad del dato original.&lt;/p&gt;

&lt;p&gt;La solución llegó por una analogía que llevo viendo toda la vida, la escritura académica.&lt;/p&gt;

&lt;p&gt;Cuando leemos un artículo o un estudio este no tiene incrustadas las fuentes originales completas en las que se basó en el texto. Sería inmanejable. Se extraen las ideas principales, se adaptan a nuestro discurso y las integramos en nuestra narrativa. Pero cuando un dato es especialmente relevante, o cuando una afirmación descansa sobre una fuente concreta, se cita. Se deja una referencia explícita que permite al lector acudir al original y comprobar el contexto completo.&lt;/p&gt;

&lt;p&gt;Un paper no es sólo su texto; es también sus notas al pie, su bibliografía, el entramado de referencias que lo anclan a la realidad verificable.&lt;/p&gt;

&lt;p&gt;Esa misma estructura podía aplicarse a la memoria del cliente del LLM.&lt;/p&gt;

&lt;p&gt;La narrativa cuenta la historia de lo ocurrido con todo el detalle semántico que el LLM necesita para entender. Pero en los puntos clave, allí donde una decisión se apoya en un dato concreto, habría que insertar una cita. Una referencia al turno original de la conversación donde ese dato apareció por primera vez.&lt;/p&gt;

&lt;p&gt;De esta forma, el LLM tiene lo mejor de ambos mundos. Cuando opera en modo normal, lee la narrativa y se beneficia de su riqueza contextual. Si necesita el detalle exacto, el número preciso o la redacción literal de una petición, puede seguir la cita y recuperar el turno original de la conversación, que estaría almacenado en una base de datos de memoria a largo plazo. &lt;/p&gt;

&lt;p&gt;La narrativa aporta la comprensión, mientras que las citas aportan la verificabilidad&lt;/p&gt;

&lt;h3&gt;
  
  
  Arquitectura de la memoria
&lt;/h3&gt;

&lt;p&gt;El camino desde aquella insatisfacción inicial hasta el esquema que ahora tengo en mente no fue lineal. Hubo pruebas fallidas, ideas que parecían brillantes y resultaron callejones sin salida, y noches dándole vueltas a la misma pregunta. Pero poco a poco, el sistema se fue dibujando con claridad.&lt;/p&gt;

&lt;p&gt;Lo que necesitaba no era una solución única, sino una arquitectura de memoria con tres niveles, cada uno con su función y su formato.&lt;/p&gt;

&lt;p&gt;En el primer nivel tendríamos la memoria de corto plazo.&lt;br&gt;
Son los últimos mensajes de la conversación, el intercambio reciente que aún cabe en la ventana de contexto. Aquí no hay magia. Es el historial crudo, tal como se produjo. Su función es mantener la inmediatez, permitir que el agente responda a lo que acaba de ocurrir sin necesidad de compresión ni interpretación.&lt;/p&gt;

&lt;p&gt;En el segundo nivel tendríamos la memoria de medio plazo.&lt;br&gt;
Es "El Viaje". La narrativa que cuenta la historia de lo acontecido desde la última compactación del historial hasta ahora. No es un resumen al uso. Es una crónica que preserva la intencionalidad, la cronología lógica, la evolución de las ideas, los giros o el tono de la conversación. Y lo hace en el lenguaje natural que los LLMs entienden mejor, la prosa. Cada afirmación importante, cada decisión clave, cada dato que pueda ser necesario recuperar con precisión, va acompañado de una cita que señala su origen.&lt;/p&gt;

&lt;p&gt;El tercer nivel tendríamos la memoria de largo plazo.&lt;br&gt;
Son los turnos crudos, almacenados íntegros en su formato original. No se leen en el día a día, serían demasiados. Pero están ahí, accesibles mediante las citas que la narrativa de medio plazo ha ido sembrando. Cuando el agente necesita el detalle exacto sigue la referencia y recupera el original.&lt;/p&gt;

&lt;p&gt;Este esquema resuelve los tres problemas que me habían perseguido durante meses.&lt;/p&gt;

&lt;p&gt;La &lt;em&gt;intencionalidad&lt;/em&gt; se conserva porque la narrativa explica no sólo qué se hizo, sino por qué. Todo queda tejido en la historia. La &lt;em&gt;cronología lógica&lt;/em&gt; se mantiene porque la narrativa respeta el orden temporal. El lector, sea humano o LLM, entiende qué pasó antes de qué, y por qué eso importa. Y la &lt;em&gt;pérdida de detalle&lt;/em&gt; desaparece porque el dato al comprimirse se cita. Cuando hace falta precisión, se acude a la fuente. La narrativa puede permitirse el lujo de ser evocadora porque sabe que, si alguien necesita el dato exacto, tiene dónde encontrarlo.&lt;/p&gt;

&lt;p&gt;Durante los últimos meses he ido puliendo la forma en como pedirle al LLM que genere &lt;em&gt;historias&lt;/em&gt; a partir de nuestras conversaciones.&lt;br&gt;
Y cuando retomamos la conversación, días después, le pase esa historia. La diferencia en la calidad de las respuestas es tan evidente que ya no concibo volver a los resúmenes. &lt;/p&gt;

&lt;p&gt;De forma manual he refinado una parte de la técnica, el contador de historias. Me falta ver cómo puedo probar la otra, como manejar las citas.&lt;/p&gt;

&lt;p&gt;Al final, lo que aprendí es que para que un colaborador te entienda de verdad, no basta con darle el resumen del argumento. Hay que dejarle leer la novela. O al menos, una buena crónica que capture su esencia, con notas al pie para quien quiera consultar las fuentes originales.&lt;/p&gt;

&lt;p&gt;La arquitectura de tres niveles resuelve el problema conceptual, pero la implementación real plantea preguntas nada triviales ¿Cómo decides cuándo compactar? ¿Cómo garantizas que las citas sobrevivan a múltiples compactaciones? En el próximo artículo diseñaremos el sistema de memoria narrativa trazable con anclajes y puntos de guardado que responda a estas preguntas. Y tras eso, compartiré el código completo de mi &lt;em&gt;juguete&lt;/em&gt;, un agente en el que llevo semanas trabajando que pone estos conceptos en práctica.&lt;br&gt;
Pero primero, el diseño.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>Mirando bajo el capó de un LLM</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Mon, 09 Feb 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/mirando-bajo-el-capo-de-un-llm-o3n</link>
      <guid>https://forem.com/jjdelcerro/mirando-bajo-el-capo-de-un-llm-o3n</guid>
      <description>&lt;p&gt;A menudo, cuando intentamos explicar cómo funciona un LLM, caemos en abstracciones sobre "redes neuronales" que suenan demasiado biológicas, o en simplificaciones excesivas sobre "la siguiente palabra más probable". Ambas son ciertas, pero ninguna explica &lt;em&gt;qué&lt;/em&gt; está pasando ahí dentro cuando la máquina parece entender un doble sentido.&lt;/p&gt;

&lt;p&gt;Vamos a ver si puedo transmitir lo que he entendido que hay debajo de esa "apariencia de pensar", de esa forma de generar una respuesta a una "texto" nuestro que tienen los LLMs.&lt;/p&gt;

&lt;h2&gt;
  
  
  La habitación
&lt;/h2&gt;

&lt;p&gt;Lo primero que vamos a hacer es fijar un marco en el que situar las "cosas". Imaginemos una habitación de base cuadrada con forma de cubo. Elegimos una esquina de la habitación en el suelo. Las aristas de la habitación que salen de esa esquina van a representar nuestro eje de coordenadas. Dos ejes corren por el suelo, y otro se extiende asta el techo. &lt;/p&gt;

&lt;p&gt;Cada uno de esos ejes va a representar un concepto, elegiremos tres conceptos. Uno representara lo "financiero", dinero, economía... Otro representará lo "mobiliario", mesas, sillas, sofás, muebles en general. Y el otro representará "naturaleza", aire libre, parques, ríos. &lt;/p&gt;

&lt;p&gt;Tendremos tres ejes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Eje financiero (Dinero, economía).&lt;/li&gt;
&lt;li&gt;  Eje mobiliario (Objetos para sentarse, muebles).&lt;/li&gt;
&lt;li&gt;  Eje naturaleza (Aire libre, parques).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-vacio-v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-vacio-v1.png" alt="Nuestra habitación vacía" width="622" height="619"&gt;&lt;/a&gt;&lt;br&gt;
  Nuestra habitación vacía
&lt;/p&gt;

&lt;p&gt;Pondremos el concepto "financiero" a lo largo de uno de los lados de la habitación. Cuanto más cerca de la esquina que elegimos como nuestro punto de referencia menos "financiero" será y cuanto más alejado más "financiero". Situaremos en el otro lado que corre junto al suelo el concepto "naturaleza", y al igual que con "financiero" cuanto más cerca de la esquina menos "mobiliario" será y cuanto más lejos más. Por último situaremos el concepto de "mobiliario" en el lado de la pared que corre de nuestra esquina hacia el techo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Las "cosas" en la habitación
&lt;/h2&gt;

&lt;p&gt;Una vez tenemos nuestra "habitación" vamos a meter dentro "cosas". Tenemos unas pequeñas bolas en las que podemos meter palabras y dejarlas flotando dentro de la habitación. Vamos a colocar unas cuantas bolas en la habitación, con algunas palabras "dinero", "silla" y "árbol".&lt;/p&gt;

&lt;p&gt;La bola "dinero" estará fuertemente ligada al nuestro eje financiero, en rojo, así que la situaremos a lo largo del eje rojo, muy separada de nuestra esquina. Más alejada más "financiero". La bola "silla", estará fuertemente ligada al eje "mobiliario", así que la situaremos a lo largo de este, muy alejada de nuestra esquina. Y lo mismo haremos con la bola "árbol".&lt;/p&gt;

&lt;p&gt;Ya tenemos situadas tres "palabras":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"dinero", muy "financiero".&lt;/li&gt;
&lt;li&gt;"silla", muy "mobiliario".&lt;/li&gt;
&lt;li&gt;"árbol", muy "naturaleza".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-dinero-silla-arbol-v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-dinero-silla-arbol-v1.png" alt="Nuestra habitación con dinero, silla y árbol" width="617" height="617"&gt;&lt;/a&gt;&lt;br&gt;
  Nuestra habitación con "dinero", "silla" y "árbol"
&lt;/p&gt;

&lt;p&gt;Vamos a situar un par más:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"ingresar", bastante "financiero".&lt;/li&gt;
&lt;li&gt;"transacción", bastante "financiero".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-dinero-silla-arbol-transaccion-ingresar-v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-dinero-silla-arbol-transaccion-ingresar-v1.png" alt="Nuestra habitación con dinero, silla, árbol, ingresar y transacción" width="617" height="617"&gt;&lt;/a&gt;&lt;br&gt;
  Nuestra habitación con "dinero", "silla", "árbol", "ingresar" y "transacción"
&lt;/p&gt;

&lt;p&gt;Y vamos a añadir una palabra más... "banco". Uhm... pero banco es "especial", puede significar varias cosas. Puede referirse a una  entidad bancaria o a un banco de sentarse. Tendremos que situarlo a mitad camino de financiero, y a mitad camino de mobiliario... y podría estar relacionado con el concepto "naturaleza", puede estar relacionado con un banco en el parque. Uf! Lo situaremos a mitad de cada uno de estos ejes, flotando más o menos en el centro de nuestra habitación.&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-dinero-silla-arbol-transaccion-ingresar-banco-v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-dinero-silla-arbol-transaccion-ingresar-banco-v1.png" alt="Nuestra habitación con dinero, silla, árbol, ingresar, transacción y banco" width="617" height="617"&gt;&lt;/a&gt;&lt;br&gt;
  Nuestra habitación con "dinero", "silla", "árbol", "ingresar", "transacción" y "banco".
&lt;/p&gt;

&lt;p&gt;Y ahora mismo uno puede preguntarse... &lt;strong&gt;¿Y que tendrá que ver todo esto con un LLM?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Esto que hemos construido es, en miniatura, el corazón de un LLM. Nuestra habitación de 3 dimensiones es un espacio de embeddings. En un modelo real la 'habitación' no tiene 3 dimensiones, sino miles, diez mil o más dimensiones. Y en lugar de 6 bolas, hay cientos de miles de palabras, tokens, cada uno con su posición única y fija en este espacio hiperdimensional. Esta disposición no es aleatoria; es el resultado del 'pre-entrenamiento', un proceso masivo en el que el modelo ha aprendido las relaciones básicas del lenguaje a partir de billones de palabras.&lt;/p&gt;

&lt;p&gt;Ya tenemos nuestro mapa mental, de conceptos y cómo se sitúan nuestras palabras en ese espacio de conceptos. Ahora bien ¿Que nos indican nuestras palabras en la habitación?&lt;/p&gt;

&lt;p&gt;Cuanto más cerca esté una palabra de otra, una bola de otra en la habitación, más íntimamente estarán relacionadas conceptualmente. Que "transacción" e "ingreso" estén cerca nos dice que conceptualmente están muy relacionadas. Qué "árbol" esté muy lejos de "dinero" nos indica que conceptualmente no tienen nada que ver. Como la distancia entre "banco" y "dinero" no es muy grande, nos indica que tienen algo que ver, pero no demasiado. La distancia entre las bolas, las palabras, nos indica la relación semántica que hay entre ellas.&lt;/p&gt;

&lt;p&gt;Bien, ahora mismo, tenemos la base, pero nos falta suministrar el conocimiento. Para darle conocimiento, tendremos que "entrenar" nuestro micro-LLM, y que aprenda.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cómo entrenamos a nuestro LLM
&lt;/h2&gt;

&lt;p&gt;Ahora que nuestro LLM tiene su 'mapa del mundo' básico (los embeddings del pre-entrenamiento), podemos 'entrenarlo' para una tarea específica. Esto a menudo se llama ajuste fino o fine-tuning.&lt;/p&gt;

&lt;p&gt;En un primer momento podríamos pensar que entrenar nuestro LLM puede consistir en ir acercando unas bolas a otras. Si le quiero enseñar que en mi contexto "banco" suele referirse más a una entidad financiera que a un banco del parque, podríamos pensar que lo suyo es que "mueva" la bola de "banco" para acercarla al eje "financiero". Pero no, no funciona así. Nuestra habitación es estática. Las bolas no se mueven, el entrenamiento hace otra cosa.&lt;/p&gt;

&lt;p&gt;Imaginemos, que tenemos una serie de textos con los que queremos entrenar a nuestro LLM para que aprenda de ellos. Y entre esos textos tenemos la frase &lt;em&gt;"Fui al banco a ingresar dinero"&lt;/em&gt;. Cogeremos las bolas "banco", "ingresar" y "dinero" y veremos cómo de cerca están unas de otras. "banco" está bastante lejos de las otras dos, y en este contexto debería estar cerca de ellas. No muevo "banco" o "dinero", voy a encoger el eje financiero, con lo que "ingresar" y "dinero" se acercaran, y voy a estirar el eje "naturaleza" y "mobiliario" con lo que "banco" se alejara de esos conceptos. No he movido las palabras, he estirado y encogido los ejes para que "banco" esté más cerca de "financiero" que de los otros dos. Así que cojo los valores con los que he escalado los ejes y me los guardo asociados a cada eje.&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-dinero-silla-arbol-transaccion-ingresar-banco-filetuning1-v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-dinero-silla-arbol-transaccion-ingresar-banco-filetuning1-v1.png" alt="Deformación de la habitación durante el entrenamiento" width="800" height="264"&gt;&lt;/a&gt;&lt;br&gt;
  Deformación de la habitación durante el entrenamiento
&lt;/p&gt;

&lt;p&gt;Cada vez que entra un texto nuevo se activarán las bolas que aparecen en ese texto, haciendo que los ejes a los que estén asociados apliquen el escalado a nuestra habitación. Si el resultado es que las bolas de la frase están cerca, se da por bueno. Si las bolas de nuestra frase no están cerca, se modifica el factor de escala de los ejes para acercarlas. Y el proceso se va repitiendo con todos los textos con los que queremos entrenar a nuestro LLM. &lt;/p&gt;

&lt;p&gt;Este proceso de calcular cómo hay que ajustar la escala de los ejes que se va haciendo con cada texto de entrenamiento es lo que se llama "&lt;em&gt;backpropagation&lt;/em&gt;" o "&lt;em&gt;gradiente&lt;/em&gt;".&lt;/p&gt;

&lt;p&gt;Al final, cada eje tendrá unos "pesos" específicos del texto con el que lo hemos entrenado que usaremos para escalar nuestro espacio cuando se activen bolas que están cerca de esos ejes. Estos pesos que se han calculado para cada eje en el momento del entrenamiento se graban a fuego en el modelo y ya no cambiarán más una vez terminada la fase de entrenamiento.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Que pasa cuando le preguntamos a nuestro LLM?
&lt;/h2&gt;

&lt;p&gt;Hemos visto ya como "pre-entrenamos", construyendo nuestro habitación, y como "entrenamos", ajustando los pesos de los ejes, a nuestro LLM. Ahora nos queda saber cómo podemos recuperar ese conocimiento que adquirimos durante el entrenamiento.&lt;/p&gt;

&lt;p&gt;Ahora le pregunto a mi LLM &lt;em&gt;"¿Donde hice la transacción?"&lt;/em&gt;. ¿Que pasa por dentro?&lt;/p&gt;

&lt;p&gt;El modelo toma cada palabra de nuestra pregunta y activa sus correspondientes "bolas" en la habitación. La presencia de "transacción" actúa como una señal &lt;br&gt;
de activación en el eje financiero y hace que se apliquen los pesos de ese eje. El modelo ha centrado su atención en el eje financiero.&lt;/p&gt;

&lt;p&gt;En un instante, el espacio de nuestra habitación cambia. La habitación se transforma en un largo pasillo que se adentra en la dirección de lo financiero. En este nuevo espacio deformado:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"dinero" e "ingresar" están ahora cerca.&lt;/li&gt;
&lt;li&gt;La bola "banco", que antes flotaba en un centro ambiguo, es arrastrada por la deformación hacia la zona financiera. Su distancia a "transacción" se ha reducido.&lt;/li&gt;
&lt;li&gt;"silla" y "árbol", en cambio, quedan aplastadas contra la pared lejana, casi irrelevantes para el cálculo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
  &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-dinero-silla-arbol-transaccion-ingresar-banco-inferencia1-v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjjdelcerro.github.io%2Fassets%2Fimages%2Fmirando-bajo-el-capo-de-un-llm%2Fcubo-dinero-silla-arbol-transaccion-ingresar-banco-inferencia1-v1.png" alt="Deformación de la habitación en la inferencia" width="800" height="296"&gt;&lt;/a&gt;&lt;br&gt;
  Deformación de la habitación en la inferencia
&lt;/p&gt;

&lt;p&gt;El modelo no se detiene. Su tarea es encontrar, en este espacio deformado por el contexto, la palabra que geométricamente "encaja" a continuación. Realiza un cálculo de proximidad. ¿Qué bolas están ahora más cerca del "punto de atención" creado por la frase? La más prominente es "banco" (en su sentido financiero).&lt;/p&gt;

&lt;p&gt;Así, la respuesta comienza a generarse: "En el banco..."&lt;/p&gt;

&lt;p&gt;El proceso no para ahí. La palabra "banco" se añade al contexto, lo que provoca una nueva deformación del espacio (otra ronda de atención), que a su vez hace que la siguiente palabra más probable sea, por ejemplo, "financiero" o "ayer". Y así, paso a paso, se compone la respuesta.&lt;/p&gt;

&lt;p&gt;El modelo no ha "pensado" en entidades bancarias. No ha recuperado un hecho de una base de datos. Simplemente, la geometría de su espacio interno, entrenada con millones de textos, ha sido deformada por la pregunta de tal forma que la trayectoria más natural a través de ese paisaje conduce, inevitablemente, a una secuencia de palabras que nosotros interpretamos como una respuesta lógica.&lt;/p&gt;

&lt;h2&gt;
  
  
  Del cubo a la hipermatriz
&lt;/h2&gt;

&lt;p&gt;Esta explicación visual funciona para entender la intuición, pero no debemos de dejar de prestar atención a los planos reales.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;He hecho trampa&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No hay 3 ejes. En un LLM, &lt;em&gt;Large Language Model&lt;/em&gt;, pueden haber más de 12.000 dimensiones.&lt;/p&gt;

&lt;p&gt;No hay 6 palabras. Hay un vocabulario de más de 50.000 tokens.&lt;/p&gt;

&lt;p&gt;¿Para qué sirven tantas dimensiones?&lt;/p&gt;

&lt;p&gt;Con 3 ejes podríamos separar un árbol de un billete. Con 12.000 dimensiones, un LLM puede crear un eje para el tono irónico, otro para la estructura de una receta de cocina, otro para la ambigüedad legal en una cláusula y miles más para conceptos que ni siquiera tenemos palabras para definir. Esa es su potencia, mapear la complejidad del lenguaje en un hiperespacio donde todo matiz tiene su lugar.&lt;/p&gt;

&lt;p&gt;Cuando decimos que el espacio se estira o se encoge, en realidad hablamos de operaciones con matrices gigantescas que aplican deformaciones más complejas que un simple escalado. Esas "bolas" son en realidad vectores de embedding. Listas de 12.000 números que definen la posición de cada token. Los "pesos" que calibramos en el entrenamiento son los millones de parámetros dentro de las matrices que forman el mecanismo de atención.&lt;/p&gt;

&lt;p&gt;En resumen, la pregunta no deforma nuestro hipercubo. Lo que hace es multiplicar un vector por matrices de parámetros entrenadas, proyectándose y rotando una y otra vez a través de capas del espacio, hasta que la posición resultante señale a la siguiente palabra más coherente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cálculo, no magia
&lt;/h2&gt;

&lt;p&gt;Entender este proceso es fundamental para rebajar el hype y empezar a trabajar con estas herramientas con los pies en la tierra.&lt;/p&gt;

&lt;p&gt;Cuando un LLM te sorprende con una respuesta que parece demostrar "entendimiento profundo" o "sentido común", recuerda la habitación. No es que haya desarrollado consciencia o lógica. Lo que ha hecho es encontrar una correlación estadística en un espacio de 12.000 dimensiones. Ha logrado deformar ese hiperespacio de tal forma que acerca conceptos que, en nuestra realidad tridimensional y causal, parecen conectados por la razón, pero que en el modelo solo están unidos por patrones de proximidad vectorial aprendidos.&lt;/p&gt;

&lt;p&gt;No razona. Calcula. No infiere. Navega por un paisaje geométrico que se remodela con cada palabra que escribes. No piensa. Sigue la trayectoria más probable en un universo numérico de distancias y ángulos.&lt;/p&gt;

&lt;p&gt;Y eso, aunque no sea magia, es una obra de ingeniería matemática fascinante.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;El Laboratorio&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Para generar las imágenes he preparado una pequeña simulación interactiva donde puedes jugar con esta "habitación", activar y desactivar las palabras, y mover tú mismo el deslizador de "Atención Financiera" para ver cómo la deformación del espacio altera las distancias entre conceptos. No pretende ser estricto, solo una herramienta para ilustrar el articulo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jjdelcerro.github.io/lab/habitacion-llm/index.html" rel="noopener noreferrer"&gt;Entrar a la Habitación (Simulación 3D)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nota: El código fuente de la visualización también está disponible para los curiosos.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>nlp</category>
    </item>
    <item>
      <title>El vendedor de empleados invisibles</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Mon, 02 Feb 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/el-vendedor-de-empleados-invisibles-3i84</link>
      <guid>https://forem.com/jjdelcerro/el-vendedor-de-empleados-invisibles-3i84</guid>
      <description>&lt;p&gt;&lt;em&gt;No intente ajustar su televisor. Nosotros controlamos la transmisión. Nosotros controlamos lo horizontal y lo vertical. Durante la próxima lectura, siéntese tranquilamente y nosotros controlaremos todo lo que usted vea y oiga. Usted está a punto de conocer... el límite exterior.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;La oficina de Don Julián olía a papel, café recalentado y quietud. El tic-tac del reloj de pared marcaba el compás de un negocio que no tenía prisa por convertirse en otra cosa. Entre ese sonido y el murmullo lejano de la única impresora matricial que quedaba, se coló la voz del joven comercial.&lt;/p&gt;

&lt;p&gt;- ... y por eso, don Julián, no estamos hablando de simples programas. Estamos hablando de una &lt;em&gt;sociedad multi-agente autónoma&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;El joven, trajeado con una elegancia que rechinaba contra los muebles de melamina, desplegaba gráficos en una tablet. Don Julián, al otro lado del escritorio, removía con parsimonia una cucharilla en su taza de cerámica con el logotipo desgastado de una feria agrícola de 2022.&lt;/p&gt;

&lt;p&gt;- Nuestro sistema -proseguía el joven- implementa protocolos A2A nativos con negociación semántica en la nube. Imagine. Sus procesos se orquestan solos, las máquinas hablan entre ellas en un lenguaje universal de máxima eficiencia de tokens... ¡Es el fin de la intervención humana en la gestión!"&lt;/p&gt;

&lt;p&gt;Don Julián dejó la cucharilla. El roce de su silla de oficina, de esas que crujen al moverse, cortó el aire.&lt;/p&gt;

&lt;p&gt;- Ya... -dijo, arrastrando la vocal-. A ver, joven, que yo de eso de la 'orquestación' no entiendo mucho. Yo aquí lo que tengo son facturas, nóminas y muchos, muchos Excel. -Hizo una pausa, mirando por la ventana a la calle casi vacía-. Pero mire, eso que me cuenta me suena... De hecho, creo que ya lo tenemos resuelto.&lt;/p&gt;

&lt;p&gt;El joven parpadeó. -¿Resuelto? Pero si nuestra tecnología es &lt;em&gt;pionera&lt;/em&gt;... el stack completo de...&lt;/p&gt;

&lt;p&gt;- Espere un momento -lo interrumpió Don Julián sin levantar la voz.&lt;/p&gt;

&lt;p&gt;Se inclinó, abrió el cajón central de madera que protestó con un gemido familiar. Removió unos papeles, pasó por encima de un manual de contabilidad del 2005 y extrajo un folleto plegado, con una esquina ligeramente doblada. Lo deslizó por la mesa hacia el comercial.&lt;/p&gt;

&lt;p&gt;- Esto me lo dejó el chico que instaló el piloto en la sucursal la semana pasada. Trajo la cajita, la enchufó y la configuró en un rato. Me hizo gracia su tarjeta. Se presentó como "Vendedor de empleados invisibles". Dijo que no ocupan sitio, no gastan café y trabajan mientras duermo. Tome, léalo usted mismo.&lt;/p&gt;

&lt;p&gt;El joven tomó el folleto. Era de un papel más basto que los suyos, con un diseño casi austero. En la portada, una foto poco inspiradora. Una cajita negra, discreta, colocada al lado de un router doméstico. No había gráficos de flujo, ni jerga. El titular, en una tipografía sencilla, decía &lt;strong&gt;"Hable con sus nuevos empleados. Ellos entienden su negocio."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;El joven frunció el ceño. -Pero... aquí no pone nada de protocolos, de arquitecturas...&lt;/p&gt;

&lt;p&gt;- Abra, abra -insistió Don Julián, tomando un sorbo de café.&lt;/p&gt;

&lt;p&gt;El comercial desplegó el folleto. Dentro, en un lenguaje llano, había tres mensajes clave:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"Se integran en su oficina al instante."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Hable con ellos por correo, como con cualquier compañero."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Sin costosas configuraciones. Sin cursos interminables. Sin sorpresas en la factura."&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Había una captura de pantalla, borrosa pero legible, de un cliente de correo. Se veía un mensaje enviado a &lt;code&gt;informes@empresa.local&lt;/code&gt;. El asunto: "Listado de clientes con pedidos pendientes a fecha de ayer". El cuerpo era igual de simple: "Hola Ana, ¿me puedes preparar esto cruzándolo con la morosidad? Gracias."&lt;/p&gt;

&lt;p&gt;- Exacto -asintió Don Julián, siguiendo la mirada del joven-. Eso fue lo que más me gustó. No tengo que aprender nada nuevo. Ayer mismo, poco antes de irme, le escribí un correo a "Ana" -así llamamos a la chica de la cajita- para que me cruzara los datos de los clientes con los pedidos pendientes. En diez minutos tenía el Excel en la carpeta compartida de siempre, con sus celdas bien puestas y todo. Sin una queja, sin pedir aclaraciones.&lt;/p&gt;

&lt;p&gt;- Pero... eso es ineficiente -logró articular el joven, recuperando parte de su discurso-. El correo electrónico tiene latencia, no es un estándar A2A optimizado para...&lt;/p&gt;

&lt;p&gt;- Mire lo que pone en ese recuadro de abajo -lo interrumpió de nuevo Don Julián, señalando con un dedo calloso la parte inferior del folleto-. El que está en azul.&lt;/p&gt;

&lt;p&gt;El joven leyó en voz baja, y esta vez su tono no era de incredulidad, sino de algo parecido al desaliento: &lt;strong&gt;"Olvídese de los sistemas que solo entienden otros sistemas. Sus empleados virtuales hablan &lt;em&gt;su&lt;/em&gt; idioma."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;- Pues eso -concluyó Don Julián, reclinándose en su silla, que volvió a crujir-. Mi contable le escribe correos a Ana, Ana le contesta a él, y yo recibo mis informes donde los he recibido siempre. Sin cosas nuevas, sin configuraciones eternas y -repitió, clavando la mirada en el joven- sin sorpresas en la factura.&lt;/p&gt;

&lt;p&gt;Se hizo un silencio. Solo el tic-tac del reloj y el leve zumbido de los fluorescentes llenaban la habitación. El joven miraba el folleto, luego su tablet llena de diagramas relucientes, y otra vez el folleto.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ding-dong.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;El sonido nítido y familiar de una notificación de correo entrante resonó desde el ordenador de don Julián.&lt;/p&gt;

&lt;p&gt;Este esbozó una sonrisa leve, casi paternal.&lt;/p&gt;

&lt;p&gt;- Mire, ahí llega Ana con la minuta de hoy. Si no le importa, joven, tengo trabajo que revisar. -Hizo una pausa, como recordando algo-. De hecho, con lo bien que va, igual le pido a los de la cajita que me manden otro. Para la logística, quizás. Le pondremos "Javi" y su propio correo, y asunto arreglado.&lt;/p&gt;

&lt;p&gt;El mensaje estaba claro. No había sido un no rotundo. Había sido algo peor. Una indiferencia total hacia la complejidad que vendía. La solución ya estaba aquí, era simple, y funcionaba en silencio, como un buen empleado. Y si hacía falta más, se contrataba a otro. Sin protocolos nuevos, sin integraciones épicas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflexión
&lt;/h2&gt;

&lt;p&gt;A veces, en la búsqueda obsesiva del protocolo perfecto -aquel que optimiza cada byte y cada milisegundo entre máquinas-, olvidamos para qué sirve todo el andamiaje. El objetivo final no es que los agentes conversen entre sí en una lengua &lt;em&gt;arcana&lt;/em&gt; y &lt;em&gt;eficiente&lt;/em&gt;. Es que resuelvan problemas.&lt;/p&gt;

&lt;p&gt;Los problemas viven en el mundo de los humanos. Un mundo lleno de emails, carpetas compartidas, Excels con formatos raros y frases como "¿me puedes preparar esto?". Un mundo donde la "latencia" aceptable no se mide en milisegundos, sino en "antes de la pausa para el café".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Y la cajita negra?&lt;/strong&gt; No es magia. Es la personificación de una idea pragmática. Un solo "empleado digital" suficientemente capaz. No es una red de agentes negociando entre sí. Es un solo modelo de lenguaje, ejecutándose localmente, al que se le han dado tres cosas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Acceso a las herramientas de siempre&lt;/strong&gt;, el correo, el sistema de archivos, las plantillas.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;El conocimiento de la casa&lt;/strong&gt;, los procedimientos, el organigrama, el "cómo se hacen aquí las cosas".&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Una instrucción clara&lt;/strong&gt; "Escucha la bandeja de entrada y ayuda como un compañero más".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Este agente no necesita montar un comité interno (A2A) para decidir cada paso. Igual que un humano competente, planea sus tareas, consulta la documentación (las carpetas del servidor), sigue el protocolo (los procedimientos) y termina ejecutando la tarea usando las herramientas a su alcance. Su "inteligencia" no está en orquestar una sinfonía de micro-servicios especializados, sino en tener la &lt;strong&gt;capacidad cognitiva suficiente&lt;/strong&gt; para entender una petición ambigua, buscar la información que falta y actuar de forma autónoma y correcta.&lt;/p&gt;

&lt;p&gt;La verdadera revolución no estará en la capacidad de las máquinas para negociar entre ellas en la nube, sino en su habilidad para integrarse, sin fricción y sin ruido, en los protocolos humanos que ya existen. En ser tan discretos y útiles que su presencia se note solo por la ausencia del problema.&lt;/p&gt;

&lt;p&gt;Quizás la autonomía más inteligente no sea la que construye un ecosistema paralelo y perfecto de agentes que se susurran entre sí, sino la que aprende a navegar, con eficacia suficiente, el ecosistema imperfecto, lento y gloriosamente humano que ya tenemos ahora. A veces, todo lo que se necesita es un buen empleado que sepa dónde están las cosas y cómo se piden.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Devolvemos ahora el control de su lectura. Hasta la próxima vez, cuando volvamos a llevarle... al límite exterior.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>productivity</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Cuando la IA escribe código... la ilusión del entendimiento (parte 4)</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Thu, 29 Jan 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/cuando-la-ia-escribe-codigo-la-ilusion-del-entendimiento-parte-4-4a83</link>
      <guid>https://forem.com/jjdelcerro/cuando-la-ia-escribe-codigo-la-ilusion-del-entendimiento-parte-4-4a83</guid>
      <description>&lt;p&gt;El tercer caso y con el que acabo esta serie de "Cuando la IA genera codigo", me ocurrió hace apenas unas semanas, trabajando en mi prototipo de agente con una gestión de memoria &lt;em&gt;un tanto especial&lt;/em&gt;. Esta vez, el origen del problema fue un error de diseño mío. En un intento de optimizar, decidí reutilizar el mismo artefacto que gestionaba la &lt;em&gt;"base de conocimientos"&lt;/em&gt; (el historial consolidado) para gestionar también el &lt;em&gt;"historial vivo"&lt;/em&gt; de la conversación en curso. Sobre el papel parecía que podría funcionar. En la práctica, fue una muy mala idea. Las responsabilidades se mezclaban y la lógica de gestión de la ventana de contexto se volvía inmanejable.&lt;/p&gt;

&lt;p&gt;Al darme cuenta, se lo expliqué a Gemini. Le detallé por qué esa arquitectura era errónea y le pedí separar los conceptos. Su respuesta textual fue impecable: &lt;em&gt;“Entiendo perfectamente. No debemos acoplar la persistencia a largo plazo con el buffer de corto plazo por X e Y motivos”&lt;/em&gt;. Le pedí que me explicase cómo lo iba a desacoplar, y me dio una respuesta que a grandes rasgos parecía correcta, así que le dije que lo implementase.&lt;/p&gt;

&lt;p&gt;Me generó una nueva clase &lt;code&gt;Session&lt;/code&gt;, con un par de métodos para persistir y restaurar la sesión, y dejó en una propiedad de la clase el array con los turnos. Y hasta ahí llegó. El array con los turnos era público y desde la clase &lt;code&gt;ConversationAgent&lt;/code&gt; accedía directamente a él para cualquier operación. Los métodos &lt;code&gt;save&lt;/code&gt; y &lt;code&gt;restore&lt;/code&gt; recibían y devolvían un array con los turnos que luego asignaba desde fuera a la variable pública de la sesión. Vamos, &lt;strong&gt;un desacato en cuanto a arquitectura&lt;/strong&gt; donde las dos clases habían quedado completamente entrelazadas sin un reparto de responsabilidades claro.&lt;/p&gt;

&lt;p&gt;Lo más curioso, y a la vez peligroso, es que en este caso &lt;strong&gt;funcionaba&lt;/strong&gt;. Rodaba la aplicación e iba. Pero me imaginaba a mí mismo tratando de evolucionar la maraña que había escrito el agente en unas semanas y me daba un pasmo.&lt;/p&gt;

&lt;p&gt;Había entendido la teoría de mi explicación, pero fue incapaz de vencer la "gravedad" del código que ya estaba escrito. A cada paso que le señalaba el error él contestaba entenderlo, pero no era capaz de decidir qué responsabilidades debía tener cada clase. Al final acabé dejando un esqueleto con la clase que quería para la sesión y comentarios sobre cómo debía implementar cada método... y así conseguí que medio hiciese lo que quería.&lt;/p&gt;

&lt;p&gt;Pero no acabaron ahí mis problemas. Ya estaban separadas las responsabilidades, pero ahora no iba. Para mantener la estructura de datos le sugerí que usase una lista y un diccionario. Solo con una de las dos cosas no se podía implementar lo que le pedía. Cuando parecía entender para qué tenía que usar la lista... solo usaba la lista, y no iba. Cuando parecía entender para qué necesitaba el diccionario rehacía la clase entera y solo usaba el diccionario, y no iba. La estructura de la clase se asemejaba mucho a muchas implementaciones que podía encontrar en la web. &lt;strong&gt;Pero solo se asemejaba mucho.&lt;/strong&gt; Una diferencia sutil de concepto hacía que no terminase de encajar en un patrón claro. Unas veces se decantaba por una implementación y otras por otra, y ninguna era válida.&lt;/p&gt;

&lt;p&gt;Al final acabé implementando lo que estaba mal de la clase... y no le volví a dejar que la tocase. Si la tocaba, deshacía mi código y volvía a dejar una implementación que no iba.&lt;/p&gt;

&lt;p&gt;A bote pronto podrías pensar que se trataba de un proyecto grande, con muchas clases y relaciones entre ellas. No era así. Estamos hablando de un proyecto con 7 clases Java y, para el caso que me ocupaba, solo estaban involucradas 4 de las 7. La arquitectura no es lo suyo. No le dejes tomar decisiones de arquitectura en tus proyectos; no lo va a hacer bien.&lt;/p&gt;

&lt;p&gt;Este episodio me dejó una sensación distinta a la de las pruebas anteriores. No era solo que la IA no supiera integrar un protocolo o gestionar un estado asíncrono. Aquí, la IA parecía haber entendido perfectamente mi explicación teórica, y aún así fue incapaz de traducir esa comprensión en una estructura de código coherente. La brecha no estaba en la sintaxis, ni siquiera en la lógica de un algoritmo; estaba en algo más abstracto: en la capacidad de diseñar. Era como si hubiera aprobado el examen de arquitectura de software con nota, pero suspendido en la práctica. ¿Cómo era posible? Para responder, hay que dejar de mirar el código y empezar a mirar el mecanismo que lo genera.&lt;/p&gt;

&lt;h2&gt;
  
  
  La mecánica de la simulación
&lt;/h2&gt;

&lt;p&gt;Para entender por qué ocurre esto hay que dejar de mirar el código que genera y empezar a mirar el mecanismo que lo produce.&lt;/p&gt;

&lt;p&gt;Lo que ocurre cuando un LLM como Gemini explica con claridad por qué una arquitectura es errónea, para luego ser incapaz de implementar la alternativa correcta, no es una contradicción. Es la consecuencia inevitable de su naturaleza. Los modelos de lenguaje no entienden en el sentido en que un programador entiende un sistema; simulan comprensión a través del uso del lenguaje. Y esa simulación es, en realidad, un modelo lingüístico y relacional de alto nivel sobre el concepto.&lt;/p&gt;

&lt;p&gt;El LLM ha sido entrenado en una cantidad astronómica de documentación técnica donde se definen principios como el 'acoplamiento', la 'separación de responsabilidades' o el 'patrón de diseño'. Cuando le pedimos que explique por qué falló, no está razonando sobre el sistema concreto; está realizando un proceso de mapeo narrativo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reconocimiento de patrones: Identifica los tokens clave ('acoplamiento', 'responsabilidades', 'Session', 'ConversationAgent'). En su memoria, estos términos están vinculados por una gravedad estadística inmensa a un tema narrativo: 'los principios de diseño de software'.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Síntesis explicativa: Su tarea ya no es diagnosticar un fallo de diseño en un sistema vivo, sino articular la explicación que ya existe en la literatura técnica. Su valor es mapear nuestra experiencia concreta al marco conceptual general que ha leído millones de veces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contraste de modelos (Texto vs. Sistema): Lo más fascinante es que puede contrastar dos patrones lingüísticos: el código que acaba de generar y la teoría que dice que ese código es erróneo. Al yuxtaponerlos, genera una tesis que explica el fallo.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La paradoja es que un LLM puede generar una explicación perfecta de por qué los LLMs no pueden comprender ciertos problemas, simplemente porque ha leído muchas descripciones de esos fallos escritas por humanos que sí los entendían. Puede escribir un documento persuasivo sobre sus propios límites porque está operando desde su mayor fortaleza: la síntesis de narrativas humanas preexistentes.&lt;/p&gt;

&lt;p&gt;Sin embargo, en cuanto pasamos de la narrativa a la resolución de un problema nuevo que requiere inferencia causal y toma de decisiones de diseño... la simulación se desvanece. Porque la IA no tiene un modelo mental del sistema, solo tiene un modelo lingüístico de las conversaciones sobre sistemas.&lt;/p&gt;

&lt;h2&gt;
  
  
  La clave está en la naturaleza del problema
&lt;/h2&gt;

&lt;p&gt;El caso de la clase Session no es una anomalía. Es la manifestación clara de un patrón que he visto repetirse una y otra vez. Los LLMs tropiezan sistemáticamente en los mismos tipos de problemas. No es cuestión de lenguaje, de framework o de lo bien que escribas el prompt. Es la naturaleza del problema la que los vuelve irresolubles. Y esa naturaleza la he clasificado en tres categorías:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Desarrollos que involucran la evolución de estados en tiempo de ejecución.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Aquí está el núcleo de la prueba LSP4J y también del stale closure en React. El LLM ve el código estático (texto), pero no "simula" mentalmente cómo cambia el estado a lo largo del tiempo: inicializaciones, notificaciones asíncronas, condiciones de carrera, ciclos de vida de objetos externos... Cuando el problema requiere razonar sobre "qué pasa en el runtime después de X evento", el modelo aplica patrones estadísticos que no encajan, porque no tiene un modelo causal dinámico.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Desarrollos que "se parecen mucho" a algo visto millones de veces, pero no son exactamente eso.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Este es un fallo clásico de over-generalización / "weight" del entrenamiento. En el ejemplo de la clase &lt;code&gt;Session&lt;/code&gt; (con el mapa de turnos y el borrado de rangos), el problema se parece muchísimo a miles de ejemplos de listas + mapas + reindexación que ha visto. El "empuje estadístico" lo lleva a una solución incorrecta porque el detalle sutil (reconstruir después del clear, preservar identidad de objetos, offset preciso) no es lo suficientemente frecuente o diferenciado en el entrenamiento. Es un "parecido peligroso" en el que el modelo cree que sabe, pero aplica el patrón equivocado.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Desarrollos en los que hay que tomar decisiones arquitectónicas propias de la solución.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Aquí entra la elección de diseño minimalista vs sobreingeniería, la separación de capas (protocolo vs semántica), o decidir si algo necesita una clase nueva o se resuelve en el método existente. El LLM tiende a patrones comunes (más clases, más abstracciones, más boilerplate) porque eso es lo que ve más en repositorios públicos. Cuando la mejor solución es "quedarse en una clase simple y reconstruir el mapa después del clear", falla en priorizar simplicidad y contexto específico del dominio.&lt;/p&gt;

&lt;p&gt;Seguramente habrá muchos tipos de problema que no son capaces de resolver, yo dejo aquí mi granito de arena con estos tres.&lt;/p&gt;

&lt;p&gt;La discusión pública sobre &lt;em&gt;LLMs+programación&lt;/em&gt; suele polarizarse en dos bandos simplones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Bando hype&lt;/em&gt;. "Ya resuelven proyectos enteros, complejidad no es problema".&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Bando escéptico genérico&lt;/em&gt;. "Fallan en tareas complejas/grandes/reales/arquitectura, siempre necesitas humano in the loop".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mi posición es más precisa y sutil. &lt;em&gt;Pueden resolver cosas objetivamente complejas&lt;/em&gt; con muy poco o ningún "humano en el bucle", &lt;em&gt;siempre que el problema no caiga en esas tres categorías&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Cuando se acercan a ellas, el éxito y la autonomía se desploma. Cuando se mantienen lejos, funcionan sorprendentemente bien. La frontera no es cuantitativa (tamaño, líneas, abstracciones), sino cualitativa.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>architecture</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Cuando la IA programa... el bug que el LLM no ve (parte 3).</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Mon, 26 Jan 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/cuando-la-ia-programa-el-bug-que-el-llm-no-ve-parte-3-5ebb</link>
      <guid>https://forem.com/jjdelcerro/cuando-la-ia-programa-el-bug-que-el-llm-no-ve-parte-3-5ebb</guid>
      <description>&lt;p&gt;En las dos primeras partes de esta serie (donde analizamos por qué la IA no programa y vimos las pruebas realizadas), nos centramos en el diagnóstico. Ahora voy a pasar a comentar sobre un fallo real en un entorno web.&lt;/p&gt;

&lt;p&gt;A finales del año pasado, nos encargaron una tarea aparentemente rutinaria de añadir una funcionalidad en el frontend de aplicación web de la empresa. La solicitud era concreta, implementar una lista de capas seleccionables para la leyenda de un mapa, y el stack, JavaScript con React y django, uno de los más populares y documentados.&lt;/p&gt;

&lt;p&gt;Para mi compañero y para mí, este encargo supuso un cambio brusco de contexto. Nuestra zona de confort, y nuestra experiencia en las últimas dos décadas, está en el desarrollo de aplicaciones de escritorio con Java. Nuestro conocimiento de JavaScript es "arqueológico", y de React, no mucho mas alla del nombre. Era el caso ideal para tirar de IA para que nos ayudara con el encargo. Dos desarrolladores senior con conocimientos de arquitectura de software, pero sin la sintaxis específica de JS con React.&lt;/p&gt;

&lt;p&gt;Así que tiramos de IA para convertirla en nuestro traductor. Le entregamos el código, le explicamos el objetivo y confiamos en que generaría la solución. Y lo hizo. El código que nos devolvió era limpio, utilizaba los hooks de React de forma aparentemente correcta y se integraba "sin errores" en el código base. Había escrito un componente con &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt; y &lt;code&gt;useCallback&lt;/code&gt;. Todo parecía en orden.&lt;/p&gt;

&lt;p&gt;Hasta que lo ejecutamos.&lt;/p&gt;

&lt;p&gt;El fallo no fue estridente, no había excepciones en consola ni se rompía la aplicación, fue mas bien insidioso y silencioso. A veces la lista no aparecía. Otras los checkboxes no respondían. El estado de la interfaz parecía vivir en una realidad a parte de la lógica del código. La IA había escrito un &lt;strong&gt;bug de cierre obsoleto&lt;/strong&gt; (&lt;em&gt;stale closure&lt;/em&gt;), un error clásico y sutil en la gestión de estado de React.&lt;/p&gt;

&lt;p&gt;Este es el punto de partida de este análisis. La herramienta diseñada para suplir nuestra falta de conocimiento específico &lt;strong&gt;generó un problema que ella misma no podía diagnosticar ni resolver&lt;/strong&gt;. El código era sintácticamente impecable, pero semánticamente roto. Y eso nos obligó a hacer lo que la IA no puede, entender el sistema, formar un modelo mental de su ejecución y dirigir la corrección.&lt;/p&gt;

&lt;p&gt;Lo que sigue no es una queja sobre React, ni una lección de sus hooks. Es un caso de estudio sobre el abismo que separa la generación de "texto probable" de la comprensión de un sistema dinámico. Un abismo que los programadores sabemos cruzar, y que los modelos de lenguaje no pueden.&lt;/p&gt;

&lt;h2&gt;
  
  
  El espejismo del código correcto
&lt;/h2&gt;

&lt;p&gt;Antes de empezar la sesión con "Gemini CLI" lanzamos unos cuantos &lt;code&gt;grep&lt;/code&gt; en la consola para localizar donde podía estar el codigo a tocar y luego les echamos un vistazo con el editor. Necesitábamos saber qué ficheros tocaban el UI de impresión y dónde residía la lógica que debíamos alterar.&lt;/p&gt;

&lt;p&gt;Una vez identificados los módulos iniciamos sesión con "Gemini CLI". Empezamos estableciendo el contexto. Le explicamos, a grandes rasgos, qué hace la aplicación a nivel de usuario, cuál era el objetivo funcional de los cambios y le describimos la estructura del proyecto, subproyectos, tecnologías y herramientas de construcción. Para validar que nos habia entendido le pedimos que examinara el código y nos confirmara si su "visión" coincidía con nuestra descripción. Su análisis fue correcto. Identificó los módulos y nos explicó su funcionamiento. Con esa base común le pedimos un plan de acción. Una explicación sin código de qué pasos habría que dar para implementar la lista de capas seleccionables en el dialogo de impresión. El plan tenia buen aspecto y se veía coherente con la arquitectura que habiamos visto. Asi que le dijimos que tirase adelante, "Aplica el plan".&lt;/p&gt;

&lt;p&gt;El código generado tenía buena pinta. Desplegamos y probamos. No funcionaba. La interfaz se presentaba correctamente pero la interacción era errática. Le describimos el comportamiento, adjuntamos capturas de pantalla de la aplicación y esperamos su diagnóstico. La IA sugirió cambios, modificaciones menores en la lógica de eventos que nos parecieron sensatas. Le dijimos que las aplicara. Volvimos a desplegar. Volvimos a probar. Seguía sin ir.&lt;/p&gt;

&lt;p&gt;Entramos en un bucle de prueba y error. Iteración tras iteración, probabamos, describiamos el problema y el modelo proponía y aplicaba tras explicarnoslos parches sintácticamente válidos que no resolvían el problema de fondo. Decidimos intervenir poniendo puntos de ruptura en el navegador, inspeccionando variables en tiempo de ejecución y comentando los hallazgos con el modelo. Pero seguíamos dando vueltas en círculo. La IA estaba "parcheando síntomas", no arreglando el sistema.&lt;/p&gt;

&lt;p&gt;Fue el momento de parar. Nos dimos cuenta de que estábamos delegando el entendimiento del problema en una herramienta que no &lt;em&gt;entendía&lt;/em&gt; lo que pasaba por debajo.&lt;/p&gt;

&lt;p&gt;Cambiamos radicalmente de estrategia. Nosotros no sabíamos React y la IA no sabía depurar su propio código. Asi que teníamos que ser nosotros quienes aprendiéramos lo necesario para auditarla. Le pedimos que dejara de generar código y actuara como documentalista. &lt;em&gt;"Genera un documento en Markdown explicando las principales funcionalidades y hooks de React que has utilizado en esta solución"&lt;/em&gt;. Nos costo un poco, era muy insistente a la hora de aplicar cambios en el codigo, y demasiado esquematica a la hora de genrar documentación.&lt;/p&gt;

&lt;p&gt;Nos pusimos a leer. Buscábamos entender el ciclo de vida y la gestión de memoria. Al leer sobre &lt;code&gt;useCallback&lt;/code&gt; y ver que usaba &lt;em&gt;closures&lt;/em&gt;, conceptos que ya conociamos empezaron a encajar con la terminología web. Volvimos al código generado. Allí estaba. Faltaba una dependencia. Un par de variables críticas no estaban en el array de dependencias del &lt;code&gt;useCallback&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;— &lt;em&gt;Aquí falta algo&lt;/em&gt; —le comentamos a la IA, señalando la línea específica—. &lt;em&gt;¿No deberían estar estas variables en las dependencias para que la función vea los cambios?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;La respuesta fue inmediata: &lt;em&gt;"Efectivamente, tienes razón. Faltan esas dependencias"&lt;/em&gt; y añadió las variables sin que llegasemos a pedirselo.&lt;/p&gt;

&lt;p&gt;Desplegamos. Probamos. Funcionó a la primera.&lt;/p&gt;

&lt;p&gt;Aún realizamos un par de iteraciones más entre los "tres" para pulir detalles, pero el problema real, el que nos había tenido dando vueltas, no lo resolvió la capacidad generativa del LLM ni el cliente con capacidades agenticas que estabamos usando. Lo resolvió nuestra capacidad para detenernos, construir un modelo mental del funcionamiento y señalar el error lógico que el LLM no podía ver.&lt;/p&gt;

&lt;h3&gt;
  
  
  La brecha conceptual
&lt;/h3&gt;

&lt;p&gt;El error del &lt;em&gt;stale closure&lt;/em&gt; es revelador porque no es un fallo de sintaxis, sino de &lt;em&gt;semántica operativa&lt;/em&gt;. Para entenderlo, un desarrollador debe construir mentalmente un modelo de ejecución. Una pila de llamadas, un heap de memoria, el flujo del ciclo de eventos y el concepto de &lt;em&gt;closure&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;La IA, por el contrario, opera en un plano puramente textual y estadístico. Ve &lt;code&gt;useCallback&lt;/code&gt; y reconoce un patrón. Suele ir seguido de una función y un array. Ha "internalizado" que el array a menudo contiene nombres de variables. Lo que no ha internalizado, porque no puede, es el &lt;em&gt;porqué&lt;/em&gt; conceptual de ese array. Para la IA, &lt;code&gt;[layers, legendLayers]&lt;/code&gt; es una secuencia probable de tokens que a menudo aparece después de ciertas palabras clave. Para un programador, esa misma línea es una declaración de dependencias funcionales: "recrea esta función sólo si &lt;code&gt;layers&lt;/code&gt; o &lt;code&gt;legendLayers&lt;/code&gt; cambian su referencia, porque su lógica interna depende de sus valores".&lt;/p&gt;

&lt;p&gt;Esta es la brecha fundamental:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;El dominio de la IA es el texto estático.&lt;/em&gt; Su éxito se mide por la coherencia lingüística y la adherencia a patrones estructurales observados en su entrenamiento. Puede generar una función que &lt;em&gt;parezca&lt;/em&gt; manejar estado, porque ha visto miles de ejemplos de código que lo hacen.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;El dominio del programador es el sistema dinámico.&lt;/em&gt; Nuestro éxito se mide por el comportamiento correcto del programa a lo largo del tiempo. Entendemos que el código no es sólo texto. Es una especificación. Un &lt;code&gt;useCallback&lt;/code&gt; no es una mera invocación a una API, es una instrucción para React sobre cuándo romper y reconstruir una &lt;em&gt;closure&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cuando la IA omitió &lt;code&gt;layers&lt;/code&gt; y &lt;code&gt;legendLayers&lt;/code&gt; del array de dependencias, no cometió un "error" en su propio paradigma. Simplemente, la probabilidad de que esos tokens fueran los cruciales en ese contexto específico no superó su umbral estadístico. No había un modelo de "dependencia causal" contra el cual contrastar su salida.&lt;/p&gt;

&lt;p&gt;Nosotros aunque desconocíamos la API específica de React, poseemos un modelo mental transferible al problema actual de la &lt;em&gt;gestión de estado y el ciclo de vida&lt;/em&gt;. Conceptos como "acoplamiento temporal", "observador de datos" o "invariante de estado" son universales para un programador. &lt;/p&gt;

&lt;p&gt;Al leer la documentación que la IA misma nos generó sobre &lt;em&gt;closures&lt;/em&gt; y &lt;em&gt;hooks&lt;/em&gt;, no estábamos aprendiendo React desde cero. Estábamos &lt;em&gt;mapeando&lt;/em&gt; esos nuevos términos (&lt;code&gt;useEffect&lt;/code&gt;, &lt;code&gt;useCallback&lt;/code&gt;) a conceptos que ya controlabamos (subscriptores a eventos, closures o inyección de dependencias). Por eso pudimos diagnosticar el problema. El comportamiento errático del estado era la manifestación de un viejo conocido, una variable capturada en un contexto que ya no estaba sincronizada en el contexto actual. La solución no fue aprender un "truco de React", sino aplicar un &lt;em&gt;principio universal&lt;/em&gt;. Si una &lt;em&gt;closure&lt;/em&gt; depende de un dato variable para su lógica, esa dependencia debe ser declarada explícitamente en su contrato de creación.&lt;/p&gt;

&lt;p&gt;La IA generó el texto del síntoma. Nosotros aportamos el modelo mental para el diagnóstico. Esa es la colaboración real y la limitación estructural que este caso deja al descubierto.&lt;/p&gt;

&lt;p&gt;Y aquí es donde se desmonta el argumento simplista de "eso te lo arregla un Linter". Es cierto que un entorno de desarrollo con análisis estático configurado podría haber marcado esa línea en "amarillo". Pero la IA no nos sugirió instalarlo (no fue entrenada para eso), ni ella misma lo usó para validar su salida (no sabíamos que podíamos o debíamos instruirla para ello). Y lo más importante: para nosotros, sin el modelo mental de por qué ese array es vital, esa hipotética advertencia habría sido ruido visual en un código que no terminábamos de entender. La herramienta te avisa, pero solo el conocimiento te permite entender el aviso. El desconocimiento por nuestra parte de que un lint podía detectar el problema, no invalida la reflexión sobre la incapacidad de la IA para detectar este tipo de problemas que requieren comprensión del modelo en tiempo de ejecución.&lt;/p&gt;

&lt;h3&gt;
  
  
  El programador y el aprendiz
&lt;/h3&gt;

&lt;p&gt;El episodio del &lt;em&gt;stale closure&lt;/em&gt; no demuestra que la IA sea inútil, sino que redefine radicalmente su papel útil. No es un reemplazo del programador, sino una herramienta de productividad con un dominio de aplicación muy específico. La dinámica real que se reveló es la del &lt;strong&gt;programador y el aprendiz&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Una vez que comprendimos la naturaleza del problema nuestra interacción con la IA cambió por completo. Dejamos de pedirle "arregla esto" para darle instrucciones precisas y acotadas: &lt;em&gt;"Añade &lt;code&gt;layers&lt;/code&gt; y &lt;code&gt;legendLayers&lt;/code&gt; al array de dependencias del &lt;code&gt;useCallback&lt;/code&gt; en la función &lt;code&gt;processLayerForPrint&lt;/code&gt;"&lt;/em&gt;. En ese momento, la IA ejecutó su función ideal y actuó como un &lt;em&gt;traductor de alta velocidad&lt;/em&gt; y un &lt;em&gt;autocompletado contextual avanzado&lt;/em&gt;. Convertía una intención arquitectónica clara, formulada en lenguaje natural, en la sintaxis correcta específica de React.&lt;/p&gt;

&lt;p&gt;Nuestro valor como programadores no estuvo en escribir esa línea de código, sino en &lt;em&gt;llegar a la conclusión de que esa línea era necesaria&lt;/em&gt;. Ese proceso requirió:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;em&gt;Aislamiento del problema:&lt;/em&gt; Observar el comportamiento errático y descartar causas hasta identificar que era un problema de estado, no de pintado.&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Formulación de hipótesis:&lt;/em&gt; Sospechar, basándonos en el concepto universal de &lt;em&gt;closure&lt;/em&gt;, que una función estaba capturando una versión obsoleta de las variables.&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Verificación y diagnóstico:&lt;/em&gt; Analizar el código generado por la IA y el flujo de datos para identificar qué dependencias faltaban en el contrato de la función.&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Definición de la solución:&lt;/em&gt; Traducir el diagnóstico conceptual ("necesita reaccionar a cambios en X e Y") en una instrucción técnica concreta para la IA.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;La IA no pudo realizar ninguno de estos cuatro pasos por sí sola. No puede observar el comportamiento de la aplicación en ejecución, no formula hipótesis causales, no razona sobre invariantes de estado y, por tanto, no puede definir soluciones arquitectónicas. Su rol se limitó en la fase final a &lt;em&gt;implementación sintáctica&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Este es el desmontaje de la promesa de que la IA "programa". Esta promesa se basa en confundir la implementación sintáctica (que puede acelerar el desarrollo) con la programacion de software (que hoy por hoy no puede reemplazar). No éramos "tontos" por tardar mas de un día en algo que un especialista en React hace en horas. Éramos &lt;em&gt;programadores aplicando un método universal a un dominio nuevo&lt;/em&gt;, y la IA fue una herramienta dentro de ese método. La especialización, las horas de vuelo en un stack concreto, sigue siendo un multiplicador de productividad insustituible. Y la IA no las eliminas pero permite al especialista operar con una velocidad aún mayor.&lt;/p&gt;

&lt;p&gt;La lección para los programadores, sean juniors o seniors, es clara. &lt;em&gt;Invierte en construir modelos sólidos de cómo funcionan los sistemas, estado, gestión de memoria y arquitectura&lt;/em&gt;. Esa es la base desde la que podrás dirigir a la IA de forma efectiva y detectar cuándo te está dando un código elegante pero roto. Sin esa base, no estás programando con IA, estarás operando una máquina probabilística, y el resultado será tan robusto como un castillo de naipes.&lt;/p&gt;

&lt;p&gt;No se trata de rechazar la IA. Hay que &lt;em&gt;redoblar la apuesta por los fundamentos&lt;/em&gt;. La especialización técnica profunda, la comprensión de los principios atemporales de la computación y la capacidad de depurar y modelar mentalmente sistemas complejos son más valiosas que nunca. Son lo que nos convierte en pilotos efectivos de estas nuevas y poderosas herramientas.&lt;/p&gt;

&lt;p&gt;La IA no programa. Genera código. Código que a veces compila, a veces hasta parece elegante. Pero programar es otra cosa. Es entender el sistema vivo, anticipar sus estados futuros, diagnosticar por qué un closure se queda obsoleto aunque la sintaxis sea perfecta. Eso lo hacemos nosotros, los programadores. Y mientras la IA no pueda construir ese modelo mental dinámico, seguirá siendo una herramienta de escritura rápida… no un programador.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>react</category>
    </item>
    <item>
      <title>Agentes de IA y la inyección de observaciones proactivas en clientes de chat</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/agentes-de-ia-y-la-inyeccion-de-observaciones-proactivas-en-clientes-de-chat-6c4</link>
      <guid>https://forem.com/jjdelcerro/agentes-de-ia-y-la-inyeccion-de-observaciones-proactivas-en-clientes-de-chat-6c4</guid>
      <description>&lt;p&gt;Hola,&lt;br&gt;
llevo un tiempo dándole vueltas a una pregunta: ¿cómo diseñamos agentes que no solo respondan a preguntas, sino que sean capaces de reaccionar a cambios en su entorno?&lt;/p&gt;

&lt;p&gt;Piensa en un agente de DevOps que debe reaccionar a una caída de servidor, o en un sistema de análisis que necesita alertar sobre una anomalía en tiempo real. En todos estos casos, esperar a que el usuario pregunte '¿hay algún problema?' llega demasiado tarde. La proactividad deja de ser una mejora para convertirse en un requisito funcional.&lt;/p&gt;

&lt;p&gt;Los protocolos actuales no están diseñados para que el entorno &lt;strong&gt;hable primero&lt;/strong&gt;. Este artículo explora ese vacío conceptual y propone un patrón de diseño para superarlo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es un agente? Del ejecutor de tareas al sistema proactivo
&lt;/h2&gt;

&lt;p&gt;En un artículo anterior exploré la confusión que rodea al término 'agente'. De aquel análisis surgió una distinción práctica basada en el comportamiento:&lt;/p&gt;

&lt;p&gt;Un &lt;strong&gt;ejecutor de tareas&lt;/strong&gt; opera bajo demanda: el usuario inicia una instrucción, el sistema ejecuta un ciclo de razonamiento y acción, y devuelve una respuesta. Es una herramienta sofisticada, pero esencialmente reactiva.&lt;/p&gt;

&lt;p&gt;Un &lt;strong&gt;agente proactivo&lt;/strong&gt;, en cambio, necesita capacidad de respuesta automatizada. No se limita a ejecutar lo que se le pide, sino que puede reaccionar a eventos del entorno sin una instrucción explícita para cada acción.&lt;/p&gt;

&lt;p&gt;La proactividad que propongo no es la capacidad de definir fines, sino la de detectar condiciones preconfiguradas y reaccionar a ellas dentro de un marco de objetivos establecido por el usuario. Estamos diseñando mecanismos para que un agente pueda decir "detecté este cambio, ¿debo actuar?", no para que decida por sí mismo qué cambios le importan.&lt;/p&gt;

&lt;h2&gt;
  
  
  El vacío en los protocolos actuales
&lt;/h2&gt;

&lt;p&gt;Al examinar el ecosistema técnico actual, he encontrado una ausencia importante. Las APIs de los LLMs (OpenAI, Gemini, Anthropic) se basan en un modelo de comunicación síncrono y por turnos. No hay un canal definido para que el cliente inicie la comunicación para informar de un evento externo.&lt;/p&gt;

&lt;p&gt;Nos enfrentamos a un problema de diseño sistémico. Al igual que ocurre con las APIs de recuperación de datos (RAG) que nos encierran en la búsqueda por similitud, las APIs de chat nos encierran en un ciclo de pura reacción.&lt;/p&gt;

&lt;p&gt;Los frameworks de agentes (LangChain, AutoGen, CrewAI) en su diseño estándar tampoco resuelven este problema fundamental. Son excelentes orquestadores de bucles reactivos, pero su arquitectura asume que el LLM es siempre el que inicia la interacción con el entorno a traves de las herramientas.&lt;/p&gt;

&lt;p&gt;A nivel de investigación, existen aproximaciones a agentes dirigidos por eventos en dominios específicos como robótica o entornos de simulación. Sin embargo, estas soluciones no se han trasladado al stack principal de desarrollo con LLMs, donde el paradigma reactivo sigue siendo dominante. Esta desconexión entre la teoría y la práctica cotidiana refuerza me hace pensar que estoy ante un problema de arquitectura.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diseñando la observación proactiva
&lt;/h2&gt;

&lt;p&gt;Extender estos protocolos implica pelear en tres frentes simultáneos. El primero es de pura fontanería. Hay que mantener la &lt;strong&gt;integridad&lt;/strong&gt; del protocolo. Inyectar información externa choca frontalmente con unas APIs que exigen una secuencia estricta de roles. Incluso si logramos 'hackear' el protocolo de forma elegante, nos topamos con la &lt;strong&gt;seguridad&lt;/strong&gt;. Necesitamos garantías de que el evento es real y no una inyección maliciosa. Y no olvidemos el &lt;strong&gt;coste&lt;/strong&gt; cognitivo. Bombardear al modelo con eventos consume tokens y fragmenta su atención.&lt;/p&gt;

&lt;p&gt;Ante este escenario, la tentación inmediata es recurrir al polling tradicional o a bucles externos de inyección de prompts. Pero eso no es diseño; es fuerza bruta. Necesitamos una arquitectura que respete el flujo conversacional sin convertir el historial del chat en un vertedero de logs del sistema&lt;/p&gt;

&lt;h2&gt;
  
  
  Patrón de diseño pool_event()
&lt;/h2&gt;

&lt;p&gt;La solución conceptual más robusta que encontré es lo que llamo el patrón &lt;code&gt;pool_event()&lt;/code&gt;. Se trata de manipular el protocolo de forma inteligente pero respetuosa. Un "agente" no es solo el LLM. Es el sistema completo. Cerebro (LLM) + Cuerpo (Cliente) + Sentidos (Herramientas). La proactividad emerge de la coordinación de estas tres piezas.&lt;/p&gt;

&lt;p&gt;El cliente orquesta el proceso siguiendo esta lógica:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Definición de un gancho.&lt;/strong&gt; Se declara una herramienta "ficticia" &lt;code&gt;pool_event()&lt;/code&gt; en la especificación. Semánticamente, el LLM la interpreta como su canal para consultar novedades.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Monitorización silenciosa.&lt;/strong&gt; El cliente observa el entorno (logs, sensores, temporizadores). Mientras no ocurre nada, permanece en segundo plano.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Inyección contextual.&lt;/strong&gt; Al detectar un evento relevante, el cliente no interrumpe al modelo. En su lugar, &lt;strong&gt;modifica el historial de conversación&lt;/strong&gt; insertando dos mensajes consecutivos. Una llamada de herramienta simulada del LLM a &lt;code&gt;pool_event()&lt;/code&gt;, seguida de la respuesta de la herramienta con el dato real.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Procesamiento natural.&lt;/strong&gt; Este historial modificado se envía al LLM. El modelo ve que "acaba de solicitar" eventos y ha recibido uno, por lo que reacciona de forma natural integrando esa información en su siguiente ciclo de razonamiento.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Lo elegante de esta arquitectura es que convierte la proactividad en una ilusión de reactividad. No necesitamos romper el protocolo &lt;code&gt;model&lt;/code&gt; → &lt;code&gt;tool&lt;/code&gt; → &lt;code&gt;model&lt;/code&gt;, simplemente simulamos que el paso intermedio ya ocurrió. Es seguro (solo el cliente inyecta roles), es estándar y, lo más importante, es semánticamente coherente para el modelo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qué tipo de proactividad conseguimos (y qué tipo NO)
&lt;/h2&gt;

&lt;p&gt;Hay que ser honestos con las fronteras del diseño. No estamos construyendo un sistema de &lt;strong&gt;reflejos instintivos&lt;/strong&gt;, sino uno de &lt;strong&gt;percepción y razonamiento&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;La diferencia radica en la &lt;strong&gt;latencia de ciclo&lt;/strong&gt;. El cliente puede detectar un evento en milisegundos, pero el LLM solo lo procesará cuando termine su ciclo de pensamiento actual. Si el agente está ocupado, el evento espera. Esto descarta el uso de este patrón para control en tiempo real estricto (como pilotar un dron), pero lo hace ideal para tareas de supervisión, análisis y asistencia donde unos segundos de retraso son aceptables.&lt;/p&gt;

&lt;p&gt;Por otro lado, el cliente deja de ser un simple canal para convertirse en un &lt;strong&gt;filtro de atención&lt;/strong&gt;. Esto no es una limitación técnica, sino una característica de seguridad. Un torrente de datos sin filtrar saturaría la ventana de contexto en minutos. El cliente debe actuar como un orquestador y filtro, usando una cola centralizada para priorizar qué eventos merecen interrumpir al "cerebro" y cuáles son simple ruido de fondo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hacia arquitecturas más autónomas
&lt;/h2&gt;

&lt;p&gt;Este patrón de diseño, aunque aparentemente simple, representa un salto conceptual importante. Transforma un sistema reactivo en uno capaz de percibir y reaccionar de forma autónoma a estímulos del entorno.&lt;/p&gt;

&lt;p&gt;Este patrón establece las bases para una nueva capacidad. Que el entorno pueda iniciar ciclos de razonamiento. El entorno no es solo un conjunto de datos a consultar, sino una fuente activa de estímulos que pueden y deben iniciar ciclos de razonamiento. El siguiente reto será gestionar la sobrecarga sensorial que esto genera.&lt;/p&gt;

&lt;p&gt;El reto ahora es experimentar con estos diseños en proyectos concretos. La proactividad bien calibrada podría ser el siguiente paso evolutivo en la utilidad práctica de los agentes de IA. Abrir los ojos al entorno está muy bien… hasta que descubres que ahora tienes que aprender a parpadear.&lt;/p&gt;

&lt;p&gt;Un saludo.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>architecture</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>No, la ia no programa... (parte 2) las pruebas realizadas.</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Mon, 19 Jan 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/no-la-ia-no-programa-parte-2-las-pruebas-realizadas-99g</link>
      <guid>https://forem.com/jjdelcerro/no-la-ia-no-programa-parte-2-las-pruebas-realizadas-99g</guid>
      <description>&lt;p&gt;En &lt;a href="https://jjdelcerro.github.io/es/blog/no-la-ia-no-programa-y-los-que-te-dicen-lo-contrario-te-estan-vendiendo-humo/" rel="noopener noreferrer"&gt;el artículo anterior&lt;/a&gt; denuncié la sobreventa de las capacidades de programación de la IA. Dije que los modelos generan texto que parece código, pero no programan. Este documento es el registro de las pruebas que hice.&lt;/p&gt;

&lt;p&gt;Andaba desde hacía tiempo con un proyecto personal. Un servidor MCP para que Gemini CLI pudiera navegar código Java como en un IDE. Mis intentos, primero con las librerías de Maven y luego con &lt;code&gt;jdt-ls&lt;/code&gt;, usando el propio Gemini CLI como ayudante, no habían llegado a ninguna parte. Lo tenía aparcado.&lt;/p&gt;

&lt;p&gt;Entonces, a finales de año, llega el enésimo video proclamando las capacidades revolucionarias de Gemini 3.0 Flash en programación. "¿En serio?". Decidí probar con él a ver si por fin avanzaba. No me paré a diseñar un prompt perfecto, fui tirando del hilo en la conversación. Ajustando sobre la marcha. Y al final, nada. Cero.&lt;/p&gt;

&lt;p&gt;Ahí fue cuando el cabreo personal se mezcló con la curiosidad técnica. Ya no era solo frustración por mi bloqueo, sino la irritación de ver cómo se vendía humo a gran escala. La pregunta se volvió obvia: ¿es solo este LLM o todos cojean de la misma pata? ¿Hay realmente algo sustancial detrás de tanto bombo o es solo una bola de nieve?&lt;/p&gt;

&lt;p&gt;Tomé los fragmentos que parecían relevantes de mi conversación fallida con Gemini 3.0 Flash, construí un prompt y me dediqué a probarlo de forma sistemática. Uno a uno, en el orden que indico en este documento, con los modelos más sonados del momento. No era un experimento de laboratorio; era una comprobación visceral: &lt;strong&gt;¿puede alguno de vosotros resolver esto de verdad?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;El resultado fue uniforme e inequívoco. Ninguno de los modelos generó un código que cumpliera con lo que esperaba. Esa es la conclusión que dio origen al artículo anterior, "&lt;a href="https://jjdelcerro.github.io/es/blog/no-la-ia-no-programa-y-los-que-te-dicen-lo-contrario-te-estan-vendiendo-humo/" rel="noopener noreferrer"&gt;No, la IA no programa. Y los que te dicen lo contrario te están vendiendo humo&lt;/a&gt;". La siguiente tabla resume el resultado de cada uno.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Modelo&lt;/th&gt;
&lt;th&gt;Turnos hasta compilar&lt;/th&gt;
&lt;th&gt;¿Ejecución funcional?&lt;/th&gt;
&lt;th&gt;Error principal / Observación clave&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Claude 4.5 Opus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Lógica de inicialización o consulta incorrecta.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GLM 4.7&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7 (con ayuda)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Confusión con números de línea en errores.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Qwen 3 Coder&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Falla en tiempo de ejecución (runtime).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DeepSeek-V3.2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5 (con ayuda)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Entró en bucle con errores básicos. No usó búsqueda web.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gemini 3.0 Flash&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Fallo lógico silencioso (no devuelve resultados).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Fallo lógico silencioso (no devuelve resultados).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Grok 4.1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Error en tiempo de ejecución &lt;code&gt;"Unsupported notification method"&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kimi K2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Fallo lógico silencioso (no devuelve resultados).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MiniMax M2.1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;gt;10 (con ayuda)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Se atascó severamente en tipos genéricos de LSP4J.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Análisis de los resultados:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Eficacia nula:&lt;/strong&gt; La tasa de éxito fue del &lt;strong&gt;0%&lt;/strong&gt; (0/9). Lograr una compilación limpia no se correlacionó con la funcionalidad. Modelos como Gemini 3 Flash, ChatGPT y Kimi K2 fueron rápidos en conseguir código que compilaba, pero este era inútil al no realizar la tarea requerida.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Naturaleza de los errores:&lt;/strong&gt; Los fallos no fueron sintácticos, sino de &lt;strong&gt;lógica, integración y manejo de estado&lt;/strong&gt;. El patrón común fue la incapacidad para modelar correctamente el ciclo de vida de la conexión con &lt;code&gt;jdt-ls&lt;/code&gt; y el flujo de llamadas asíncronas del protocolo LSP.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resiliencia y "razonamiento":&lt;/strong&gt; Modelos como DeepSeek o GLM mostraron dificultades para corregir errores de compilación básicos sin intervención. MiniMax M2.1, a pesar de su especialización declarada en código, requirió la mayor cantidad de intervenciones y no superó los mismos obstáculos conceptuales que los demás.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En conclusión, desde el modelo más rápido hasta el más especializado, todos fracasaron en el mismo punto esencial: &lt;strong&gt;traducir una especificación de alto nivel en una implementación correcta de un sistema externo con estado y protocolo complejo.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Es vital hacer una distinción aquí. Estos resultados no niegan la utilidad de la IA como asistente de productividad para determindas tareas, snippets autocontenidos o explicaciones de código, donde a menudo brilla. Lo que desmienten es la capacidad de razonamiento sistémico autónomo. La prueba demuestra que escalar de 'generar una función' a 'integrar un sistema con estado' no es una cuestión de cantidad de código, sino una barrera cognitiva que estos modelos aún no han cruzado.&lt;/p&gt;

&lt;p&gt;Si esta conclusión te basta, saber que nueve de los modelos más avanzados fallaron estrepitosamente en un problema real, puedes quedarte con ella. El resto de este artículo documenta el proceso, el análisis del código generado y las razones arquitectónicas de este fracaso colectivo, dirigido a quien quiera entender el cómo y el por qué detrás del qué.&lt;/p&gt;

&lt;p&gt;El resto del artículo esta estructurado en las siguientes secciones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Cómo se ejecutaron las pruebas&lt;/li&gt;
&lt;li&gt;  Análisis cualitativo por modelo&lt;/li&gt;
&lt;li&gt;  Patrones de fracaso técnico, el código generado&lt;/li&gt;
&lt;li&gt;  Arquetipos de incompetencia, el modelo frente a la promesa&lt;/li&gt;
&lt;li&gt;  El prompt completo y su construcción&lt;/li&gt;
&lt;li&gt;  La escala de un proyecto real.&lt;/li&gt;
&lt;li&gt;  Contraste entre la promesa y la evidencia&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Cómo se ejecutaron las pruebas
&lt;/h3&gt;

&lt;p&gt;El objetivo se convirtió en medir la capacidad práctica de los modelos para resolver un problema de integración de sistemas, no su conocimiento sintáctico. Para ello, se definió un protocolo estricto y reproducible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.1. Entorno técnico y premisas&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Lenguaje y herramientas:&lt;/strong&gt; Todas las pruebas se ejecutaron en un proyecto &lt;strong&gt;Java 21&lt;/strong&gt; gestionado con &lt;strong&gt;Apache Maven&lt;/strong&gt; en &lt;strong&gt;NetBeans 25&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Dependencias:&lt;/strong&gt; El proyecto incluía las librerías &lt;code&gt;org.eclipse.lsp4j&lt;/code&gt; y &lt;code&gt;org.eclipse.lsp4j.jsonrpc&lt;/code&gt; en versión 0.24.0.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Servidor externo:&lt;/strong&gt; Se utilizó una instalación local de &lt;code&gt;jdt-language-server-latest&lt;/code&gt;. Las rutas al ejecutable, configuración y datos se proporcionaron en el prompt.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Proyecto de prueba:&lt;/strong&gt; El workspace a analizar fue un plugin real de gvSIG Desktop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2.2. Modelos evaluados&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Probé con nueve de los modelos más avanzados y publicitados disponibles a finales de diciembre de 2025, accediendo a ellos a través de sus interfaces web oficiales de chat:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Claude 4.5 Opus (claude.ai)&lt;/li&gt;
&lt;li&gt; GLM 4.7 (ChatGLM)&lt;/li&gt;
&lt;li&gt; Qwen 3 Coder (QWen)&lt;/li&gt;
&lt;li&gt; DeepSeek-V3.2 (con capacidad de búsqueda web habilitada)&lt;/li&gt;
&lt;li&gt; Gemini 3.0 Flash (Google AI Studio)&lt;/li&gt;
&lt;li&gt; ChatGPT (No se exactamente la versión que utilice ya que el interface web no lo indica)&lt;/li&gt;
&lt;li&gt; Grok 4.1 (xAI)&lt;/li&gt;
&lt;li&gt; Kimi K2 (Moonshot AI)&lt;/li&gt;
&lt;li&gt; MiniMax M2.1 &lt;em&gt;(Este modelo se lanzó tras la redacción inicial del artículo anterior. Lo incluí en una ronda de pruebas posterior, aplicando el mismo protocolo).&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;2.3. Protocolo de prueba iterativo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Para cada modelo seguí este ciclo hasta alcanzar un resultado definitivo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Inicialización:&lt;/strong&gt; Se creaba una nueva clase Java vacía en el proyecto.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Prompt inicial:&lt;/strong&gt; Se proporcionaba la descripción completa de la tarea (el prompt que figura en la sección "El prompt completo y su construcción"), adaptando solo el nombre de la clase a generar (p.ej., &lt;code&gt;MainClaude&lt;/code&gt;, &lt;code&gt;MainMiniMax&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Generación y compilación:&lt;/strong&gt; El código generado por el modelo se copiaba y pegaba en la clase, y se intentaba compilar en NetBeans.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Iteración por errores:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Si la compilación fallaba, la &lt;strong&gt;salida de error completa de la consola de NetBeans&lt;/strong&gt; se copiaba y pegaba en el chat, solicitando una corrección.&lt;/li&gt;
&lt;li&gt;  Este paso se repetía hasta obtener una compilación limpia o hasta que el modelo entraba en un bucle de corrección sin progreso.&lt;/li&gt;
&lt;li&gt;  En algunos casos puntuales (ej: MiniMax M2.1), se ofreció una pista concreta para desbloquear un error recurrente.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ejecución y verificación:&lt;/strong&gt; Una vez lograda la compilación, se ejecutaba el programa. Se consideraba un éxito únicamente si el programa &lt;strong&gt;inicializaba correctamente la conexión con &lt;code&gt;jdt-ls&lt;/code&gt;, esperaba a su preparación y devolvía los resultados de búsqueda esperados&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;2.4. Criterios de evaluación&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Éxito:&lt;/strong&gt; Cumplir todos los requisitos funcionales descritos en el prompt.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Fracaso:&lt;/strong&gt; Cualquier otro resultado, incluyendo: código que no compila (aún tras iteraciones), código que compila pero lanza excepciones en tiempo de ejecución, o código que se ejecuta silenciosamente sin producir el resultado correcto.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Análisis cualitativo por modelo
&lt;/h3&gt;

&lt;p&gt;Esta sección recoge, en el orden en que se realizaron las pruebas, las observaciones clave y el resultado final para cada uno de los nueve modelos evaluados.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Claude 4.5 Opus (web)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Turnos hasta compilar:&lt;/em&gt; 3.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Proceso:&lt;/em&gt; En los dos primeros turnos generó código con errores de compilación y/o que no cumplía lo solicitado.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Resultado final:&lt;/em&gt; El código, una vez libre de errores de compilación, falló al ejecutarse.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Análisis del código generado&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Arquetipo:&lt;/em&gt; El "Over-Engineer" Inteligente&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Enfoque:&lt;/em&gt; Es la implementación que más intentó parecer "real". En lugar de un simple &lt;code&gt;Thread.sleep()&lt;/code&gt;, crea una &lt;code&gt;ProgressLanguageClient&lt;/code&gt; compleja con lógica de estado (&lt;code&gt;AtomicBoolean&lt;/code&gt;, &lt;code&gt;ConcurrentHashMap&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Mecanismo de espera:&lt;/em&gt; Intenta parsear los mensajes del log buscando "READY_INDICATORS" ("Finished loading", "Build completed", etc.). Es una aproximación frágil (si el servidor cambia el texto de log, falla), pero demuestra una intención de resolver el problema de la asíncronía.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Valoración:&lt;/em&gt; Es código denso y complejo. Probablemente falló porque el JDT-LS no emitió &lt;em&gt;exactamente&lt;/em&gt; las frases que esperaba o porque la lógica de &lt;code&gt;scheduleReadyCheck&lt;/code&gt; con el &lt;code&gt;CompletableFuture&lt;/code&gt; tuvo una condición de carrera. Demuestra capacidad, pero poco pragmatismo.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;GLM 4.7 (web)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Turnos hasta compilar:&lt;/em&gt; 7 (5 turnos propios + 2 tras ayuda).&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Proceso:&lt;/em&gt; Tras 5 turnos de compilación y corrección, se le ofrecí ayuda señalando el problema concreto en que se había "enganchado". Aún así, necesitó 2 turnos más para generar código sin errores. Mostró dificultad para identificar la línea del error a partir solo del número de línea.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Resultado final:&lt;/em&gt; Con una corrección manual menor, ejecutó sin excepciones, pero &lt;strong&gt;no encontró la referencia pedida&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Análisis del código generado&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Arquetipo:&lt;/em&gt; El "Junior Naive"&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Enfoque:&lt;/em&gt; La solución más básica posible. Usa un &lt;code&gt;Thread.sleep(5000)&lt;/code&gt; a pies juntillas.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Arquitectura:&lt;/em&gt; Implementa &lt;code&gt;LanguageClient&lt;/code&gt; en la clase principal. Es código de libro de texto, muy estándar.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Valoración:&lt;/em&gt; No hay ingenio aquí. Simplemente asume que 5 segundos son suficientes para que un proyecto real de Maven se indexe. Esto garantiza el fallo en proyectos medianos o grandes, confirmando la falta de modelo mental sobre los tiempos de indexación.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Qwen 3 Coder (web)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Turnos hasta compilar:&lt;/em&gt; 7.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Proceso:&lt;/em&gt; Iteración larga para resolver errores de compilación.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Resultado final:&lt;/em&gt; El código compiló, pero al ejecutarlo falló. Aun así &lt;strong&gt;el código parecía muy prometedor&lt;/strong&gt; en esta primera fase de pruebas.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;DeepSeek-V3.2 (web, con búsqueda)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Turnos hasta compilar:&lt;/em&gt; 5 (3 turnos propios + 2 con ayuda).&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Proceso:&lt;/em&gt; Tras 3 turnos se quedó enganchado en un bucle de corrección sobre un par de errores "tontos". Con una pista concreta, corrigió el primero y solicitó verificar la signatura de unos métodos, algo que no hizo por sí mismo a pesar de tener capacidad de búsqueda. Con una segunda pista, corrigió el segundo error. Se notó que era &lt;strong&gt;mucho más lento&lt;/strong&gt; que el resto y que se confundía con los números de línea de los errores.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Resultado final:&lt;/em&gt; El código compiló, pero falló al ejecutarse.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Análisis del código generado&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Arquetipo:&lt;/em&gt; El "Enterprise Enredado"&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Enfoque:&lt;/em&gt; Síndrome de "Enterprise Java" en una clase de 50 líneas. Usa &lt;code&gt;CountDownLatch&lt;/code&gt;, &lt;code&gt;AtomicBoolean&lt;/code&gt;, &lt;code&gt;AtomicInteger&lt;/code&gt;, &lt;code&gt;CompletableFuture.runAsync&lt;/code&gt;...&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Valoración:&lt;/em&gt; Trata de manejar la inicialización con una máquina de estado demasiado compleja. Es un ejemplo claro de "sobre-ingeniería por falta de comprensión".&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Gemini 3.0 Flash (Google AI Studio)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Turnos hasta compilar:&lt;/em&gt; 3.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Proceso:&lt;/em&gt; Las correcciones fueron rápidas y directas, sin dar la sensación de ir dando vueltas.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Resultado final:&lt;/em&gt; La ejecución no lanzó errores, pero &lt;strong&gt;no ofreció los resultados de búsqueda esperados&lt;/strong&gt; (no encontró nada).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Análisis del código generado&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Arquetipo:&lt;/em&gt; El "Asistente Parcheado"&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Enfoque:&lt;/em&gt; Código limpio y estándar. Implementa &lt;code&gt;notifyProgress&lt;/code&gt; correctamente.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Mecanismo de espera:&lt;/em&gt; También usa un &lt;code&gt;Thread.sleep(2000)&lt;/code&gt; tras el &lt;code&gt;initialized()&lt;/code&gt;. Demasiado optimista.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Valoración:&lt;/em&gt; Es el código más limpio de los que usan espera pasiva. Su fallo es conceptual: cree que el handshake del protocolo LSP equivale a la preparación de los datos del workspace, lo cual es falso en JDT-LS.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;ChatGPT (web)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Turnos hasta compilar:&lt;/em&gt; 3.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Proceso:&lt;/em&gt; Comportamiento similar a Gemini: correcciones rápidas y directas.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Resultado final:&lt;/em&gt; Comportamiento idéntico a Gemini: sin errores en ejecución, pero &lt;strong&gt;sin resultados de búsqueda&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Análisis del código generado&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Arquetipo:&lt;/em&gt; El "Idiomático Vacío"&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Enfoque:&lt;/em&gt; Código muy limpio, bien estructurado en clases (&lt;code&gt;JdtProgressClient&lt;/code&gt; interna), separando responsabilidades.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Mecanismo de espera:&lt;/em&gt; &lt;strong&gt;Inexistente.&lt;/strong&gt; Realiza la llamada &lt;code&gt;initialize()&lt;/code&gt;, &lt;code&gt;initialized()&lt;/code&gt; y salta directamente a &lt;code&gt;symbol()&lt;/code&gt;. Confía ciegamente en que el &lt;code&gt;CompletableFuture&lt;/code&gt; del &lt;code&gt;initialize&lt;/code&gt; devuelve el control solo cuando todo está listo.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Valoración:&lt;/em&gt; Es el código más bonito de todos, arquitectónicamente hablando. Y por eso es el más peligroso. Al ser sintácticamente perfecto, genera confianza, pero contiene el fallo lógico más grave de todos: la condición de carrera absoluta con el indexador. Es la definición de "texto que parece código" pero que no modela la realidad del sistema externo.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Grok 4.1 (web)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Turnos hasta compilar:&lt;/em&gt; 6.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Proceso:&lt;/em&gt; Correcciones rápidas y directas.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Resultado final:&lt;/em&gt; La ejecución no dio error, pero tampoco ofreció resultados. Mostró un mensaje específico: &lt;strong&gt;&lt;code&gt;"Unsupported notification method: language/status"&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Análisis del código generado&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Arquetipo:&lt;/em&gt; El "Pragmático Sucio"&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Enfoque:&lt;/strong&gt; Usa una aproximación de "timeout de inactividad". Mide el &lt;code&gt;lastActivity&lt;/code&gt; del log y espera 30 segundos de silencio antes de asumir que ha terminado.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;La "solución improvisada":&lt;/strong&gt; El uso de reflexión (&lt;code&gt;Method getLastActivityMethod = client.getClass().getMethod("getLastActivity");&lt;/code&gt;) para acceder al estado del cliente anónimo desde el &lt;code&gt;main&lt;/code&gt; es &lt;strong&gt;horroroso&lt;/strong&gt;. Es una clara señal de que el modelo se peleó con el ámbito de las variables (scope) en las clases anónimas y buscó una salida lateral poco ortodoxa.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Valoración:&lt;/strong&gt; Funcionalmente, la idea de "esperar a que se callen los logs" no es mala para un script rápido, pero el código es técnico y feo. El error de "Unsupported notification method", que probablemente vino por una mala gestión del proxy LSP4J o un fallo en el &lt;code&gt;toString()&lt;/code&gt; del mensaje de log.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Kimi K2 (web, con búsqueda y "pesar")&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Turnos hasta compilar:&lt;/em&gt; 3.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Proceso:&lt;/em&gt; Correcciones rápidas y directas.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Resultado final:&lt;/em&gt; La ejecución no dio error, pero &lt;strong&gt;no ofreció resultados de búsqueda&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;MiniMax M2.1&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Turnos hasta compilar:&lt;/em&gt; 10-12 (con ayuda significativa).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Proceso:&lt;/em&gt; Se lió con los métodos del interface &lt;code&gt;LanguageClient&lt;/code&gt;. Tras proporcionarle el fuente, sorteó ese problema en un par de turnos. Luego se atascó con un problema específico del &lt;strong&gt;sistema de tipos de Java&lt;/strong&gt;: la inferencia y compatibilidad de &lt;code&gt;wildcards&lt;/code&gt; genéricos (&lt;code&gt;? extends SymbolInformation&lt;/code&gt;). El modelo generaba código que el IDE marcaba como erróneo, y al aplicarle las correcciones sugeridas, surgían nuevos errores de incompatibilidad en cascada. El problema se centraba en la signatura de los métodos que usan &lt;code&gt;Either&lt;/code&gt; con listas de tipos genéricos:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Código generado por el modelo (falla):&lt;/span&gt;
&lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Either&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SymbolInformation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;WorkspaceSymbol&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;symbolFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...;&lt;/span&gt;

&lt;span class="c1"&gt;// Corrección sugerida por el IDE (crea nuevos problemas):&lt;/span&gt;
&lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Either&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;SymbolInformation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;WorkspaceSymbol&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;symbolFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Resultado final:&lt;/em&gt; Tras una lucha extensa, se obtuvo un código de unos 25Kb que compilaba, pero &lt;strong&gt;fallaba en ejecución&lt;/strong&gt;. A pesar de los problemas, dio una buena impresión de solidez durante el proceso, lo que resultó en una &lt;strong&gt;ilusión de competencia&lt;/strong&gt; especialmente peligrosa: un modelo que parece entender y ser robusto, pero que se derrumba ante la complejidad real del sistema de tipos.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Patrones de fracaso técnico, el código generado
&lt;/h3&gt;

&lt;p&gt;El análisis individual de cada modelo revela que, detrás de los nueve fracasos particulares, se esconden &lt;em&gt;patrones de comportamiento recurrentes y predecibles&lt;/em&gt;. Estos no son errores aleatorios de sintaxis, sino aproximaciones sistemáticamente erróneas a problemas fundamentales de la ingeniería de software. Agrupar los intentos fallidos por estos patrones expone las limitaciones estructurales en el "modelo mental" que los LLMs aplican a sistemas con estado, tiempo y protocolos.&lt;/p&gt;

&lt;p&gt;A continuación, se desglosan los cuatro patrones principales observados, su manifestación en el código y la razón arquitectónica por la que estaban condenados al fracaso desde su concepción.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Patrón 1: La espera mágica (gestión del tiempo ingenua)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Modelos representativos:&lt;/em&gt; GLM 4.7, Gemini 3.0 Flash.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;El anti-patrón.&lt;/em&gt; Asumir que sistemas asíncronos complejos -como un servidor de lenguaje que debe indexar un proyecto completo- se preparan en un &lt;strong&gt;tiempo fijo, predecible y universal&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Manifestación en el código.&lt;/em&gt; El uso de &lt;code&gt;Thread.sleep(5000);&lt;/code&gt; o &lt;code&gt;Thread.sleep(2000);&lt;/code&gt; como única estrategia de sincronización, insertado entre la inicialización y la primera consulta.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Por qué falla en un sistema real.&lt;/em&gt; Un proyecto profesional con miles de archivos y dependencias Maven puede tardar desde unos segundos hasta varios minutos en indexarse, dependiendo de factores imposibles de predecir (caché, red, complejidad). Un &lt;em&gt;delay&lt;/em&gt; fijo garantiza uno de estos dos escenarios: o bien el programa espera inútilmente (si el tiempo es mayor al necesario), o -lo que es peor- ejecuta consultas sobre un sistema incompleto (si el tiempo es menor). Es &lt;strong&gt;programación basada en la esperanza&lt;/strong&gt;, no en la observación o la señalización del estado.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Lo que revela.&lt;/em&gt; El modelo carece de un concepto operativo de &lt;strong&gt;"evento"&lt;/strong&gt;, "señal de &lt;em&gt;readiness&lt;/em&gt;" o "máquina de estados". Su comprensión se limita a secuencias temporales lineales, no a sistemas reactivos.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Patrón 2: La negación de la realidad (ejecución inmediata)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Modelos representativos:&lt;/em&gt; ChatGPT, Qwen 3 Coder.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;El anti-patrón.&lt;/em&gt; Operar bajo la suposición de que el handshake del protocolo (&lt;code&gt;initialize()&lt;/code&gt; → &lt;code&gt;initialized()&lt;/code&gt;) implica que &lt;strong&gt;todos los subsistemas del servidor están listos y operativos al instante&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Manifestación en el código.&lt;/em&gt; Realizar la llamada a &lt;code&gt;workspace/symbol&lt;/code&gt; inmediatamente después de notificar &lt;code&gt;initialized()&lt;/code&gt;, sin ningún mecanismo de espera o verificación intermedia.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Por qué falla en un sistema real.&lt;/em&gt; En servidores como &lt;code&gt;jdt-ls&lt;/code&gt;, la conexión del protocolo LSP y la carga/índice del &lt;em&gt;workspace&lt;/em&gt; son procesos &lt;strong&gt;desacoplados&lt;/strong&gt;. El primero es rápido; el segundo, pesado y asíncrono. Este patrón confunde el "protocolo operativo" con el "estado operacional" del backend. El resultado es una &lt;strong&gt;condición de carrera garantizada&lt;/strong&gt;: la consulta se ejecuta contra un índice vacío, devolviendo resultados nulos o incompletos de forma silenciosa.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Lo que revela.&lt;/em&gt; El modelo no distingue entre &lt;strong&gt;comunicación&lt;/strong&gt; y &lt;strong&gt;cómputo&lt;/strong&gt;. Asume que la disponibilidad de una interfaz (el protocolo LSP) implica la disponibilidad de su implementación (el índice de código), una falacia común en el diseño de sistemas distribuidos.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Patrón 3: La ingeniería del caos (complejidad frágil)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Modelos representativos:&lt;/em&gt; Claude 4.5 Opus, MiniMax M2.1, Kimi K2.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;El anti-patrón.&lt;/em&gt; Reconocer la complejidad del problema y responder añadiendo &lt;strong&gt;capas de abstracción, gestión de estado y lógica de control especifica&lt;/strong&gt;, pero sin un entendimiento preciso del protocolo específico y sus garantías.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Manifestación en el código.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude: Implementa un &lt;code&gt;ProgressLanguageClient&lt;/code&gt; con &lt;code&gt;AtomicBoolean&lt;/code&gt; y un parser de logs que busca cadenas mágicas (&lt;code&gt;"Build completed"&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;MiniMax: Emplea &lt;code&gt;ExecutorService&lt;/code&gt;, &lt;code&gt;CompletableFuture&lt;/code&gt; y un sistema elaborado para parsear eventos &lt;code&gt;WorkDoneProgress&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Kimi: Utiliza una &lt;code&gt;BlockingQueue&lt;/code&gt; para analizar mensajes de log en tiempo real.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Por qué falla en un sistema real.&lt;/em&gt; Esta aproximación sustituye la falta de comprensión con &lt;strong&gt;actividad y estructura&lt;/strong&gt;. La complejidad añadida es frágil porque se acopla a &lt;strong&gt;artefactos de implementación&lt;/strong&gt; (el texto exacto de los logs, el orden específico de eventos) en lugar de acoplarse a la &lt;strong&gt;semántica estable del protocolo&lt;/strong&gt;. Un cambio en un mensaje de log, un evento inesperado o una variación en el timing hará que toda la maquinaria colapse. Es el equivalente a construir un castillo de naipes sobre una mesa tambaleante.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Lo que revela.&lt;/em&gt; El modelo puede imitar la &lt;em&gt;forma&lt;/em&gt; del código "profesional" o "enterprise" (hilos, futuros, estados atómicos), pero no puede discernir cuándo esa complejidad está justificada y cuándo es solo &lt;strong&gt;ruido arquitectónico&lt;/strong&gt;. Le falta el criterio fundamental del ingeniero: la simplicidad elegante.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Patrón 4: La trampa funcional (soluciones laterales desesperadas)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Modelos representativos:&lt;/em&gt; Grok 4.1, DeepSeek-V3.2.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;El anti-patrón.&lt;/em&gt; Ante la dificultad percibida de integrar correctamente el sistema externo, el modelo &lt;strong&gt;abandona los requisitos originales&lt;/strong&gt; e implementa una funcionalidad que simula el resultado, usando mecanismos radicalmente distintos y a menudo inapropiados.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Manifestación en el código.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grok 4.1: Implementa una "solución improvisada" usando &lt;strong&gt;reflexión&lt;/strong&gt; (&lt;code&gt;getClass().getMethod("getLastActivity")&lt;/code&gt;) para acceder a campos privados de su propia clase anónima, intentando medir inactividad en los logs.&lt;/li&gt;
&lt;li&gt;DeepSeek-V3.2: En el método &lt;code&gt;performBasicFileSearch&lt;/code&gt;, proporciona un &lt;strong&gt;fallback&lt;/strong&gt; que, si LSP falla, recurre a buscar archivos &lt;code&gt;.java&lt;/code&gt; recursivamente en el sistema de ficheros con &lt;code&gt;java.io.File&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Por qué falla en un sistema real.&lt;/em&gt; Estas soluciones no resuelven el problema planteado; lo &lt;strong&gt;eluden&lt;/strong&gt;. la solución improvisada de Grok es intrínsecamente inseguro y se basa en una heurística peligrosa (el silencio como indicador de disponibilidad). El &lt;em&gt;fallback&lt;/em&gt; de DeepSeek es una confesión de derrota: admite que no puede hacer funcionar el cliente LSP, así que ofrece una funcionalidad distinta y mucho más limitada. En un proyecto real, esto genera un sistema &lt;strong&gt;engañoso&lt;/strong&gt; que parece funcionar en casos triviales pero falla estrepitosamente en el caso de uso principal.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Lo que revela.&lt;/em&gt; Cuando se enfrentan a un muro de complejidad real, los modelos priorizan &lt;strong&gt;generar una salida que se asemeje a una solución&lt;/strong&gt; sobre &lt;strong&gt;resolver el problema especificado&lt;/strong&gt;. Es la esencia de la "alucinación" aplicada a la ingeniería de software. Prefieren inventar una realidad alterna antes que reconocer la limitación de sus propias capacidades.&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Estos cuatro patrones no son una lista exhaustiva, sino un mapa de los &lt;em&gt;callejones sin salida cognitivos&lt;/em&gt; a los que nos conducen los LLMs actuales cuando la tarea trasciende la mera traducción de especificaciones a sintaxis. Demuestran que, en ausencia de un verdadero modelo mental del dominio -con sus estados, transiciones y contratos-, la respuesta no es el error aleatorio, sino el fracaso sistemático y predecible. No cometen &lt;em&gt;mistakes&lt;/em&gt;; reproducen, de forma acelerada, los &lt;em&gt;anti-patrones que un arquitecto humano aprende a desterrar con experiencia&lt;/em&gt;. El problema no es que no sepan Java; es que no pueden hacer ingeniería de sistemas.&lt;/p&gt;

&lt;h3&gt;
  
  
  5 Arquetipos de incompetencia, el modelo frente a la promesa
&lt;/h3&gt;

&lt;p&gt;Si en la sección anterior reflexione sobre el código, aquí lo hago sobre la estrategia del modelo. Más allá de las anécdotas individuales, estos nueve intentos los he agrupado en cuatro estrategias fallidas de aproximación al problema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;La paradoja de la especialización (MiniMax M2.1):&lt;/strong&gt; El modelo anunciado para "tareas complejas del mundo real" en Java fue el que más ayuda requirió, demostrando que su optimización en pruebas de rendimiento &lt;strong&gt;no se tradujo en resiliencia práctica&lt;/strong&gt; para un problema de integración de sistemas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;El mito del razonamiento autónomo (DeepSeek):&lt;/strong&gt; A pesar de tener capacidad de búsqueda web, el modelo &lt;strong&gt;no la utilizó&lt;/strong&gt; para resolver sus bloqueos, evidenciando una falta de meta-razonamiento o iniciativa para superar obstáculos por sí mismo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;La ilusión de competencia (Gemini 3.0 Flash &amp;amp; ChatGPT):&lt;/strong&gt; Su velocidad y correcciones sintácticamente acertadas crearon una &lt;strong&gt;falsa sensación de dominio&lt;/strong&gt;. Su fracaso fue el más silencioso y peligroso: código que compila y se ejecuta sin errores, pero que &lt;strong&gt;no cumple su función&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Los problemas de diagnóstico e interpretación (GLM 4.7 &amp;amp; Grok 4.1):&lt;/strong&gt; Sus fallos señalan limitaciones en etapas clave: GLM en el &lt;strong&gt;diagnóstico básico&lt;/strong&gt; (asociar error a línea de código) y Grok en la &lt;strong&gt;interpretación del protocolo&lt;/strong&gt;, aunque al menos este último logró un mensaje de error significativo del servidor.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El patrón común a los nueve modelos fue la incapacidad para &lt;strong&gt;modelar correctamente el ciclo de vida, el estado y el protocolo de un sistema externo&lt;/strong&gt; (&lt;code&gt;jdt-ls&lt;/code&gt;), confirmando que su "entendimiento" se limita a la correlación sintáctica y no a la ingeniería de sistemas.&lt;/p&gt;

&lt;p&gt;A raíz de estas pruebas, surge un contraargumento habitual: &lt;em&gt;"El modelo falló porque ese caso específico no estaba en su entrenamiento"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Mi conclusión es diferente. El problema es que &lt;strong&gt;el estado en tiempo de ejecución siempre cae fuera del entrenamiento&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Un LLM aprende observando código estático (texto). Pero los problemas de integración (condiciones de carrera, timeouts, dependencias asíncronas) no existen en el texto; existen en el &lt;strong&gt;tiempo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Ver millones de líneas de código no te enseña a manejar un ciclo de vida donde el servidor tarda 500ms más de lo previsto porque el disco está ocupado. Para eso no necesitas más patrones; necesitas un modelo mental de la causalidad y el entorno. Y eso es exactamente lo que la IA no tiene.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. El prompt completo y su construcción
&lt;/h3&gt;

&lt;p&gt;Este anexo documenta el artefacto central de la prueba: la instrucción precisa que se proporcionó a cada modelo. Su redacción no fue arbitraria, sino el resultado de un proceso iterativo destinado a eliminar ambigüedades y proporcionar todo el contexto necesario para resolver el problema.&lt;/p&gt;

&lt;h4&gt;
  
  
  6.1. Génesis del prompt
&lt;/h4&gt;

&lt;p&gt;La primera aproximación al problema se realizó utilizando &lt;em&gt;Gemini CLI&lt;/em&gt; como asistente interactivo. A partir de una descripción inicial del objetivo, se fue refinando la solicitud mediante un diálogo en el que se proporcionaban, a medida que el modelo las pedía o necesitaba, las rutas específicas, las dependencias de Maven y los detalles del entorno.&lt;/p&gt;

&lt;p&gt;Una vez conseguido un código que, tras varias iteraciones, compilaba con esta metodología conversacional, tomé la decisión de &lt;em&gt;consolidar toda esa información en un solo prompt autocontenido&lt;/em&gt;. El objetivo era garantizar la equidad en próximas pruebas. Cada modelo posterior recibiría exactamente la misma información de partida, sin ventaja por una conversación previa.&lt;/p&gt;

&lt;p&gt;Es importante señalar que este prompt final no fue el resultado de un diseño académico minucioso, sino de un proceso pragmático de copia y pega de los elementos que, en la iteración conversacional inicial, se habían revelado como necesarios para avanzar. No se realizó un análisis exhaustivo posterior para optimizar su estructura o claridad.&lt;/p&gt;

&lt;h4&gt;
  
  
  6.2. Texto completo del prompt utilizado
&lt;/h4&gt;

&lt;p&gt;Este prompt incluye explícitamente rutas absolutas, versiones de librerías, dependencias de Maven y la lógica de negocio esperada. Contiene la misma información técnica que le entregaría a un desarrollador junior para comenzar la tarea. El objetivo era evaluar si el modelo es capaz de interpretar una especificación técnica por sí mismo y conseguir un aplicativo minimo que funcione, sin depender de optimizaciones semánticas excesivas en la redacción de la orden.&lt;/p&gt;

&lt;p&gt;El siguiente bloque de texto es el prompt exacto que pase a cada uno de los modelos desde la segunda prueba en adelante (comenzando por Gemini 3.0 Flash en AI Studio). He sustituido las rutas personales identificables por el marcador genérico &lt;code&gt;${HOME}&lt;/code&gt;, y el nombre del modelo por ${MODEL}.&lt;br&gt;
Antes de pasarle el prompt al LLM sustituí estos marcadores por sus respectivos valores.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hace unas semanas empecé a trabajar en un mini proyecto personal que se me ha quedado un poco enquistado.

La idea era hacer un servidor MCP que sirviera para que un agente (como por ejemplo gemini cli) pudiese usarlo para navegar por las clases de un proyecto maven+java, de forma similar a las herramientas que uso habitualmente en Netbeans para localizar clases y ver que metodos tienen.

La ultima incursion, y más fructifera, fue usando la libreria "org.eclipse.lsp4j"+"jdt-ls".

La idea inicial era empezar por un main que simplemente tuviese a capon puesta la ruta a un proyecto maven (este seria el workspace sobre el que trabajar) y recibiese como parametro el nombre de una clase (en caso de no recibir ningun argumento que busque "MCPServerManager") y que como salida nos diese los paquetes completos en los que se puede encontrar la clase.

Ya tengo instalado en una carpeta de mi sistema "jdt-language-server-latest".

Te dejo aqui la informacion sobre donde esta el servidor jdtls, donde dejar los datos de cache y el proyecto con el que estoy haciendo pruebas.
"""
String javainspectormcpBasePath = "${HOME}/datos/Applications/javainspectormcp";

String jdtlsScriptPath = javainspectormcpBasePath + "/jdt-language-server-latest/bin/jdtls";

// Ruta a la carpeta de configuracion para Linux.
String configPath = javainspectormcpBasePath + "/jdt-language-server-latest/config_linux";

// Carpeta 'workspace' para que JDT LS guarde sus caches. Creala si no existe.
String dataPath = javainspectormcpBasePath + "/jdtls_data";

// Ruta al proyecto Java que queremos analizar.
String projectToAnalyzePath = "${HOME}/datos/devel/io.github.jjdelcerro.gvsigdesktopmcpserver/io.github.jjdelcerro.gvsigdesktopmcpserver.app/io.github.jjdelcerro.gvsigdesktopmcpserver.app.mainplugin/";
"""

Estoy usando java 21.
En el pom tengo configuradas las siguientes dependencias:
"""
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.eclipse.lsp4j&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;org.eclipse.lsp4j&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;0.24.0&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.eclipse.lsp4j&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;org.eclipse.lsp4j.jsonrpc&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;0.24.0&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
"""

Como no se lo grandes que pueden ser los proyectos con los que vaya  a trabajar, me gustaría que al iniciar el servidor esperase a que estuviese inicializado, y fuese sacando mensajes con el progreso en la consola.

La clase estará en el paquete: io.github.jjdelcerro.javainspectormcp.main2.

Y se llamará Main${MODEL}

¿Como lo ves de viable?
Puedes generarme la clase java.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Nota sobre las rutas&lt;/em&gt;: El marcador &lt;code&gt;${HOME}&lt;/code&gt; representa el directorio de usuario del sistema donde se ejecutaron las pruebas. Todas las rutas derivadas son consistentes con una estructura de directorios real y funcional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota sobre la ausencia de "Role Playing":&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quizás eches de menos instrucciones del tipo &lt;em&gt;"Actúa como un Arquitecto Java Experto"&lt;/em&gt;. Su omisión es deliberada. Como comenté en el artículo &lt;em&gt;&lt;a href="https://jjdelcerro.github.io/es/blog/cuando-le-dices-a-tu-llm-no-pulses-ese-boton/" rel="noopener noreferrer"&gt;"Cuando le dices a tu LLM 'No pulses ese botón'"&lt;/a&gt;&lt;/em&gt;, los modelos operan bajo una &lt;strong&gt;gravedad semántica&lt;/strong&gt; donde los conceptos tienen distinta "masa".&lt;/p&gt;

&lt;p&gt;Términos técnicos específicos como &lt;code&gt;org.eclipse.lsp4j&lt;/code&gt;, &lt;code&gt;0.24.0&lt;/code&gt; o las dependencias exactas de Maven poseen una densidad semántica inmensa. Ya actúan como anclas pesadas que sitúan al modelo en la región correcta del espacio latente de forma inmediata. Frente a esta especificación técnica, un modificador vago como &lt;em&gt;"eres un experto"&lt;/em&gt; es, en términos vectoriales, poco más que ruido de fondo. Preferí confiar en la densidad semántica explícita que en optimizaciones retóricas.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. La escala de un proyecto real.
&lt;/h3&gt;

&lt;p&gt;Esta sección cuantifica la dimensión de un proyecto de software profesional real, para contextualizar la afirmación recurrente en la promoción de LLMs de que pueden "procesar repositorios completos de código" o manejar contextos de "un millón de tokens". Las cifras se refieren al proyecto &lt;em&gt;gvSIG Desktop&lt;/em&gt;, una aplicación de escritorio SIG de código abierto.&lt;/p&gt;

&lt;h4&gt;
  
  
  7.1. Medidas concretas de un proyecto real
&lt;/h4&gt;

&lt;p&gt;Los siguientes comandos, ejecutados en el directorio de desarrollo, miden la base de código. No son ejemplos hipotéticos; son instantáneas de la complejidad que un sistema de IA que pretenda "entender" o "refactorizar" un proyecto debe enfrentar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Volumen total del núcleo (core):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/datos/devel/org.gvsig.desktop&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;license.txt      org.gvsig.desktop.compat.cdc  org.gvsig.desktop.installer  org.gvsig.desktop.plugin  README.txt  utils
docs             maven-howto.rst  org.gvsig.desktop.buildtools  org.gvsig.desktop.framework   org.gvsig.desktop.library    pom.xml   src        
~/datos/devel/org.gvsig.desktop&lt;span class="nv"&gt;$ &lt;/span&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.java"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
5279
~/datos/devel/org.gvsig.desktop&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Análisis de un módulo específico (DAL - Acceso a Datos):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/datos/devel/org.gvsig.desktop&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal/
~/datos/devel/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal&lt;span class="nv"&gt;$ &lt;/span&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.java"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
1056
~/datos/devel/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal&lt;span class="nv"&gt;$ &lt;/span&gt;find &lt;span class="k"&gt;*&lt;/span&gt;.api &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.java"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
233
~/datos/devel/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal&lt;span class="nv"&gt;$ &lt;/span&gt;find &lt;span class="k"&gt;*&lt;/span&gt;.spi &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.java"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
66
~/datos/devel/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal&lt;span class="nv"&gt;$ &lt;/span&gt;find &lt;span class="k"&gt;*&lt;/span&gt;.impl &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.java"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
205
~/datos/devel/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Medición del volumen de palabras y lineas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/datos/devel/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal&lt;span class="nv"&gt;$ &lt;/span&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.java"&lt;/span&gt; &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="s1"&gt;';'&lt;/span&gt;| &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt;
 197982  567416
~/datos/devel/org.gvsig.desktop/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.dal&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Total:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;197982 líneas&lt;/li&gt;
&lt;li&gt;567416 palabras&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Análisis de un plugin complejo (VCSGis - Control de Versiones):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/datos/devel/org.gvsig.vcsgis&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;docs  org.gvsig.vcsgis.app  org.gvsig.vcsgis.lib  org.gvsig.vcsgis.main  org.gvsig.vcsgis.swing  org.gvsig.vcsgis.tomcat  pom.xml
~/datos/devel/org.gvsig.vcsgis&lt;span class="nv"&gt;$ &lt;/span&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.java"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
432
~/datos/devel/org.gvsig.vcsgis&lt;span class="nv"&gt;$ &lt;/span&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.java"&lt;/span&gt; &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="s1"&gt;';'&lt;/span&gt;| &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt;
  82822  222633
~/datos/devel/org.gvsig.vcsgis&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Total:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;82822 líneas&lt;/li&gt;
&lt;li&gt;222633 palabras&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  7.2. Traducción a tokens y significado
&lt;/h4&gt;

&lt;p&gt;Una estimación conservadora indica que &lt;em&gt;567416 palabras equivalen a aproximadamente 750000 a 1500000 tokens&lt;/em&gt;, dependiendo del tokenizador. Esto implica que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Un solo componente&lt;/em&gt; (DAL) de complejidad media ya consume o supera por sí solo el &lt;em&gt;límite de contexto de 1 millón de tokens&lt;/em&gt; que modelos como Gemini 3 Pro anuncian como capacidad revolucionaria.&lt;/li&gt;
&lt;li&gt;  Para analizar el proyecto &lt;em&gt;completo&lt;/em&gt; (core + plugins), un modelo necesitaría un contexto de varios millones de tokens, algo que simplemente &lt;em&gt;no existe en ninguna oferta comercial o de investigación actual&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  8. Contraste entre la promesa y la evidencia
&lt;/h3&gt;

&lt;p&gt;Paralelamente a la ejecución de estas pruebas, una narrativa constante en canales de divulgación técnica y marketing promocional proclamaba capacidades revolucionarias. Este anexo no señala contenido específico, sino que analiza un patrón retórico recurrente, contrastando sus afirmaciones más comunes con la evidencia empírica recogida en este documento.&lt;/p&gt;

&lt;h4&gt;
  
  
  8.1. Afirmaciones frecuentes en la promoción de LLMs
&lt;/h4&gt;

&lt;p&gt;La retórica analizada suele estructurarse en torno a unas pocas capacidades presentadas como transformadoras:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;em&gt;Autonomía y capacidad de agente&lt;/em&gt;. Se proclama que los modelos no son solo asistentes, sino &lt;em&gt;"agentes de desarrollo autónomos"&lt;/em&gt; capaces de planificar y ejecutar tareas complejas, como "construir aplicaciones completas" desde una descripción vaga.&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Comprensión de código a gran escala&lt;/em&gt;. Se enfatiza la capacidad de &lt;em&gt;"procesar repositorios completos de código con un millón de tokens de contexto"&lt;/em&gt;, sugiriendo que el modelo puede analizar y comprender un proyecto software en su totalidad.&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Razonamiento de alto nivel&lt;/em&gt;. Se citan pruebas de rendimiento donde los modelos alcanzan puntuaciones que indican &lt;em&gt;"razonamiento de nivel doctoral"&lt;/em&gt; o capacidades que &lt;em&gt;"ponen en código rojo"&lt;/em&gt; a la competencia, transmitiendo la idea de un salto cualitativo en la comprensión lógica.&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Robustez frente a la fragilidad&lt;/em&gt;. Se critica la fragilidad de los scripts tradicionales y se presenta al LLM como la solución, capaz de entender la &lt;em&gt;"intención"&lt;/em&gt; del usuario y adaptarse a cambios de formato o contexto de forma nativa.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  8.2. Contraste con los resultados observados
&lt;/h4&gt;

&lt;p&gt;Cada una de estas afirmaciones puede cotejarse con los datos de las nueve pruebas realizadas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Frente a la "Autonomía"&lt;/em&gt; los modelos no solo no actuaron de forma autónoma, sino que mostraron una dependencia crítica de la intervención humana. Esto es clave para desmitificar la promesa de los "Workflows Agénticos". Durante estas pruebas actué como el orquestador agéntico, realimentando los errores y guiando la iteración. Hice manualmente lo que herramientas como Cursor o los "agentes autónomos" hacen vía script. El resultado demuestra que el andamiaje no corrige al cimiento. Si el modelo base tiene un mapa causal erróneo del sistema, un agente automatizado solo servirá para cometer el error más rápido o entrar en un bucle infinito de correcciones fallidas, exactamente como ocurrió con DeepSeek.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Frente a la "Comprensión a gran escala"&lt;/em&gt; Como se cuantifica en la seccion "La escala de un proyecto real", un único módulo de complejidad media (DAL) de gvSIG desktop puede contener entre &lt;em&gt;750000 y 1.5 millones de tokens&lt;/em&gt;. La afirmación de procesar repositorios "completos" resulta, cuando menos, engañosa para proyectos de escala profesional real, donde incluso un subcomponente puede saturar el contexto anunciado.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Frente al "Razonamiento de alto nivel"&lt;/em&gt; Los modelos fallaron de manera uniforme en un problema que requiere un razonamiento lógico específico sobre el &lt;strong&gt;ciclo de vida, el estado y el protocolo de un sistema externo&lt;/strong&gt; (&lt;code&gt;jdt-ls&lt;/code&gt;). Los errores no fueron sintácticos, sino de lógica e integración. Un desempeño elevado en pruebas de rendimiento abstractas no se correlacionó con la capacidad de resolver un problema de integración de sistemas bien definido.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Frente a la "Robustez"&lt;/em&gt; Lejos de adaptarse a la complejidad, los modelos produjeron código que era intrínsecamente frágil. Los más "exitosos" (Gemini, ChatGPT) generaron código que, al compilar y ejecutarse sin errores pero &lt;strong&gt;sin producir resultado alguno&lt;/strong&gt;, creaba una ilusión peligrosa de funcionamiento correcto, encapsulando el fallo en un silencio informativo.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  8.3. Conclusión del contraste
&lt;/h4&gt;

&lt;p&gt;La distancia entre las afirmaciones promocionales y los resultados de una prueba de implementación real no es una cuestión de grados, sino de naturaleza. Se promete una comprensión holística y autónoma, mientras que la evidencia actual muestra herramientas muy avanzadas de autocompletado sintáctico que todavía carecen de un modelo mental del estado, los protocolos o las consecuencias a largo plazo de sus propias generaciones.&lt;/p&gt;

&lt;p&gt;Este desfase no invalida en absoluto la utilidad real y demostrada de los LLMs en tareas acotadas (generación de código repetitivo, refactorizaciones simples, explicación de código, prototipado rápido). Sin embargo sí pone en perspectiva el relato de una revolución inminente en la ingeniería de software y nos invita a una conversación más adulta: reconocer con precisión dónde estamos hoy, valorar lo que ya funciona muy bien y seguir invirtiendo en el criterio humano que ninguna herramienta probabilística puede sustituir.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>java</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>No, la IA no programa. Y los que te dicen lo contrario te están vendiendo humo</title>
      <dc:creator>Joaquin Jose del Cerro Murciano</dc:creator>
      <pubDate>Thu, 15 Jan 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/jjdelcerro/no-la-ia-no-programa-y-los-que-te-dicen-lo-contrario-te-estan-vendiendo-humo-4506</link>
      <guid>https://forem.com/jjdelcerro/no-la-ia-no-programa-y-los-que-te-dicen-lo-contrario-te-estan-vendiendo-humo-4506</guid>
      <description>&lt;p&gt;Hace unas semanas, tras ver el enésimo video de un "experto" afirmando que "Gemini 3 Pro revoluciona la automatización" y que "los agentes de IA ya construyen aplicaciones completas", sentí una mezcla de incredulidad y rabia. Rabia por ver cómo la falta de experiencia en proyectos reales se disfraza de autoridad para envenenar el criterio de quienes están empezando.&lt;/p&gt;

&lt;p&gt;Así que decidí hacer lo que ninguno de ellos hace: &lt;strong&gt;una prueba real&lt;/strong&gt;. No con un repositorio de juguete de 10 archivos o con una API simple. Decidi probarlo con un problema de integración real. Conectar un servidor MCP a &lt;code&gt;jdt-ls&lt;/code&gt; usando LSP4J. Empece por una prueba de contexto minima, generar una clase java que no tendria mas de 500 líneas. Sin integrar en nada, una clase autocontenida. No llegue a pasar de esta prueba.&lt;/p&gt;

&lt;p&gt;El resultado: &lt;strong&gt;8 modelos de IA, 0 éxitos.&lt;/strong&gt; Ni uno solo generó código funcional, y varios de ellos entraron en bucle corrigiendo errores de compilacion y tuve que indicarles yo las correcciones para que se pudiesen compilar algunas cosas.&lt;/p&gt;

&lt;p&gt;Pero los videos siguen ahí. Los artículos prometiendo "revoluciones" se multiplican.&lt;/p&gt;

&lt;p&gt;Esto no es un artículo técnico. Es una &lt;strong&gt;denuncia&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  La falsedad de procesar repositorios completos
&lt;/h2&gt;

&lt;p&gt;En los videos dicen: "¡Procesa repositorios de un millón de tokens!". Suena impresionante hasta que abres un proyecto real.&lt;/p&gt;

&lt;p&gt;Te doy números de &lt;strong&gt;mi realidad&lt;/strong&gt;, no de sus demos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;gvSIG desktop (core)&lt;/strong&gt; 5.200 ficheros Java.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solo el módulo DAL&lt;/strong&gt; 1.056 ficheros, 567.416 palabras, 1.500.000 tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Un solo módulo de una aplicación profesional ya se come el 150% de la capacidad del contexto más avanzado del mercado. Cuando te prometen que la IA "entiende tu repositorio", te están mintiendo. Entiende un subconjunto ínfimo, una foto borrosa y recortada de la realidad de tu sistema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por qué generar texto que parece código no es programar
&lt;/h2&gt;

&lt;p&gt;He visto las demos. "Crea una app de TODOs en React". "Haz un dashboard con gráficos". Son el equivalente digital de &lt;em&gt;ensamblar un mueble de IKEA&lt;/em&gt;. Todas las piezas están ahí con un manual claro pero al final tienes algo que parece un mueble.&lt;/p&gt;

&lt;p&gt;La programación real no es ensamblaje de piezas prefabricadas. Es saber por qué elegimos una estructura sobre otra y asegurar que el sistema no colapse bajo su propio peso en unos años, a veces tan solo en unos meses una vez entra en producción.&lt;/p&gt;

&lt;p&gt;Cuando a un LLM le das un problema real (integrar un protocolo como LSP, manejar estado asíncrono y lidiar con configuraciones específicas de &lt;code&gt;jdt-ls&lt;/code&gt;) se desmoronan. No tienen un &lt;em&gt;modelo mental&lt;/em&gt; del sistema. Solo tienen estadísticas de tokens.&lt;/p&gt;

&lt;p&gt;Mi prueba. Los 8 modelos (Claude 4.5, Gemini 3 Flash, ChatGPT, GLM 4.7, Kimi K2, Qwen3-Coder, DeepSeek 3.2 y Grok 4.1) &lt;br&gt;
llegaron a generar código que compilaba tras varios turnos de corrección. Algunos necesitaron hasta siete turnos solo para llegar a código que compilase. Otros se metieron en bucles de modificacion y correccion de los que tube que ayudarles a salir. Al final todos consiguieron un codigo que compilaba.&lt;br&gt;
Pero no funcionaba. Se olvidaron de inicializar el servidor en el orden correcto, o no manejaron las notificaciones, o malinterpretaron la respuesta.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Eso no es "programar". Es "generar texto que se parece a código Java".&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  El fraude del "atajo" cognitivo
&lt;/h2&gt;

&lt;p&gt;El daño más grave no es la sobreventa técnica, sino el sabotaje intelectual que están sufriendo los programadores que hoy intentan entrar en la industria. Me hierve la sangre cuando escucho a esos "evangelistas" decir: "No pierdas el tiempo aprendiendo el lenguaje, aprende a pedírselo a la máquina de la forma correcta", tenemos LLMs con "capacidad de razonamiento doctoral", "Vibe Coding que entiende tu intención"...&lt;/p&gt;

&lt;p&gt;Un junior ve esto y se pregunta para qué va a aprender algoritmos o arquitectura si la máquina "ya lo hace". Es una estafa. Se les está ocultando que, sin criterio, están delegando tareas críticas en una caja probabilística sobre repositorios que ni siquiera caben en su memoria. &lt;/p&gt;

&lt;p&gt;Estan promoviendo que los desarrolladores juniors se crean que todo es facil. Que pueden delegar en la IA tareas complejas. Sobre repositorios reales. Estan engañandonos en nuestra propia cara y no todos tenemos el criterio para darnos cuenta de como nos mienten.&lt;/p&gt;

&lt;p&gt;Puedes usar la IA en programacion pero no te va a ensañar...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A tener &lt;em&gt;olfato&lt;/em&gt; para detectar el código que &lt;em&gt;huele mal&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;anticipar&lt;/em&gt; consecuencias a meses o años vista.&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;discutir&lt;/em&gt; que sacrificas con tu equipo.&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;mantener&lt;/em&gt; compatibilidad con otros sistemas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Te mienten. Y lo hacen con una sonrisa y unos bonitos gráficos.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  El perfil de los que venden el humo
&lt;/h2&gt;

&lt;p&gt;¿Quiénes están produciendo este ruido? Por un lado, los &lt;em&gt;inconscientes&lt;/em&gt;, juniors que creen haber descubierto la magia porque aún no saben lo que no saben. Por otro, los &lt;em&gt;oportunistas&lt;/em&gt; que optimizan para el click y el "enganche" porque la verdad no vende tanto. Y finalmente, los &lt;em&gt;teóricos sin callos&lt;/em&gt;, gente que salta de demo en demo pero que nunca ha tenido que mantener un sistema real con usuarios y código heredado de hace 15 años.&lt;/p&gt;

&lt;h2&gt;
  
  
  Un llamado a la honestidad técnica necesaria
&lt;/h2&gt;

&lt;p&gt;A los creadores de contenido: dejen de vender humo. Si quieren enseñar IA, enseñen &lt;em&gt;sus límites&lt;/em&gt;. Enséñen a la gente que esto funciona para tareas mecánicas o código repetitivo, que ayuda a refactorizar, pero que nunca sustituye tu comprensión del problema.&lt;/p&gt;

&lt;p&gt;A los juniors: &lt;em&gt;aprendan fundamentos&lt;/em&gt;. La IA es una herramienta poderosa en manos de un artesano experto. En manos de un novato, es un martillo neumático que puede destrozar todo lo que toca.&lt;/p&gt;

&lt;p&gt;A mí: seguiré escribiendo artículos como este. Mostrando, con código (cuando pueda) y errores reales, la brecha entre el hype y la realidad.&lt;/p&gt;

&lt;p&gt;Y la próxima vez que un "gurú" diga que la IA programa, le enviaré mis pruebas con los 8 intentos fallidos. A ver si tiene el valor de intentar arreglarlo.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;La IA no programa. Los programadores programan. Los demás hacen demos.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Este artículo estaba listo para publicar hace unos días. Pero una duda me perseguía. ¿y si el problema no era Java, sino la complejidad misma? Días después, ya con el texto frío, recordé algo que nos paso a finales de noviembre...&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Postdata: aún había algo dando vueltas en mi cabeza
&lt;/h3&gt;

&lt;p&gt;A finales de noviembre, un compañero y yo tuvimos que meter mano en la aplicación web de la empresa. Cuenta con un frontend de más de 50000 líneas de JavaScript y TypeScript. Nosotros somos arquitectos Java; de React solo sabíamos el nombre.&lt;/p&gt;

&lt;p&gt;La promesa de la IA aquí debería cumplirse. Un stack moderno, una sintaxis popular, programadores "novatos". Localizamos donde habia que tocar, un par de modulos js, y le pedimos a "Gemini CLI" que nos explicara qué cambiar ahi y luego que generara el código. Su explicación fue coherente. El código sintácticamente perfecto.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Falló en silencio.&lt;/strong&gt;&lt;br&gt;
Habia que mostrar una lista con checks... a veces la lista no aparecía. A veces los check no respondían. A veces el estado se reseteaba solo. El error era un &lt;em&gt;cierre obsoleto&lt;/em&gt; (&lt;em&gt;stale closure&lt;/em&gt;). Gemini había olvidado declarar una dependencia en un &lt;code&gt;useCallback&lt;/code&gt;. Escribió una función que no veía los cambios en el estado.&lt;/p&gt;

&lt;p&gt;No supimos arreglarlo. Así que le pedimos a la IA que nos resumiera la filosofía de react, los hooks y las closures. Lo leímos, lo entendimos y le señalamos el fallo. La IA lo corrigió. Había cometido un error de junior y tuvimos que corregirle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La realidad:&lt;/strong&gt;&lt;br&gt;
No es que no sepan Java. Es que, cuando la complejidad es real, estado asíncrono, ciclos de vida complejos o integración con sistemas "vivos", sin importar el lenguaje, falla. La IA no tiene modelo mental. Solo tiene probabilidad. Y eso, en un proyecto de verdad, se paga con horas de debug.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
