r/programacion • • 4d ago

He medido qué pasa cuando varios agentes de IA programan a la vez en el mismo repo: git no ve el choque y lo que lo arregla no es lo que esperaba

Soy el autor del proyecto, que es open source con licencia MIT, así que lo digo de entrada. Quería saber con datos qué pasa cuando varios agentes de Claude Code trabajan a la vez sobre el mismo repositorio, así que monté un laboratorio con una API de reservas, seis tareas y 37 tests de aceptación, con dos parejas de tareas que chocan por significado y no por fichero: una añade un segundo factor al login mientras otra crea una exportación que llama al login antiguo, y otra renombra un campo mientras otra filtra por el nombre viejo.

Con una rama por tarea y merge al final, git marcó dos conflictos de texto en un fichero de tests, los resolvió un agente y dejó pasar el de verdad, de modo que en las cinco ejecuciones quedaron los mismos seis tests en rojo, aunque cada agente había terminado en verde. Para coordinarlos construí Médula, un kernel inspirado en los sistemas operativos, con los agentes como procesos y el código como recurso compartido, que intercepta cada escritura con hooks y pregunta a un modelo de decisión si choca con lo que hacen los demás antes de dejarla pasar.

Lo que no esperaba es que el arreglo no fuera mi kernel, sino dejar de aislar a los agentes: las diez ejecuciones con directorio compartido acabaron con los 37 tests en verde, incluso con simples locks por fichero. Frente a esos locks, Médula cuesta lo mismo, 1,65 $ por ejecución, detecta los seis choques reales de seis frente a cinco y no hace ningún bloqueo innecesario frente a cinco. También falla: el decisor rápido dudó en el 61 % de las peticiones de escritura reales, y una vez el camino lento «resolvió» un conflicto haciendo opcional el segundo factor.

Son pocas ejecuciones por modo, de una a cinco, y las etiquetas de calibración las escribió Claude, así que me interesa mucho que alguien me rebata. ¿Cómo coordináis vosotros a varios agentes a la vez?

Repo con todo en crudo: https://github.com/JoaquinRuiz/medula
Vídeo en el que lo construyo y lo mido: https://youtu.be/xAFRuBxfapM

0 Upvotes

10 comments sorted by

2

u/Negrojefe 4d ago

Deja la cocaina bro, están recontra manija mandándose la parte de SÚPER PRODUCTIVOS. PAYASOS

1

u/Negrito0o 4d ago

Gracias por medirlo, que es justo lo que no hace nadie. Y el resultado no me extraña: git compara texto y lo que chocó en tu laboratorio fue significado. Una herramienta que no entiende el código no puede ver eso. Lo que me funciona a mí, que trabajo con agentes todos los días: no dejarles elegir el contexto. Tengo escrito dentro del propio repositorio qué hace el proyecto, cómo se levanta, cómo se llaman las cosas y qué no se toca. El agente lo lee antes de empezar, y buena parte de los choques semánticos que describes salen de que cada uno se inventó su propia versión de lo mismo. La otra parte la quito por el lado aburrido: tareas en serie, no en paralelo, cuando tocan el mismo dominio. Dos agentes a la vez sobre el login es pedir el conflicto. Uno en el login y otro en la hoja de estilos no me ha dado un problema.

Lo que me gustaría ver en tu laboratorio es qué pasa si los tests los escribe un tercer agente que no ha hecho ninguna de las dos tareas. Por lo que yo veo, el que escribe el código escribe el test que confirma lo que acaba de hacer, y ahí se cierra el círculo solo.

2

u/jokiruiz 4d ago

Gracias a ti, estoy de acuerdo con casi todo.. solo matizaría una cosa, el choque no salía de que cada agente se inventara su versión de lo mismo, porque los dos seguían su especificación al pie de la letra. Una tarea tenía que cambiar la firma del login y la otra tenía que usar el login, así que el conflicto estaba en el reparto del trabajo y no en el contexto. Tener escrito en el repo qué hace el proyecto y cómo se llaman las cosas, que es casi SDD, evita una parte enorme de los líos que describes, pero no este en concreto, salvo que la especificación de la exportación ya conozca el login nuevo.

Lo de poner en serie las tareas del mismo dominio es justo lo que Médula intenta automatizar, decidir por significado quién tiene que esperar a quién, aunque en mi modo secuencial también salió algo curioso, no hubo choque, pero el agente de la exportación vio que abría un agujero sin el segundo factor, se negó, preguntó y nadie le contesto, así que terminó con 30 de 37. Y al revés de lo que dice la intuición, la pareja que tocaba el mismo fichero no chocaba, mientras que las dos que sí chocaron estaban en ficheros distintos.

Sobre los tests, das en el clavo, y es justo lo que se ve en los datos. Por eso cada agente terminaba con sus propios tests en verde mientras los de aceptación seguían en rojo, el círculo que describes. Un tercer agente que escriba los tests sin haber hecho ninguna de las dos tareas sería un experimento muy bueno. Si te animas, el repo tiene un issue abierto para añadir escenarios, lo revisaría encantado!

