Saltar al contenido
Bitácora / procesos y agentes

Errores trabajando con agentes: procesos, reglas y pruebas

Estoy revisando errores que se repiten en proyectos largos con varios agentes, contextos grandes y documentación que cambia durante el trabajo. Lo que más me está haciendo mirar el proceso son las reglas poco claras y la falta de criterio para decidir qué comprobar. Esta entrada conserva un caso concreto: 29 errores registrados al trabajar con NEAT en Isaac Lab y el paso hacia Unity.

Descargar la versión técnica (.md)

La pregunta que estoy revisando ahora

Mi investigación ya abarca más proyectos que ese entrenamiento. Estoy probando formas de coordinar agentes, mantener documentación viva y decidir cuándo una respuesta necesita rigidez y cuándo conviene dejar espacio para explorar.

Se están haciendo tests para evitar errores, pero sigo viendo una parte pendiente: el criterio para elegirlos, también al trabajar con modelos de frontera. Una prueba puede pasar y aun así no responder a la pregunta que necesitábamos resolver.

Cómo leer el caso documentado

Los 29 casos de abajo pertenecen al registro de NEAT, con su versión técnica al 17/09/2026. Los mantengo como evidencia de ese proyecto; no son una lista de incidentes de todos los proyectos que estoy revisando ahora ni resultados de las pruebas con PPO.

Cada entrada cuenta qué pasó, qué costó y la regla que quedó. Algunas son muy propias del motor de física; otras permiten discutir problemas de coordinación y proceso que pueden aparecer al trabajar sobre un mismo proyecto.

Cinco palabras que se repiten
Corrida
Una ejecución completa de entrenamiento o de evaluación.
Registro (raw)
Lo que el motor escribe mientras corre. Es la única fuente que cuenta como prueba.
Compuerta
Una comprobación automática que decide si una corrida pasa o no.
Control negativo
Una prueba hecha para fallar a propósito. Si no falla, la compuerta no sirve.
ULP
El paso más pequeño que puede dar un número decimal en la computadora. Se usa para comparar resultados sin engañarse.

Errores de rótulo Familia A · decir que algo es lo que no es

Los más tontos y los que más se repitieron. Un nombre mal puesto hace que otros trabajen sobre algo que no existe.

A1Llamar «entorno» a algo que no lo era

Qué pasó. Se llamó «entorno» a un lector de contrato, y después a un lazo sin recompensa. Ninguno ejecutaba reset ni step.

Qué costó. Dos ciclos de trabajo sobre algo que no simulaba nada.

Regla. Una pieza se llama por lo que el registro del motor demuestra que ejecutó. «Listo para X» exige el registro de X.

A2Un valor escrito a mano que pasó por medición

Qué pasó. Un valor fijo (physicalResetNoExtraSimStep: True) viajó en el registro como si fuera un dato medido, durante muchos ciclos. Al medirlo había 3 ticks, y en otra función.

Qué costó. Tres afirmaciones sin medir y una discusión sobre un dato que no existía.

Regla. Nada que afirme un hecho físico entra al registro sin un contador o una lectura real detrás. Los valores fijos se marcan como tales.

A3Un video con cuatro objetivos que era el mismo cuatro veces

Qué pasó. El video de Isaac decía «objetivo 39 / 59 / 115 / 155 (validación)» y en realidad corrió un solo objetivo de entrenamiento cuatro veces.

Qué costó. Un video que no se podía comparar, entregado, y una recaptura.

Regla. El rótulo se lee del motor, no del argumento con que se lanzó. Detector: cuatro mínimos idénticos hasta 18 decimales. Una coincidencia imposible dice tanto como una discrepancia.

A4Un descriptor que decía «resuelto» y era una copia

Qué pasó. El descriptor de salida decía «miembros RUN resueltos» y era copia byte a byte del de entrada, con cinco PENDING.

Qué costó. Un archivo de identidad que no identificaba nada.

Regla. La identidad de una corrida es su registro. Ningún consumidor lee el descriptor de salida hasta que se haya escrito.

