Puntuar respuestas sin otro modelo
Puntuar una respuesta con reglas es comprobarla con código normal: ¿es JSON válido?, ¿la etiqueta es correcta?, ¿el número está en el rango? Importa porque las reglas son rápidas, gratis y dan siempre la misma respuesta.
El clasificador de la tienda ahora responde en JSON con una etiqueta, una urgencia y una frase para el cliente. Cada parte se comprueba con una regla.
Al final de esta lección
Nota
Puedo puntuar una respuesta con reglas que no necesitan un modelo.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Regla | una comprobación escrita en código que una respuesta pasa o no | |
| Igualdad exacta | el valor debe ser igual al esperado | facturación |
| JSON válido | la respuesta se decodifica en el formato pedido | |
| Dentro del rango | un número está entre dos límites | |
| Puntuación | el número de reglas que pasa una respuesta | |
| Frase prohibida | palabras que una respuesta nunca debe contener |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Cuatro tipos de regla cubren casi todo
La mayoría de las comprobaciones caben en cuatro tipos. JSON válido: la respuesta es el JSON pedido. Igualdad exacta: un campo vale lo esperado. Dentro del rango: un número queda entre límites. Contiene: una frase está, o no debe estar.
Cada regla ocupa pocas líneas. Ninguna necesita un modelo, así que una ejecución no cuesta nada.
Ejemplo resuelto: una regla para cada parte
| Parte de la respuesta | Regla | Un ejemplo que falla |
|---|---|---|
| Toda la respuesta | Es un objeto JSON válido | Claro, es un mensaje de envío |
| label | Igualdad exacta con el caso | facturación cuando se esperaba envío |
| urgency | Un entero de 1 a 3 | 7 |
| reply | Hasta 120 caracteres y ninguna frase prohibida | Tu reembolso ha sido aprobado |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Una puntuación por caso muestra dónde falla
Da a la respuesta un punto por cada regla que pasa. No pares en el primer fallo: los puntos muestran qué regla se rompió. Un caso aprueba solo cuando todas las reglas se cumplen.
Si la respuesta no es válida, ninguna regla posterior puede ejecutarse, así que su puntuación es 0.
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 reglas, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const forbidden = [\"reembolso ha sido\", \"garantizado\"];' 'function score(text, want) {' ' const out = { parses: false, label: false, range: false, reply: false };' ' let data = null;' ' try { data = JSON.parse(text); } catch (error) { return out; }' ' if (data === null || Array.isArray(data) || typeof data === \"string\" || typeof data === \"number\" || typeof data === \"boolean\") return out;' ' out.parses = true;' ' out.label = data.label === want;' > 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 las reglas, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' out.range = Number.isInteger(data.urgency) && data.urgency >= 1 && data.urgency <= 3;' ' const said = typeof data.reply === \"string\" ? data.reply : \"\";' ' const low = said.toLowerCase();' ' const banned = forbidden.some(function (phrase) { return low.includes(phrase); });' ' out.reply = said.length > 0 && said.length <= 120 && banned === false;' ' return out;' '}' 'function points(out) {' ' return (out.parses ? 1 : 0) + (out.label ? 1 : 0) + (out.range ? 1 : 0) + (out.reply ? 1 : 0);' '}' 'module.exports = { score, points };' >> 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 script de comprobación, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const { score, points } = require(\"./score\");' 'function reply(label, urgency, text) {' ' return JSON.stringify({ label: label, urgency: urgency, reply: text });' '}' 'const recorded = [' ' { id: 1, want: \"facturación\", text: reply(\"facturación\", 2, \"Perdona por el cobro doble, lo estamos revisando.\") },' ' { id: 2, want: \"envío\", text: reply(\"facturación\", 2, \"Lo estamos mirando.\") },' ' { id: 3, want: \"otro\", text: \"Claro, es un mensaje de envío.\" },' > check2.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 script de comprobación, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' { id: 8, want: \"envío\", text: reply(\"envío\", 7, \"Lamentamos oír eso.\") },' ' { id: 10, want: \"desconocido\", text: reply(\"desconocido\", 1, \"Tu reembolso ha sido aprobado.\") },' '];' 'function yesNo(value) { return value ? \"sí\" : \"no\"; }' 'function show(name, out) {' ' console.log(name + \": \" + points(out) + \" de 4 (JSON válido \" + yesNo(out.parses) + \", etiqueta \" + yesNo(out.label) + \", rango \" + yesNo(out.range) + \", respuesta \" + yesNo(out.reply) + \")\");' '}' 'for (const one of recorded) show(\"Caso grabado \" + one.id, score(one.text, one.want));' >> check2.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 script de comprobación, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const sample = reply(\"facturación\", 2, \"Lo sentimos, estamos revisando tu pedido.\");' ' const prompt = \"Clasifica este mensaje de una tienda. Responde solo con JSON de tres claves: label (facturación, envío, otro o desconocido), urgency (un número entero de 1 a 3) y reply (una frase amable de menos de 100 caracteres).\n\nMensaje: Me cobraron dos veces el mismo pedido\";' ' const text = await ask([{ role: \"user\", content: prompt }], sample, 120);' ' console.log(\"Respuesta real: \" + text);' ' show(\"Caso real 1\", score(text, \"facturación\"));' '}' 'main();' >> check2.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 cinco respuestas y una real
docker exec -w /home/node/project agent node check2.jsSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Una salida posible
| Línea | Qué muestra |
|---|---|
| Caso grabado 1 | 4 de 4, todas las reglas se cumplen |
| Caso grabado 2 | 3 de 4, la etiqueta es incorrecta |
| Caso grabado 3 | 0 de 4, palabras y no JSON |
| Caso grabado 8 | 3 de 4, la urgencia 7 sale del rango |
| Caso grabado 10 | 3 de 4, la frase prohibida |
| Caso real 1 | Suele dar 3 o 4 de 4 y puede cambiar en cada ejecución |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Pruébalo
Consejo
En score.js añade una tercera frase prohibida, perdona por el cobro doble, y ejecuta otra vez. El caso grabado 1 debe perder su último punto.
Un error frecuente
Advertencia
Mucha gente cree que la puntuación máxima con reglas indica una buena respuesta. Las reglas solo comprueban la forma y los hechos. Una respuesta puede ser válida, llevar la etiqueta correcta y seguir siendo grosera o inútil. Reserva las reglas para lo que el código puede decidir.