¿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 diseñar herramientas para agentes LLM

Después de esta lección: Puedo escribir una herramienta que un modelo use bien, con un nombre claro, un límite dicho y un error útil.

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

Una herramienta es un manual para el modelo

Diseñar una herramienta para un agente es escribir su nombre, su descripción, sus parámetros y sus errores para que un modelo la use bien. Esas palabras son el único manual del modelo.

Una herramienta llamada do con cinco opciones sueltas se adivina. Una herramienta llamada read_file con una sola ruta se usa bien.

Al final de esta lección

Nota

Puedo escribir una herramienta que un modelo use bien, con un nombre claro, un límite dicho y un error útil.

Palabras clave

PalabraQué significa
Herramientauna función que el agente puede pedir al arnés que ejecute
Descripciónlas palabras que dicen al modelo cuándo usar una herramienta
Herramienta estrechauna herramienta que hace un solo trabajo
Parámetrouna entrada con nombre de una herramienta
Ambigüedaddos herramientas que parecen servir para una misma tarea
Error de herramientael texto que devuelve una herramienta cuando falla

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

Las herramientas estrechas ganan a las anchas

Una herramienta estrecha hace un solo trabajo y recibe pocos parámetros. Una herramienta ancha, como run_anything(options), obliga al modelo a inventar un minilenguaje, y suele equivocarse.

Da a cada trabajo su herramienta: read_file, write_file, list_files. Quédate en cuatro parámetros o menos. Una herramienta que necesita más suele ser dos herramientas.

Nombres y descripciones dicen cuándo no usarla

Un nombre es un verbo y un sustantivo: search_text, no helper. Una descripción dice qué hace la herramienta y también cuándo no usarla.

Dos herramientas que parecen servir para la misma tarea son una ambigüedad. Esa segunda frase las separa. Sin ella, el modelo elige al azar entre read_file y search_text, y lo descubres en una traza.

Fallos que hay que revisar

FalloAspectoArreglo
Nombre vago`do`, `helper`Un verbo y un sustantivo
Descripción corta`Hace cosas`Decir qué lee o qué cambia
Sin límiteNingún «no la uses»Añadir para qué no sirve
Demasiados parámetrosCinco o másDividirla en herramientas

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

Escribe los errores para el modelo

Un error de herramienta es la siguiente entrada que lee el modelo. Escríbelo, pues, para él: qué salió mal y qué hacer después.

Error: no hay ningún archivo en src/app.pyy. Llama a list_files y vuelve a intentarlo. dice al modelo cómo recuperarse. Un simple ENOENT no. En un rechazo, di que no reintente, o el modelo lo intentará una y otra vez.

Un error frecuente

Advertencia

Mucha gente escribe las palabras de una herramienta para sí misma y las deja cortas. El modelo no tiene nada más. Escribe la descripción como para un compañero que nunca ha visto el código.

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 revisor de herramientas, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const VAGUE = [\"do\", \"run\", \"handle\", \"tool\", \"helper\", \"process\", \"util\"];' 'const tools = [' '  { name: \"read_file\", description: \"Lee el texto de un archivo a partir de su ruta. No lo uses para carpetas.\", params: [\"path\"] },' '  { name: \"search_text\", description: \"Encuentra las líneas que contienen una palabra en todos los archivos del proyecto\", params: [\"word\"] },' '  { name: \"do\", description: \"Hace cosas\", params: [\"a\", \"b\", \"c\", \"d\", \"e\"] },' '];' > tools2.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 revisor de herramientas, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function faults(tool) {' '  const found = [];' '  if (VAGUE.includes(tool.name)) found.push(\"vague-name\");' '  if (tool.description.split(\" \").length < 8) found.push(\"short-description\");' '  if (tool.description.toLowerCase().includes(\"no lo uses\") === false) found.push(\"no-limit\");' '  if (tool.params.length > 4) found.push(\"too-many-params\");' '  return found;' '}' >> tools2.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 revisor de herramientas, parte 3

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function errorText(e) {' '  if (e.code === \"not_found\") return \"Error: no hay ningún archivo en \" + e.path + \". Llama a list_files y vuelve a intentarlo.\";' '  if (e.code === \"too_big\") return \"Error: \" + e.path + \" tiene \" + e.size + \" líneas y el límite es \" + e.limit + \". Pide un rango de líneas.\";' '  return \"Error: \" + e.code + \". No lo reintentes.\";' '}' >> tools2.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 revisor de herramientas, parte 4

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  for (const t of tools) console.log(t.name + \": \" + (faults(t).join(\", \") || \"sin fallos\"));' '  console.log(errorText({ code: \"not_found\", path: \"src/app.pyy\" }));' '  console.log(errorText({ code: \"too_big\", path: \"data.csv\", size: 9000, limit: 500 }));' '  const list = tools.slice(0, 2).map(function (t) { return t.name + \": \" + t.description; }).join(\" | \");' '  const task = \"Enséñame las primeras líneas de src/app.py. Responde solo con el nombre de una herramienta.\";' '  const reply = await ask([{ role: \"user\", content: \"Herramientas: \" + list + \" | \" + task }], \"read_file\", 10);' '  console.log(\"el modelo eligió: \" + reply.text);' '}' 'main();' >> tools2.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 revisor de herramientas

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

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

Lo que muestra la llamada al modelo

Al modelo del laboratorio se llega con texto plano, sin función de llamada a herramientas. Por eso el Run pega las descripciones en el prompt y pide un nombre de herramienta. Basta para mostrar que las palabras son el manual.

Las comprobaciones y los dos errores no necesitan ningún modelo.

Una salida posible

LíneaQué muestra
read_file: sin fallosUna herramienta estrecha, con límite
search_text: no-limitNunca dice cuándo no usarla
do: vague-name, short-description, no-limit, too-many-paramsCuatro fallos en una sola herramienta
Error: no hay ningún archivo en src/app.pyy. Llama a list_files y vuelve a intentarlo.Un error con un siguiente paso
el modelo eligió: ...Probablemente read_file. Las palabras cambian en cada ejecución

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.