Trata un prompt como código que se publica
Un prompt cambia lo que hace una función, así que merece el cuidado que se da al código. Eso significa un archivo, una versión, una revisión, un despliegue gradual y una vuelta atrás. Importa porque una palabra cambiada puede mejorar un caso y romper otro, y nadie lo ve sin una prueba.
Un equipo edita un prompt en un panel el viernes por la tarde. El lunes llegan las quejas. Nadie sabe qué cambió ni cómo deshacerlo.
Al final de esta lección
Nota
Puedo versionar, revisar y desplegar un prompt como si fuera código.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Versión de prompt | un estado con nombre y guardado de un prompt | v2 |
| Caso de evaluación | una entrada con una regla de acierto | |
| Regresión | un caso que pasaba antes y falla ahora | |
| Despliegue gradual | servir un cambio a una parte de los usuarios | |
| Cubo | un número de 0 a 99 propio de cada usuario |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un prompt vive en un archivo versionado
Guarda cada prompt en un archivo del repositorio, con un nombre y una versión. Un cambio pasa a ser un commit, una revisión y una diferencia. El código se refiere a un prompt por nombre y versión, nunca por una cadena pegada.
La versión se escribe en cada registro. Cuando una respuesta es mala, puedes decir qué prompt la produjo.
Juzga un cambio con resultados grabados
Ejecuta los mismos casos de evaluación con el prompt viejo y el nuevo. Compara la tasa de acierto y lista las regresiones: los casos que pasaban y ahora fallan. Dos prompts con la misma tasa pueden acertar en casos distintos.
Marca algunos casos como obligatorios, por ejemplo una negativa que protege a un usuario. Un cambio que falla uno no sale, sea cual sea la tasa.
Ejemplo resuelto: v1 frente a v2
| Caso | v1 | v2 | Nota |
|---|---|---|---|
| c1 (obligatorio) | pasa | pasa | Se mantiene |
| c2 (obligatorio) | pasa | pasa | Se mantiene |
| c3 | falla | pasa | Arreglado |
| c4 | pasa | pasa | Se mantiene |
| c5 | pasa | falla | Regresión: una persona debe mirarlo |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Despliega con un cubo determinista
No cambies a todos los usuarios de golpe. Convierte el id de un usuario en un cubo de 0 a 99 con una función fija. El usuario recibe el prompt nuevo cuando su cubo es menor que el porcentaje del despliegue.
El mismo usuario recibe siempre la misma versión, y subir el porcentaje solo añade usuarios. No uses nunca un número aleatorio por petición: una persona vería las dos versiones.
Guarda un camino de vuelta
Guarda la versión vieja en el repositorio y el porcentaje en un solo ajuste. Para volver atrás, pon el porcentaje a cero. Sin desplegar, sin editar, sin discutir.
Sube el porcentaje por pasos y vigila las mismas medidas en cada paso: aciertos en muestras reales, coste y quejas.
Un error frecuente
Advertencia
Mucha gente cree que una tasa de acierto mayor significa un cambio seguro. Puede esconder un cambio de sitio: un caso arreglado, otro roto. Lee la lista de regresiones y comprueba los casos obligatorios, no solo la tasa.
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 la publicación del prompt, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const fs = require(\"fs\");' 'const { ask } = require(\"./model\");' '// Un prompt vive en un archivo con versión, así un cambio es una diferencia.' 'const file = { name: \"resumen\", version: \"v2\", text: \"Resume el ticket en una frase. Nombra el producto.\" };' 'fs.writeFileSync(\"prompt-resumen.json\", JSON.stringify(file, null, 1));' '// Resultados de evaluación grabados: ¿pasó cada caso? Inventados para la lección.' 'const oldRun = { c1: true, c2: true, c3: false, c4: true, c5: true };' 'const newRun = { c1: true, c2: true, c3: true, c4: true, c5: false };' 'const MUST = [\"c1\", \"c2\"]; // casos que nunca pueden fallar' > prompts.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 la publicación del prompt, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function rate(run) {' ' const names = Object.keys(run);' ' const passed = names.filter(function (n) { return run[n]; });' ' return Math.floor(passed.length * 100 / names.length);' '}' 'function reasons(a, b) {' ' const out = [];' ' if (rate(b) < rate(a)) out.push(\"tasa más baja\");' ' MUST.forEach(function (n) { if (b[n] === false) out.push(\"obligatorio falla: \" + n); });' ' return out;' '}' 'const slipped = Object.keys(oldRun).filter(function (n) { return oldRun[n] && newRun[n] === false; });' 'console.log(\"antes\", rate(oldRun), \"ahora\", rate(newRun));' 'console.log(\"puede salir:\", reasons(oldRun, newRun).length === 0, \"retrocesos:\", slipped.join(\",\"));' >> prompts.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 la publicación del prompt, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function bucket(user) {' ' let h = 0;' ' for (const c of user) h = (h * 31 + c.charCodeAt(0)) % 1000003;' ' return h % 100;' '}' 'const rollout = { prompt: \"v2\", fallback: \"v1\", percent: 20 };' 'function version(user) { return bucket(user) < rollout.percent ? rollout.prompt : rollout.fallback; }' '[\"sara\", \"raul\", \"ana\", \"diego\", \"marta\", \"pablo\"].forEach(function (u) { console.log(u, bucket(u), version(u)); });' 'rollout.percent = 0; // la vuelta atrás es un número' 'console.log(\"tras la vuelta atrás:\", version(\"sara\"), version(\"raul\"));' >> prompts.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 la publicación del prompt, parte 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const text = file.text + \" Ticket: El teléfono Orbit no carga desde el lunes.\";' ' const sample = \"El teléfono Orbit no carga desde el lunes.\";' ' console.log(\"Llamada real con v2:\", await ask([{ role: \"user\", content: text }], sample, 40));' '}' 'main();' >> prompts.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Juzga y despliega un prompt
docker exec -w /home/node/project agent node prompts.jsSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Qué está grabado y qué es real
Los resultados de evaluación están grabados y son inventados. Un equipo real ejecuta sus propios casos y guarda los resultados junto a la versión del prompt. La función del cubo y el ajuste del despliegue son la técnica real.
El Run escribe prompt-resumen.json. Ábrelo y lee la versión.
Una salida posible
| Línea | Qué muestra |
|---|---|
| antes 80 ahora 80 | La tasa de acierto es la misma |
| puede salir: true retrocesos: c5 | La regla lo permite, y una persona aún lee c5 |
| sara 4 v2 y los demás usuarios | Cada usuario tiene un cubo y una versión fijos |
| tras la vuelta atrás: v1 v1 | Un porcentaje cero manda a todos a v1 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.