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
| Palabra | Qué significa |
|---|---|
| Herramienta | una función que el agente puede pedir al arnés que ejecute |
| Descripción | las palabras que dicen al modelo cuándo usar una herramienta |
| Herramienta estrecha | una herramienta que hace un solo trabajo |
| Parámetro | una entrada con nombre de una herramienta |
| Ambigüedad | dos herramientas que parecen servir para una misma tarea |
| Error de herramienta | el 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
| Fallo | Aspecto | Arreglo |
|---|---|---|
| Nombre vago | `do`, `helper` | Un verbo y un sustantivo |
| Descripción corta | `Hace cosas` | Decir qué lee o qué cambia |
| Sin límite | Ningún «no la uses» | Añadir para qué no sirve |
| Demasiados parámetros | Cinco o más | Dividirla 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
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 el revisor de herramientas, parte 1
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
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
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
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
docker exec -w /home/node/project agent node tools2.jsSe 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ínea | Qué muestra |
|---|---|
| read_file: sin fallos | Una herramienta estrecha, con límite |
| search_text: no-limit | Nunca dice cuándo no usarla |
| do: vague-name, short-description, no-limit, too-many-params | Cuatro 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.