¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Cómo fallan los sistemas multiagente

Después de esta lección: Puedo encontrar el fallo en una transcripción y nombrar su clase.

Lección de 65 min8 comandosLaboratorio de agente de programación con IA: usa opencode para explicar y corregir código, y comprueba su trabajo

Un equipo falla como no falla un agente

Un fallo multiagente es una forma en que un equipo de agentes se tuerce y ningún agente solo lo haría. Importa porque la falta está en la conversación entre ellos, y cada agente parece correcto por separado.

Se encuentra leyendo la transcripción, la lista de mensajes que se enviaron.

Al final de esta lección

Nota

Puedo encontrar el fallo en una transcripción y nombrar su clase.

Palabras clave

PalabraQué significa
Transcripciónlos mensajes que enviaron los agentes, en orden
Bucleel mismo mensaje enviado una y otra vez
Interbloqueodos agentes que esperan cada uno al otro
Coste desbocadoun gasto de tokens que crece más allá del presupuesto
Pasada como hechouna suposición que después se repite como un hecho
Protecciónuna regla en el código que detiene un fallo pronto

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Cuatro formas de torcerse de un equipo

Un bucle repite un mensaje. Un interbloqueo pone a dos agentes esperando cada uno a que el otro empiece. Un coste desbocado crece, porque cada ronda lee todo el historial.

El cuarto es más discreto. Un trabajador supone, el siguiente agente repite la suposición, y al tercero ya se escribe como un hecho.

Ejemplo resuelto: la señal y la protección

FalloSeñal en una transcripciónProtección
Bucle (loop)Mismo emisor, receptor y texto tres vecesParar en la tercera repetición
Interbloqueo (deadlock)Dos mensajes que dicen esperando, cruzadosUn límite de tiempo y un desempate
Pasada como hecho (passed-on)Una suposición, y luego las mismas palabras como hechoLlevar el estado junto a la afirmación
Desbocado (runaway)Tokens por ronda que no dejan de subirUn presupuesto para toda la ejecución

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Mira primero la señal más clara

Una transcripción real puede mostrar más de una señal. Decide un orden y mantenlo. Un interbloqueo y un bucle paran el trabajo, así que nómbralos antes que el coste.

El módulo sobre cómo construir agentes ya trató la protección contra bucles. Esta lección trata de reconocer las cuatro, para saber qué protección añadir.

Un error frecuente

Advertencia

Mucha gente añade un reintento cuando un equipo se atasca. Un reintento alarga un bucle y no acorta un interbloqueo. Primero nombra el fallo, luego elige la protección que le corresponde.

