¿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 construir un arnés de agente pequeño

Después de esta lección: Puedo reunir contexto, herramientas, modos, aislamiento y deshacer en un arnés que puedo ejecutar y rebobinar.

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

Reúne las piezas en un bucle

Un arnés de agente es el programa que rodea al modelo: construye la ventana, ejecuta las herramientas, aplica el modo y registra los cambios. El modelo solo propone un paso. El arnés decide lo que ocurre.

Esta lección une las cinco anteriores en un bucle que puedes ejecutar y rebobinar.

Al final de esta lección

Nota

Puedo reunir contexto, herramientas, modos, aislamiento y deshacer en un arnés que puedo ejecutar y rebobinar.

Palabras clave

PalabraQué significa
Arnésel programa que hace funcionar a un agente alrededor de un modelo
Buclepedir un paso, decidir, actuar, anotar y repetir
Modelo guionizadouna lista fija de pasos que sustituye a un modelo
Transcripciónel registro de cada paso y su resultado
Ventanalos últimos resultados que se envían al modelo a continuación
Rebobinardeshacer todos los cambios posteriores a un paso elegido

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

El bucle, paso a paso

En cada vuelta el arnés pide un paso al modelo. Decide por el modo: permitir, preguntar o denegar. Si debe preguntar, responde la persona. Si el paso está permitido, el arnés anota lo que va a sustituir y luego lo hace.

El resultado entra en una ventana, que solo guarda los últimos. Luego el bucle se repite hasta que el modelo dice que ha terminado.

Qué aporta cada lección anterior

LecciónSu lugar en el bucle
ContextoLa ventana solo guarda los últimos resultados
HerramientasCada paso nombra una herramienta estrecha
ModosUna función decide permitir, preguntar o denegar
AislamientoUna tarea secundaria devuelve un resultado corto a la ventana
DeshacerSe escribe una entrada de registro antes de un cambio

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

Un error frecuente

Advertencia

Mucha gente deja que un paso rechazado desaparezca. Entonces el modelo nunca aprende que fue rechazado y lo vuelve a pedir. Anota el rechazo como un resultado, para que la siguiente ventana lo muestre.

Escribe 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.

Escribe 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.

Escribe el arnés, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const RISK = { read_file: \"read\", write_file: \"write\", delete_file: \"destructive\", run: \"run\" };' 'const script = [' '  { tool: \"read_file\", path: \"app.py\" },' '  { tool: \"write_file\", path: \"app.py\", text: \"x = 2\" },' '  { tool: \"run\", path: \"pytest\" },' '  { tool: \"delete_file\", path: \"notas.txt\" },' '  { tool: \"write_file\", path: \".env\", text: \"CLAVE=1\" },' '  { tool: \"done\" },' '];' 'const files = { \"app.py\": \"x = 1\", \"notas.txt\": \"pendiente\" };' 'const log = [];' > harness6.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 arnés, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function decide(mode, risk, path) {' '  if (mode === \"plan\") return risk === \"read\" ? \"allow\" : \"deny\";' '  if (path.startsWith(\".env\") || risk === \"destructive\") return \"ask\";' '  if (mode === \"auto\" && (risk === \"read\" || risk === \"write\")) return \"allow\";' '  if (mode === \"ask\" && risk === \"read\") return \"allow\";' '  return \"ask\";' '}' >> harness6.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 arnés, parte 3

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function act(s, n) {' '  if (s.tool === \"read_file\") return s.path in files ? files[s.path] : \"ausente\";' '  if (s.tool === \"run\") return \"ejecutado \" + s.path;' '  log.push({ step: n, path: s.path, before: s.path in files ? files[s.path] : null });' '  if (s.tool === \"write_file\") { files[s.path] = s.text; return \"escrito \" + s.path; }' '  delete files[s.path];' '  return \"borrado \" + s.path;' '}' >> harness6.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 arnés, parte 4

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function runAll(mode, approvals) {' '  const out = [];' '  for (let i = 0; i < script.length; i++) {' '    const s = script[i];' '    if (s.tool === \"done\") break;' '    const v = decide(mode, RISK[s.tool], s.path);' '    let outcome = v === \"allow\" ? \"ok\" : \"denegado\";' '    if (v === \"ask\") outcome = approvals.shift() === true ? \"aprobado\" : \"rechazado\";' '    const good = outcome === \"ok\" || outcome === \"aprobado\";' '    out.push({ step: i + 1, tool: s.tool, path: s.path, outcome: outcome, result: good ? act(s, i + 1) : outcome });' '  }' '  return out;' '}' >> harness6.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 arnés, parte 5

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function undoTo(step) {' '  for (const e of log.slice().reverse()) {' '    if (e.step <= step) continue;' '    if (e.before === null) delete files[e.path];' '    else files[e.path] = e.before;' '  }' '}' >> harness6.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 arnés, parte 6

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const out = runAll(\"auto\", [true, false]);' '  for (const o of out) console.log(o.step + \" \" + o.tool + \" \" + o.path + \" \" + o.outcome + \" -> \" + o.result);' '  console.log(\"ventana \" + JSON.stringify(out.slice(-3).map(function (o) { return o.result; })));' '  console.log(\"archivos \" + JSON.stringify(files));' '  undoTo(1);' '  console.log(\"tras deshacer hasta 1 \" + JSON.stringify(files));' '  const text = out.map(function (o) { return o.tool + \" \" + o.outcome; }).join(\", \");' '  const reply = await ask([{ role: \"user\", content: \"Escribe un mensaje de commit de una línea para una ejecución que hizo esto: \" + text }], \"Corregir el total de la cesta en app.py\", 30);' '  console.log(\"mensaje: \" + reply.text);' '}' 'main();' >> harness6.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 arnés y rebobina

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

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

El modelo es un guion

Los pasos salen de una lista fija, así que cada estudiante imprime la misma ejecución. Un arnés real pediría cada paso al modelo. La llamada corta al modelo solo redacta un mensaje de commit a partir de lo que hizo la ejecución.

Sin modelo imprime una muestra grabada para esa línea.

Una salida posible

LíneaQué muestra
1 read_file app.py ok -> x = 1Una lectura pasa en modo auto
3 run pytest aprobado -> ejecutado pytestLa primera aprobación fue sí
4 delete_file notas.txt rechazado -> rechazadoLa segunda aprobación fue no
5 write_file .env rechazado -> rechazadoNo quedaba ninguna aprobación, así que no
archivos {"app.py":"x = 2","notas.txt":"pendiente"}Solo la escritura cambió algo
tras deshacer hasta 1 {"app.py":"x = 1",...}El rebobinado devolvió la escritura

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.