Dale a una tarea secundaria su propia ventana
Un subagente es una segunda llamada al modelo que toma una tarea secundaria, trabaja en una ventana nueva y devuelve una respuesta corta. El padre nunca ve el trabajo, solo el resultado.
Ese es el sentido. Una búsqueda que lee cuarenta archivos llenaría la ventana del padre. Hecha en un subagente, le cuesta unas pocas líneas.
Al final de esta lección
Nota
Puedo dar a una tarea secundaria su propio contexto y recoger solo la respuesta, con un encargo de entrada y un resultado corto de salida.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Subagente | una llamada al modelo que hace sola una tarea secundaria |
| Aislamiento | la tarea secundaria tiene su propia ventana |
| Encargo | el mensaje corto que pone en marcha un subagente |
| Contrato | los campos y el tamaño que debe tener un resultado |
| Resultado | lo que devuelve el subagente |
| Padre | el agente que pidió la tarea secundaria |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un subagente no es un traspaso
Un traspaso, como el que se aprende al construir agentes, pasa todo el trabajo a otro agente, que sigue. Un subagente es distinto. El padre sigue al mando y hace una sola pregunta.
El subagente empieza vacío. No ve el historial del padre. Ve el encargo y nada más.
Escribe un encargo y luego un contrato
Un buen encargo indica el objetivo, los datos que importan, los archivos que mirar y el tamaño de la respuesta. Todo lo que el subagente necesita está ahí, porque no tiene otra fuente.
Un contrato dice qué vuelve: campos con nombre y un límite de palabras. El arnés corta el resultado al contrato antes de que el padre lo lea. Una respuesta larga no es una respuesta mejor.
Forma de un encargo y un resultado
| Parte | Contiene | Por qué |
|---|---|---|
| Objetivo | Una pregunta | El subagente sabe cuándo ha terminado |
| Datos | Lo que ya se sabe | No repite el trabajo |
| Archivos | Dónde mirar | No se pierde |
| Tamaño | Un límite de palabras | El resultado sigue corto |
| Contrato | Campos y un límite | El padre lee una forma fija |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un error frecuente
Advertencia
Mucha gente pasa todo el historial del padre al subagente, por si acaso. Entonces nada queda aislado y el coste se duplica. Escribe un encargo con solo lo que la tarea secundaria necesita.
Escribe el ayudante del modelo, parte 1
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.
Escribe el ayudante del modelo, parte 2
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.
Escribe la ejecución del subagente, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' '// Las palabras hacen de tokens, como en la lección 1.' 'function words(text) { return text.split(\" \").length; }' 'const parent = \"La persona quiere arreglar la prueba que falla. Leímos app.py, ejecutamos dos veces las pruebas, miramos el leeme y hablamos un rato de estilo. Pidió mantener los cambios pequeños.\";' 'const work = [' ' \"ls: app.py leeme tests notas.txt viejo.py\",' ' \"grep total: app.py línea 4 def total items return sum items\",' ' \"grep total: tests línea 9 assert total de 3 items igual a 12\",' ' \"leer tests: 40 líneas de código de prueba de la cesta\",' ' \"leer app.py: 22 líneas que calculan una cesta y suman el impuesto\",' '];' > sub4.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe la ejecución del subagente, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function makeBrief(goal, facts, files, max) {' ' const lines = [\"Objetivo: \" + goal];' ' for (const f of facts) lines.push(\"Dato: \" + f);' ' for (const f of files) lines.push(\"Archivo: \" + f);' ' lines.push(\"Responde en \" + max + \" palabras como máximo.\");' ' return lines.join(\" | \");' '}' 'function cut(text, max) { return text.split(\" \").slice(0, max).join(\" \"); }' 'function sum(list) { return list.reduce(function (a, b) { return a + b; }, 0); }' >> sub4.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe la ejecución del subagente, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const brief = makeBrief(\"Encontrar dónde se calcula el total de la cesta\", [\"La prueba de 3 items es incorrecta\"], [\"app.py\", \"tests\"], 20);' ' const sample = \"El total se calcula en app.py en la línea 4. Suma los items y no añade impuesto. Mira tests línea 9.\";' ' const own = brief + \" | \" + work.join(\" ; \");' ' const reply = await ask([{ role: \"user\", content: own }], sample, 60);' ' const result = cut(reply.text, 20);' ' console.log(\"ventana del padre: \" + words(parent) + \" palabras\");' ' console.log(\"ventana de la tarea secundaria: \" + words(own) + \" palabras, de las que \" + sum(work.map(words)) + \" son resultados de herramientas\");' ' console.log(\"resultado conservado: \" + result);' ' console.log(\"el padre paga \" + (words(brief) + words(result)) + \" palabras\");' '}' 'main();' >> sub4.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejecuta el subagente
docker exec -w /home/node/project agent node sub4.jsSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Los resultados de herramientas están grabados
Los cinco resultados de herramientas son inventados y están grabados, en lugar de lo que leería un subagente real. La llamada corta al modelo recibe el encargo y esos resultados, y el Run corta la respuesta a veinte palabras.
Sin modelo imprime una muestra grabada y usa una respuesta grabada.
Una salida posible
| Línea | Qué muestra |
|---|---|
| ventana del padre: 29 palabras | Lo que el padre ya contiene |
| ventana de la tarea secundaria: 90 palabras, de las que 53 son resultados de herramientas | Dónde ocurrió el trabajo |
| resultado conservado: El total se calcula en ... | Veinte palabras como máximo |
| el padre paga 52 palabras | El encargo y el resultado, no las 53 de las herramientas |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.