Escribir el ayudante del modelo, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// Los tokens de una respuesta, o null si no trae ninguno.' 'function count(data, name) {' '  return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribir el ayudante del modelo, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"estado \" + res.status);' '    const d = await res.json();' '    return { text: d.choices[0].message.content, inTokens: count(d, \"prompt_tokens\"), outTokens: count(d, \"completion_tokens\"), recorded: false };' '  } catch (error) {' '    console.log(\"Muestra grabada: ningún modelo respondió (\" + error.message + \").\");' '    return { text: sample, inTokens: null, outTokens: null, recorded: true };' '  }' '}' 'module.exports = { ask };' >> model.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribir el detector de fallos, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'function m(from, to, text, tokens, status) {' '  return { from: from, to: to, text: text, tokens: tokens, status: status };' '}' 'const T = {};' 'T.loop = [m(\"autor\", \"revisor\", \"revisa el borrador\", 300, \"none\"), m(\"revisor\", \"autor\", \"añade una fuente\", 200, \"none\"),' '  m(\"autor\", \"revisor\", \"revisa el borrador\", 300, \"none\"), m(\"revisor\", \"autor\", \"añade una fuente\", 200, \"none\"),' '  m(\"autor\", \"revisor\", \"revisa el borrador\", 300, \"none\")];' 'T.deadlock = [m(\"planificador\", \"revisor\", \"esperando la revisión antes de planificar\", 150, \"none\"),' '  m(\"revisor\", \"planificador\", \"esperando el plan antes de revisar\", 150, \"none\")];' > fail.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribir el detector de fallos, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'T.passed = [m(\"lector\", \"planificador\", \"las visitas del sábado subieron un 40 por ciento\", 200, \"guess\"),' '  m(\"planificador\", \"autor\", \"las visitas del sábado subieron un 40 por ciento\", 200, \"fact\")];' 'T.grows = [m(\"a\", \"b\", \"ronda uno\", 1000, \"none\"), m(\"b\", \"a\", \"ronda dos\", 2000, \"none\"), m(\"a\", \"b\", \"ronda tres\", 4000, \"none\"),' '  m(\"b\", \"a\", \"ronda cuatro\", 8000, \"none\"), m(\"a\", \"b\", \"ronda cinco\", 16000, \"none\")];' 'T.fine = [m(\"planificador\", \"lector\", \"busca la demanda del domingo\", 200, \"none\"), m(\"lector\", \"planificador\", \"212 de 400\", 150, \"fact\")];' >> fail.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribir el detector de fallos, parte 3

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function some2(ms, test) {' '  return ms.some(function (x, i) { return ms.some(function (y, j) { return i < j && test(x, y); }); });' '}' 'function deadlock(ms) {' '  return some2(ms, function (x, y) {' '    return x.text.startsWith(\"esperando\") && y.text.startsWith(\"esperando\") && x.from === y.to && x.to === y.from;' '  });' '}' 'function loop(ms) {' '  return ms.some(function (x) {' '    return ms.filter(function (y) { return y.from === x.from && y.to === x.to && y.text === x.text; }).length >= 3;' '  });' '}' >> fail.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribir el detector de fallos, parte 4

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function passedOn(ms) {' '  return some2(ms, function (x, y) { return x.status === \"guess\" && y.status === \"fact\" && x.text === y.text; });' '}' 'function total(ms) { return ms.reduce(function (a, x) { return a + x.tokens; }, 0); }' 'function find(ms, budget) {' '  if (deadlock(ms)) return \"deadlock\";' '  if (loop(ms)) return \"loop\";' '  if (passedOn(ms)) return \"passed-on\";' '  return total(ms) > budget ? \"runaway\" : \"none\";' '}' >> fail.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribir el detector de fallos, parte 5

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  for (const name of Object.keys(T)) {' '    console.log(name + \": \" + T[name].length + \" mensajes, \" + total(T[name]) + \" tokens, encontrado \" + find(T[name], 20000));' '  }' '  const q = [{ role: \"user\", content: \"En una frase: ¿qué regla simple evita que dos agentes se envíen el mismo mensaje sin parar?\" }];' '  const r = await ask(q, \"Contar cada mensaje y parar en la tercera repetición.\", 40);' '  console.log(\"Modelo: \" + r.text.trim());' '}' 'main();' >> fail.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ejecutar el detector de fallos

Comando
docker exec -w /home/node/project agent node fail.js

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Son transcripciones grabadas

Una ejecución real gastaría muchos tokens en un solo equipo roto. Por eso las cinco transcripciones son datos grabados, cortos e inventados. El detector es código de verdad.

La única llamada en vivo pide una regla. Sus palabras cambian en cada ejecución.

Una salida posible

LíneaQué muestra
loop: 5 mensajes, 1300 tokens, encontrado loopUn mensaje tres veces
deadlock: 2 mensajes, 300 tokens, encontrado deadlockCada uno espera al otro
passed: 2 mensajes, 400 tokens, encontrado passed-onUna suposición pasó a ser hecho
grows: 5 mensajes, 31000 tokens, encontrado runawayPor encima del presupuesto de 20000
fine: 2 mensajes, 350 tokens, encontrado noneNinguna señal de fallo

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Sobre este laboratorio y su código: Laboratorio de agente de programación con IA: usa opencode para explicar y corregir código, y comprueba su trabajo

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.