La respuesta buena por un mal camino
Una trayectoria es la lista de pasos que un agente dio para llegar a su respuesta. Puntuarla sirve porque un agente puede acertar tras malgastar llamadas, o por suerte, y cada paso se paga.
La tienda tiene un agente de soporte que reembolsa pedidos. Sus respuestas parecen buenas. Sus caminos, no tanto.
Al final de esta lección
Nota
Puedo puntuar los pasos que dio un agente frente a un camino de referencia.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Trayectoria | los pasos que dio un agente, en orden |
| Camino de referencia | los pasos que debe dar una buena ejecución |
| Llamada inútil | un paso que repite uno anterior |
| Presupuesto de pasos | el máximo de pasos de una ejecución |
| Nota del camino | puntos por la forma de llegar |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Puntúa el camino, no solo la respuesta
Una comprobación de la respuesta final hace una pregunta: ¿es correcta? Una comprobación del camino pregunta cómo llegó el agente. Mira la trayectoria y la compara con un camino de referencia.
Un camino muestra cuatro fallos. Falta un paso. Una llamada inútil repite otra. Un paso está fuera de orden. O hay demasiados pasos para el presupuesto de pasos.
Ejemplo resuelto: cuatro ejecuciones grabadas
| Ejecución | Pasos dados | Respuesta | Fallos del camino |
|---|---|---|---|
| A | buscar, reembolsar, escribir | buena | ninguno |
| B | buscar, buscar, ayuda, reembolsar, escribir | buena | una repetición, fuera de presupuesto |
| C | reembolsar, buscar, escribir | buena | reembolso antes de buscar |
| D | buscar, escribir | mala | falta el reembolso |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Convierte los fallos en una nota
Da a cada fallo un coste fijo y réstalo de 100. Aquí un paso que falta cuesta 25, una llamada inútil 10, pasarse del presupuesto 20 y un orden incorrecto 15.
Elige los costes antes de mirar las ejecuciones. La referencia no es el único buen camino: puntúa el orden solo donde importa.
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\";' '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 || 200 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"estado \" + res.status);' ' return (await res.json()).choices[0].message.content;' > 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' ' } catch (error) {' ' console.log(\"Muestra grabada: ningún modelo respondió (\" + error.message + \").\");' ' const list = [].concat(sample);' ' const turn = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' ' return list[Math.min(turn, list.length - 1)];' ' }' '}' '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 las ejecuciones grabadas
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const reference = [\"lookup_order:A17\", \"refund:A17\", \"send_message:A17\"];' '// Ejecuciones grabadas de un agente de soporte. Cada paso es una herramienta y su argumento.' 'const runs = [' ' { name: \"Ejecución A\", answer: \"ok\", steps: [\"lookup_order:A17\", \"refund:A17\", \"send_message:A17\"] },' ' { name: \"Ejecución B\", answer: \"ok\", steps: [\"lookup_order:A17\", \"lookup_order:A17\", \"search_help:refund\", \"refund:A17\", \"send_message:A17\"] },' ' { name: \"Ejecución C\", answer: \"ok\", steps: [\"refund:A17\", \"lookup_order:A17\", \"send_message:A17\"] },' ' { name: \"Ejecución D\", answer: \"mala\", steps: [\"lookup_order:A17\", \"send_message:A17\"] },' '];' 'module.exports = { reference, runs };' > paths.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 puntuador de caminos, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { reference, runs } = require(\"./paths\");' 'const { ask } = require(\"./model\");' 'const budget = 4;' 'function wasted(steps) {' ' const seen = [];' ' let count = 0;' ' steps.forEach(function (step) {' ' if (seen.includes(step)) count = count + 1;' ' else seen.push(step);' ' });' ' return count;' '}' 'function missing(steps) {' ' return reference.filter(function (step) { return steps.includes(step) === false; });' '}' > score.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 puntuador de caminos, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function inOrder(steps) {' ' let at = 0;' ' steps.forEach(function (step) {' ' if (at < reference.length && step === reference[at]) at = at + 1;' ' });' ' return at === reference.length;' '}' 'function score(steps) {' ' let points = 100 - 25 * missing(steps).length - 10 * wasted(steps);' ' if (steps.length > budget) points = points - 20;' ' if (inOrder(steps) === false) points = points - 15;' ' return Math.max(points, 0);' '}' >> score.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 puntuador de caminos, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const weak = [];' 'runs.forEach(function (run) {' ' const points = score(run.steps);' ' console.log(run.name + \": \" + points + \" puntos, pasos \" + run.steps.length + \" de \" + budget + \", faltan \" + missing(run.steps).length + \", inútiles \" + wasted(run.steps) + \", en orden \" + inOrder(run.steps) + \", respuesta \" + run.answer);' ' if (run.answer === \"ok\" && points < 100) weak.push(run.name);' '});' 'console.log(\"Respuesta buena, camino débil: \" + weak.join(\", \"));' >> score.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 puntuador de caminos, parte 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const prompt = \"Un cliente pide el reembolso del pedido A17. Herramientas: lookup_order, refund, send_message, search_help. Responde solo con el nombre de la herramienta que llamarías primero.\";' ' const text = await ask([{ role: \"user\", content: prompt }], \"lookup_order\", 20);' ' console.log(\"Primer paso en vivo: \" + text.trim());' ' console.log(\"Coincide con la referencia: \" + text.includes(\"lookup_order\"));' '}' 'main();' >> score.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Puntúa las cuatro ejecuciones
docker exec -w /home/node/project agent node score.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 imprime el puntuador
| Línea | Lo que muestra |
|---|---|
| Ejecución A | 100 puntos, sin fallos |
| Ejecución B | 70 puntos: una llamada inútil y 5 pasos de 4 |
| Ejecución C | 85 puntos: fuera de orden |
| Ejecución D | 60 puntos: falta el reembolso, respuesta mala |
| Camino débil | la ejecución B y la ejecución C |
| Primer paso en vivo | Una salida posible: lookup_order |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Pruébalo
Consejo
En score.js cambia el presupuesto de 4 a 5 y puntúa otra vez. La ejecución B debe ganar 20 puntos. Decide si eso la convierte en un buen camino.
Un error frecuente
Advertencia
Mucha gente cree que el camino de referencia es el único correcto y marca cualquier otro orden como fallo. Un agente suele tener dos buenos caminos. Puntúa el orden solo cuando un paso necesita el resultado de otro, y admite una segunda referencia si dos órdenes sirven.