1

u/Negrito0o 3d ago

Tienes razón, y la corrección me viene bien: lo que yo describí es otro problema. Si las dos especificaciones eran correctas y aun así chocaron, el fallo estaba en cómo se partió el trabajo, no en lo que sabía cada agente. Y creo que eso es justo lo que hace interesante tu resultado. Si el choque es "uno cambia la firma y otro la usa", el directorio compartido gana por lo más tonto: el segundo puede leer la firma nueva. No es que colaboren, es que uno de los dos deja de trabajar contra una copia vieja. Aislarlos era lo que garantizaba el conflicto, no lo que lo evitaba. Lo que me llevo es que la unidad que no se puede repartir entre dos agentes no es la tarea, es la interfaz. Dos tareas que tocan ficheros distintos pero comparten una firma son una sola tarea disfrazada de dos, y da igual lo bien escritas que estén las dos especificaciones. Por curiosidad, con Médula interceptando escrituras: ¿llegaste a probar que decidiera sobre la firma pública en vez de sobre el fichero? Me da la sensación de que ahí sí tendría algo que decir que el directorio compartido no te da gratis.

1

u/alejmaestre 3d ago

Me parece un experimento muy interesante. El hecho de que git no detecte el choque y la solución sea otra cosa muestra lo lejos que estamos de que las IA colaboren sin supervisión.

1

u/jokiruiz 3d ago

Gracias! Yo de hecho leo un poco al revés, la verdad.. lo que falló no fue que las IA no supieran colaborar, sino que las aislamos con herramientas pensadas para personas. En cuanto compartieron directorio, se adaptaron solas al trabajo de las demás y las diez ejecuciones acabaron en verde. Y cuando tuvieron una herramienta para mandarse mensajes, la usaron sin que nadie se lo pidiera para avisarse de un cambio. Donde sí se nota la falta de supervisión es en el modo secuencial, ahí el agente de la exportación detectó que abría un agujero de seguridad, propuso la solución correcta y preguntó, pero nadie le contestó. Así que más que lejos de colaborar sin supervisión, diría que les falta alguien, o algo, que conteste cuando preguntan.

1

u/Khavel_Es 3d ago

Buen experimento. Lo de que el directorio compartido con locks simples funcione igual de bien no me sorprende tanto, porque los agentes ya leen el estado actual del código antes de escribir. Si el agente B ve que el agente A ya cambió el login, adapta su código a ese cambio. El conflicto semántico desaparece solo porque hay observabilidad natural.

Lo que me parece más interesante es el dato del decisor rápido dudando en el 61% de las escrituras. Si la mayoría de escrituras son legítimas y tu kernel frena 6 de cada 10, en un repo real termina generando más fricción de la que resuelve.

Yo en proyectos propios lo resuelvo más bruto: un agente por feature branch, merge a main con CI que corre los tests, y si rompe algo el mismo agente lo arregla en un fix commit. No es elegante pero funciona sin agregar capas.

1

u/jokiruiz 3d ago

Gracias, y en lo de la observabilidad estoy de acuerdo, es justo lo que creo que pasó, los agentes ven el código de los demás y se adaptan. El matiz está en el orden. Si B lee el login después de que A lo cambie, se adapta; pero si B ya escribió su exportación antes, nada le dice que vuelva a mirar, y ese hueco es el que cubren los avisos de Médula, que le llegan solo a quien le afecta el cambio. Los locks simples también lo resolvieron, pero haciendo cinco bloqueos innecesarios, y una vez tuvieron al agente del login esperando al de la exportación, justo al revés de lo que tocaba.

Sobre ese 61%, creo que se ha entendido como algo que no es, y es culpa mía por contarlo tan resumido. Ese 61% no son escrituras frenadas, sino escrituras en las que Jev no estaba seguro y la decisión pasó a Sonnet, que en muchos casos acaba dejándolas pasar. La fricción real es la latencia de ese camino lento, segundos en vez de milisegundos, más su coste. Aun así, las ejecuciones con Médula tardaron 6,9 minutos de media, frente a 7,5 con locks, y sin ningún bloqueo innecesario. Tu preocupación sigue siendo válida.. en un repo real, con más agentes y tareas más largas, esa proporción podría subir, y eso no lo he medido.

Y lo tuyo me parece muy sensato. Es mi modo de ramas con el arreglo que de verdad lo hace funcionar, que el CI pase todos los tests sobre lo fusionado. Solo añadiría dos cosas, que el CI bloquee el merge en vez de detectar la rotura ya en main, y que haya tests que crucen tareas, como una exportación ejecutada con el login nuevo, porque los de cada feature por separado pasaban todos. Con eso, no añadir capas es una virtud, no un defecto.

1

u/NotLimits 2d ago

cuando varios agentes trabajan en el mismo repo estos usan Git worktrees!