En pocas palabras: El desarrollador Debashish Ghosal encontró 31 bugs en una sola sesión de agent-self-edit (1 de septiembre de 2026), 9 de ellos fundamentales. Ninguno crasheaba: todos producían output que parecía válido pero estaba podrido por dentro, simulando un sistema que funcionaba.
Un desarrollador llamado Debashish Ghosal armó un sidecar de IA que reescribe su propio system prompt según el feedback de ejecución, lo probó, y parecía andar de diez. No andaba. En una sola sesión encontró 31 problemas, 9 de ellos fundamentales, y cada uno hacía que el sistema pareciera funcionar cuando en realidad no. Si te dedicás al debugging de prompts de OpenAI o a testear sistemas con LLM, este caso publicado el 1 de septiembre de 2026 es oro puro.
agent-self-edit es una herramienta open-source (repo en github.com/deghosal-2026/agent-self-edit) que reescribe su propio system prompt a partir del feedback de ejecución. Corre A/B tests entre el prompt candidato y el actual, y solo promueve los ganadores estadísticamente probados. El debugging de prompts de OpenAI en este contexto no es cazar crashes: es cazar output que parece correcto pero está podrido por dentro.
En 30 segundos
- 31 bugs en una sesión, 9 fundamentales: ninguno crasheaba, todos producían output que parecía válido.
- El peor: el gate de promoción chequeaba p < 0.95 en vez de p < 0.05. Dejaba pasar ruido como “mejora”.
- El A/B test comparaba un prompt contra sí mismo: daba p=1.0 con n=5 (empate perfecto), la señal más sospechosa que existe.
- El scoring marcaba el 100% como “passed” porque aceptaba cualquier respuesta no vacía.
- Cómo los cazó a todos: leyendo el tráfico crudo del LLM (4.150 entradas en un JSONL), no los resúmenes.
¿Por qué los bugs silenciosos son más peligrosos que los crashes en sistemas con LLM?
Un bug silencioso es un error que no rompe el sistema: produce output que parece correcto mientras el sistema optimiza contra una realidad que no existe. En agent-self-edit, la precisión saltó de 20% a 40% y el autor festejó, hasta que miró el código y descubrió que la “mejora” era ruido estadístico. Un crash te avisa. Un bug silencioso te felicita.
La analogía que usa Ghosal es buenísima. Imaginá un médico que diagnostica pacientes, pero cada ficha dice “síntoma: dolor de cabeza” sin importar qué tiene el paciente. El médico va a recetar remedios para el dolor de cabeza. Ninguno va a funcionar, porque los pacientes no tienen dolor de cabeza. Eso pasaba con el analizador: aprendía de una realidad fabricada.
El sistema siempre produce algo. La pregunta es si ese algo es real.
¿Cómo un p-value invertido dejó pasar ruido como mejora?
El bug más insidioso fue un gate de promoción que chequeaba p < 0.95 cuando debía chequear p < 0.05. Con esa condición invertida, casi cualquier cosa pasaba: un p-value de 0.9 pasaba, uno de 0.5 pasaba. La “promoción” que festejó el autor con p=0.1 tenía un 10% de probabilidad de ser puro azar. Dos líneas de código separaban un sistema que aprende de uno que deriva sin rumbo. Cubrimos ese tema en detalle en cómo funciona Sora en profundidad.
El error conceptual es clásico. El test de hipótesis estándar pide p < alpha, donde alpha = 1 - confidence_level. Con un confidence_level de 0.95, el alpha es 0.05. Pero el código confundió el nivel de confianza con el umbral del p-value y comparó contra 0.95. Después del fix, esa misma edición dio p=0.23 y el gate la rechazó, correctamente: había un 23% de chance de que la “mejora” fuera casualidad, muy por encima del 5% que exige el umbral.
La lección es fea de tan simple: revisá tus estadísticas. El confidence_level no es el umbral del p-value. El alpha sí. Leé el código, no el nombre de la variable.
¿Por qué un A/B test perfecto es una red flag en prompts?
Un A/B test que da empate perfecto (p=1.0, cero diferencia en las 5 tareas) casi nunca significa que los prompts sean igual de buenos: significa que estás comparando dos cosas idénticas. En la práctica, hasta un prompt malo produce alguna variación. Un empate perfecto es una bandera roja, no un resultado tranquilizador.
¿Qué encontró cuando revisó los logs de tráfico? Exacto: las 10 llamadas del A/B test (5 tareas por 2 prompts) usaban el mismo texto de prompt. El sistema se comparaba contra sí mismo. La causa raíz era que se pasaba el fragmento editado (algo como “Sos un clasificador de tickets de soporte técnico”), no el system prompt completo. El motor esperaba un prompt válido entero, el fragmento no lo era, y hacía fallback al prompt actual para ambos brazos. El fix fue una línea: construir el candidato completo aplicando la edición al prompt actual, y recién ahí testear. Sobre eso hablamos en el chip Jalapeño de OpenAI explicado.
El primo hermano de este bug estaba en el scoring. Había un modo que chequeaba una sola cosa: bool(llm_output.strip()). Si el LLM devolvía cualquier respuesta no vacía, la traza se marcaba “passed”. Como el LLM siempre escribe algo, el pass rate era 100%, incluso en las trazas de fallo. Un 100% de aprobación es imposible salvo que el scoring esté roto. Lo estaba. El autor borró el script entero.
¿Cuáles son los 6 bugs restantes que causaron el colapso silencioso?
Los seis que quedan siguen el mismo patrón: verde en el tablero, podrido abajo. Acá van con su corrección.
- Los tests de Docker saltaban lo importante: corrían con
--once --dry-run, así que esquivaban el A/B test y el gate, los dos componentes centrales. Era un smoke test disfrazado de test de integración. Tras el fix, el test pasó de 5 a 62 segundos, porque recién ahí hacía llamadas reales al LLM. - Las trazas de fallo estaban fabricadas: todas decían que el modelo devolvía “other”, pero el modelo nunca devuelve “other” (devuelve “billing”, “security”, “technical”). El analizador optimizaba contra un problema que no existía.
- El gate recibía el prompt equivocado: le pasaban la versión editada en vez de la original al chequeo de
frozen_sections. Este bug se escondía detrás del de confianza; apareció recién cuando arreglaron el primero. - El CLI hablaba con un mock: un resto de debugging hardcodeaba un cliente falso que devolvía strings vacíos. El loop terminaba en menos de un segundo. Una llamada real a un LLM tarda minutos.
- La config ignoraba el endpoint en silencio: el
base_urlapuntaba a un servidor OMLX local (http://localhost:8000/v1), pero el dataclass no tenía ese campo, así que el valor se descartaba sin error. Todas las llamadas iban al endpoint default de OpenAI. - El runner del field test medía otra cosa: mandaba cada tarea como chat completion suelto, sin importar un solo módulo del paquete que decía testear. Medía el comportamiento base del modelo, no la capacidad del loop de mejorar.
Fijate el hilo conductor. Subís el candidato, corre el A/B test, el gate lo evalúa, los tests de Docker pasan, el field test tira números lindos, y todo el tiempo el sistema estuvo comparando un prompt contra sí mismo, midiendo trazas inventadas y hablando con un mock que devolvía vacío.
¿Cómo leer logs crudos del LLM para cazar lo que los resúmenes esconden?
Todos los bugs se cazaron igual: leyendo el tráfico crudo del LLM, no el resumen. El autor prendió una variable de entorno, AGENT_SELF_EDIT_LLM_LOG, que escribe cada par request/response a un archivo JSONL. Juntó 4.150 entradas en 15 iteraciones, y cada bug salió de leer ese archivo. El resumen decía “pass”. El tráfico decía “te estás comparando con vos mismo”. Tema relacionado: modelos open source más económicos.
La primera señal de alarma siempre fue la misma: velocidad sospechosa más resultado perfecto. Un A/B test de 54 segundos que da empate perfecto. Un 100% de aprobación sobre trazas reales. Un loop que termina en menos de un segundo. Cuando el resultado se ve demasiado limpio, casi siempre lo es. Las llamadas reales tienen latencia, los A/B tests reales tienen varianza, el scoring real produce fallos.
Si tenés que quedarte con una sola cosa: logueá el tráfico crudo del LLM, siempre. El resumen miente. Los pares request/response no.
Qué significa esto para equipos que corren LLM en producción
Si tenés un pipeline de agentes o un sistema de optimización de prompts corriendo en un VPS o en un servidor propio, el caso te da un checklist accionable. La observabilidad no es un lujo de fin de sprint: es la única forma de distinguir un sistema que aprende de uno que deriva. Cuando montés la infraestructura para esto (por ejemplo en un servidor de donweb.com con acceso a los logs de tu app), asegurate de que el logging del tráfico esté prendido antes de confiar en cualquier métrica de resumen.
- Fallos de config silenciosos: si un campo de config no matchea con tu dataclass, validalo o logueá un warning. No lo descartes sin avisar.
- Datos reales, no fabricados: corré el prompt actual contra el set de tareas, capturá los outputs reales del modelo y sembrá solo los fallos verdaderos.
- Sacá los mocks antes de shippear: si tu loop de LLM termina al instante, no estás llamando a un LLM.
Qué está confirmado y qué no
- Confirmado: los 9 bugs fundamentales, sus causas y sus fixes están documentados por el propio autor en el post de dev.to del 1 de septiembre de 2026, con el código público en GitHub.
- Confirmado: el método de detección (leer el JSONL de tráfico crudo vía
AGENT_SELF_EDIT_LLM_LOG) y las cifras (4.150 entradas, 15 iteraciones, empate en p=1.0 con n=5). - No confirmado de forma independiente: es un relato en primera persona de un solo desarrollador sobre un proyecto personal. Nadie externo replicó los resultados. Tomalo como un caso de estudio valioso, no como un benchmark auditado.
Errores comunes al debuggear prompts que aparentan funcionar
- Confiar en el pass rate del summary: un 100% de aprobación no es un éxito, es una alarma. Si tu scoring nunca falla, no está testeando nada. Andá a las trazas.
- Confundir un empate con equivalencia: cuando un A/B test da tie perfecto, revisá el tráfico. O la edición no cambia el comportamiento, o no estás testeando dos prompts distintos.
- Llamarle “test de integración” a un smoke test: si tu test saltea la parte difícil con un
--dry-run, es un smoke test. Etiquetalo como tal y no lo cuentes como cobertura del A/B test y el gate. - Arreglar un bug y cantar victoria: arreglar el de arriba del stack de fail-fast destapa el siguiente. En este caso, el bug del gate con el prompt equivocado recién apareció cuando se corrigió el del p-value invertido. Seguí buscando.
Preguntas Frecuentes
¿Cómo debuggear prompts de OpenAI que parecen funcionar?
Logueá el tráfico crudo request/response de cada llamada al LLM en un archivo JSONL y leelo, en vez de confiar en el output de resumen. En agent-self-edit, los 9 bugs fundamentales se cazaron así: el summary decía “pass” y el tráfico revelaba que el sistema se comparaba contra sí mismo o hablaba con un mock vacío.
¿Qué son los bugs silenciosos en sistemas con IA?
Son errores que no crashean el sistema: producen output que parece correcto mientras el sistema optimiza contra datos o métricas falsas. Son más peligrosos que un crash porque no te avisan; al contrario, te devuelven números que parecen buenos, como el salto de precisión de 20% a 40% que resultó ser ruido estadístico. En diferencias clave entre OpenAI y Claude profundizamos sobre esto.
¿Por qué un A/B test perfecto es una red flag?
Porque en la práctica hasta un prompt malo produce alguna variación, así que un empate perfecto (p=1.0, cero diferencia en todas las tareas) suele indicar que estás comparando dos cosas idénticas. En el caso real, las 10 llamadas del A/B test usaban el mismo texto de prompt por un fallback silencioso.
¿Cuál es la diferencia entre una alucinación y un bug en un LLM?
Una alucinación es el modelo inventando contenido plausible pero falso en su respuesta. Un bug es un error en el código que rodea al modelo: un p-value invertido, un mock hardcodeado, un campo de config que se descarta sin error. En agent-self-edit, ninguno de los 9 problemas fundamentales era alucinación; todos eran bugs de ingeniería.
¿Cómo detectar si un prompt tiene errores antes de producción?
Sembrá tus tests con fallos reales, no fabricados: corré el prompt actual contra el set de tareas y capturá los outputs verdaderos del modelo. Después, verificá que tu A/B test compare dos prompts distintos y que el scoring pueda producir fallos. Si el pass rate es 100% o el loop termina en menos de un segundo, algo está roto.
Conclusión
El caso de agent-self-edit cambia el foco del debugging de prompts de OpenAI: el enemigo no es el crash, es el output que parece correcto. Nueve bugs, todos con el tablero en verde, y el sistema derivando sin aprender nada. La defensa concreta es una sola línea de disciplina: prendé el logging del tráfico crudo del LLM antes de confiar en cualquier resumen, y sospechá siempre de lo que se ve demasiado limpio. Si tenés un pipeline de agentes corriendo hoy, andá a buscar tu --dry-run escondido, tu mock olvidado y tu p-value al revés. Están ahí.