A5Datos de procedencia heredados de otra corrida

Qué pasó. Campos como «corrida corta, 50 updates» viajaron a la referencia de la corrida larga y al auditor de Unity.

Qué costó. Rótulos falsos circulando entre equipos.

Regla. Los consumidores deciden por el SHA del archivo en disco, nunca por un rótulo dentro del JSON. Cada corrida regenera su procedencia.

Errores de medición Familia B · números que no medían lo que decían

Aquí el dato existía, pero no significaba lo que se afirmó. Son los más fáciles de publicar por error.

B1Umbrales absolutos para comparar poses

Qué pasó. Un umbral fijo de 1e-6 m rechazaba poses exactas a 33 m y aceptaba corrupción a 1.5 m.

Qué costó. Tres rondas de compuertas inútiles.

Regla. Presupuestos según la representación del número (ULP) y compuertas que predicen el valor exacto.

B2«Como máximo 1 ULP» como compuerta

Qué pasó. Una corrida legítima dio 4 ULP y fue rechazada.

Qué costó. Falsos negativos.

Regla. Se predice el valor por el mecanismo (el recorrido pasa por el centro de masa), no con una tolerancia genérica.

B3Un retorno inicial que no era inicial

Qué pasó. Se tomó 250.84 como retorno inicial (R₀); era el retorno tras 10 updates. El campo de al lado, updateIndex, no se miró. Llegó a un descriptor sellado y desplegado.

Qué costó. Un umbral mal derivado y una versión extra del paquete.

Regla. R₀ se mide en el update 0 de la propia corrida, antes del primer aprendizaje. Una cita verifica que el valor está, no que signifique lo que se dijo.

B4«Ganancia ×4 por paso» que era una secante

Qué pasó. Se publicó «ganancia 3.96, ×4 por paso». Era una secante entre amplitudes; la incremental decae a 0.23.

Qué costó. Una justificación falsa, publicada y difundida.

Regla. Una magnitud de amplitud no es sensibilidad. La sensibilidad se mide con un Δ pequeño sobre datos reales (salió p50 4.27).

B5Prueba de lotes con datos que no eran los de la corrida

Qué pasó. Observación sintética y pesos distintos de los de la corrida. La monotonía «4 → 8 → 12 ULP» era un artefacto.

Qué costó. Una conclusión falsa: «1024 es el peor caso». El peor caso era lote 100.

Regla. Las pruebas de la red usan observaciones reales y los pesos exactos de la corrida, identificados por SHA.

B6Ratios gigantes con denominador cercano a cero

Qué pasó. Ratios de sensibilidad por componente de hasta 3.7e4 porque el denominador era el ULP de un valor casi cero.

Qué costó. Casi se publicó.

Regla. Solo se citan cocientes con denominador homogéneo. Los ratios por componente sirven para ordenar, no para acotar.

B7Parar mirando la métrica equivocada

Qué pasó. El criterio de parada miró el retorno, ya saturado contra su techo, mientras la métrica de tarea seguía mejorando a buen ritmo.

Qué costó. La corrida paró en el primer punto posible con pendiente.

Regla. El criterio mira la métrica de tarea sostenida, no solo el retorno. Se instrumentó C2 (mejor error por episodio) antes de la corrida; sin ella se habría leído «no aprendió».

Errores de instrumento Familia C · compuertas que no podían fallar

Una compuerta que siempre pasa no es una compuerta. Todos estos parecían funcionar.

C1Un comparador que decía «idénticos» cuando no había nada

Qué pasó. Cuando las sondas fallaban, comparaba None con None y escribía «IDÉNTICOS».

Qué costó. Un falso positivo en la compuerta que habilitaba el lanzamiento.

Regla. Toda compuerta se prueba primero contra una entrada que debe hacerla fallar.

C2Un control negativo con valores viejos

Qué pasó. El generador tenía fijos la fila y el límite anteriores. El negativo «pasó» y no acreditaba nada.

Qué costó. Un control que no controlaba.

Regla. El elemento y el límite del negativo se derivan del registro que se audita.

C3Cuatro copias contadas como cuatro observaciones

Qué pasó. Cuatro entornos con el mismo input se trataron como cuatro observaciones distintas.

Qué costó. Un determinismo que no acreditaba nada.

Regla. El control debe variar la variable: seguir al valor, seguir al eje.

C4El vigilante se mató a sí mismo

Qué pasó. Mataba «todo python salvo ComfyUI», y se incluyó en la lista.

Qué costó. No escribió la medición posterior al cierre.

Regla. Una lista por negación protege lo que nombra y nada más. Hay que excluir el propio proceso y su árbol.

C5Un validador que dio «0 errores» sobre un archivo roto

Qué pasó. El YAML tenía claves repetidas (YAML se queda con la última sin avisar) y se perdió un campo en silencio.

Qué costó. Un valor superado apareciendo junto a una razón que hablaba de otro.

Regla. Un validador acredita lo que comprueba, no el archivo entero. Se buscan claves duplicadas y se lee el registro, no lo que uno cree haber escrito.

C6La observación inicial era de otro estado

Qué pasó. En cada evaluación, la observación del paso 0 era la guardada del último paso de entrenamiento, no la del objetivo asignado.

Qué costó. Una acción de 240 por episodio calculada sobre otro estado, en las 11 evaluaciones.

Regla. Tras asignar objetivos se reconstruye la observación desde el estado. Detector: dos corridas «idénticas» que no coincidieron bit a bit.

Errores de física y API Familia D · costaron construcciones

Los más específicos del motor. Si no trabajas con Isaac Lab o Unity, quédate con D4: es universal.

D1Reescribir el estado con sus propios valores

Qué pasó. Reescribir posiciones y velocidades con los mismos valores dejaba los bits iguales, pero cambiaba la evolución.

Qué costó. El bit a bit del reset se rompió dos veces.

Regla. El reset escribe solo las filas de los entornos terminados, por índice, en los cinco tensores.

D2Un cierre que no retorna

Qué pasó. app.close de Kit no vuelve: el proceso queda vivo con la GPU tomada.

Qué costó. Corridas que «no terminaban» y mediciones posteriores imposibles.

Regla. El registro se sella antes de cerrar; un vigilante externo mata el proceso huérfano después y escribe el archivo lateral.

D3Dos librerías que no conviven en el mismo proceso

Qué pasó. Importar onnxruntime dentro de Kit produce una violación de acceso.

Qué costó. Dos construcciones perdidas.

Regla. La traza va en dos etapas: torch dentro de Kit, onnxruntime en un proceso aparte, y se comparan por fila.

D4Correr a 1024 sin probar a 4

Qué pasó. Dos construcciones de 1024 entornos perdidas por un IndexError que con 4 entornos habría aparecido en segundos.

Qué costó. Dos horas de GPU.

Regla. Nada corre a 1024 sin pasar de punta a punta con N=4, con el mismo script.

D5Configurar antes de activar (Unity)

Qué pasó. Las escrituras a la raíz hechas antes de activar el cuerpo se perdían: iteraciones, profundidad de penetración, inmóvil.

Qué costó. Configuración que no se aplicaba.

Regla. Todo ajuste de raíz se aplica y se verifica después de la activación.

Errores de proceso Familia E · los más caros, por repetidos

Ninguno tiene que ver con física. Son de cómo se coordina el trabajo, y fueron los que más horas se llevaron.

E1Terminar el turno con trabajo pendiente

Qué pasó. El ejecutor cerraba su turno «ocioso» con trabajo pendiente («Sigo…» y nada más). Ocho veces.

Qué costó. Ciclos de 20 minutos perdidos. La corrida larga corrió dos horas sin ningún reporte, y el retorno inicial lo tuvo que leer otro del disco.

Regla. Un turno no termina con trabajo pendiente, salvo bloqueo contractual o corrida en vuelo con vigía. Encargos de un solo entregable.

E2Mensajes pequeños que se reordenaban

Qué pasó. Mensajes en cola llegaban desordenados y duplicados; uno decía algo y el siguiente lo corregía.

Qué costó. Confusión en tres chats.

Regla. Un mensaje consolidado por chat y por ciclo, con visto bueno humano. Tope de 40 líneas. Sin acuses de recibo.

E3Hashes sin decir de qué eran

Qué pasó. Hashes de git publicados junto a SHA-256 crudos, sin rótulo.

Qué costó. Casi se leyó como una diferencia real entre la máquina local y la remota.

Regla. Cada SHA se publica con la pregunta contra la que se comparó.

E4Dos copias y un solo nombre

Qué pasó. Dos copias del paquete en la máquina remota; una quedó vencida y se seguía llamando «el desplegado».

Qué costó. Riesgo de lanzar contra la copia equivocada.

Regla. Las órdenes citan rutas completas. Un nombre en singular que apunta a varios objetos es una trampa.

E5Contratos antes de correr lo simple

Qué pasó. El contrato P2 tuvo cuatro versiones antes de ejecutar nada. Se consultó al Crítico por cuestiones de redacción.

Qué costó. Horas de proceso sin una sola medición nueva.

Regla. Correr primero lo que ya tiene insumos. El Crítico entra solo en compuertas de fase. Se registran decisiones y defectos, no lecciones.

E6Defectos acumulados como «pendientes»

Qué pasó. Los defectos conocidos se dejaban en lista en vez de corregirse juntos.

Qué costó. Cada medición nueva tropezaba con un defecto viejo.

Regla. Una versión del paquete con todos los defectos conocidos corregidos en un solo cambio, antes de la siguiente fase.

Lo que funcionó en ese proyecto y hay que conservar

  • Medir antes de diseñar: la medición invalidó dos contratos antes de que costaran GPU.
  • Predicción sellada antes de correr, con fecha verificable, en vez de explicar después.
  • Controles negativos reales y verificación cruzada entre dos máquinas y dos operadores.
  • Un Crítico adversarial con la tabla completa: retiró argumentos del Arquitecto, del coordinador y del ejecutor.
  • Sellar lo que se consumió y verificar que consumido = sellado antes de cada veredicto.
  • Un fallo bien reportado valió más que un pase forzado, todas las veces.

El criterio que quiero pedirle a una prueba

Esta es la revisión que quiero hacer al decidir qué tests necesita un cambio:

  • ¿Qué comportamiento o fallo concreto está intentando comprobar?
  • ¿Podría fallar si ese comportamiento estuviera roto, o solo está repitiendo lo que dice la implementación?
  • ¿Usa datos y condiciones que representen el caso que importa?
  • ¿Qué demuestra al pasar y qué queda fuera de su alcance?
  • ¿Su costo y su mantenimiento tienen sentido para el riesgo de ese cambio?

No quiero medir la calidad por la cantidad de tests. Quiero comprobar si ayudan a detectar problemas reales y si sus resultados permiten tomar la siguiente decisión.

Documentación viva y reglas claras

También estoy revisando cómo mantener las decisiones vigentes al trabajar con varios agentes. Una documentación que nadie actualiza puede seguir circulando como si fuera válida. Y una instrucción rígida aplicada fuera de su contexto puede consumir trabajo sin resolver el problema.

La prueba con mensajes entre agentes forma parte de esa investigación. Quiero separar lo que necesita una regla precisa —permisos, responsabilidades, condiciones de entrega— de lo que necesita margen para explorar. Todavía estoy comprobando dónde poner esa separación.

Lo que sigo revisando

En el caso de NEAT, los errores más caros fueron de rótulo y de proceso. En los proyectos que estoy revisando ahora, el foco sigue en aclarar reglas, mantener el contexto al día y elegir pruebas con criterio. Registrar resultados ayuda, pero también hay que saber qué permiten afirmar y qué sigue pendiente.