Los datos de entrenamiento son ejemplos
Ajustar un modelo es enseñarle con ejemplos que tú aportas. Cada ejemplo es un par: lo que recibe el modelo y lo que quieres que devuelva. Lo que hagan tus pares, el modelo lo copia.
Así que una grafía descuidada, repetida cuarenta veces, son cuarenta lecciones de lo que no toca.
Al final de esta lección
Nota
Puedo escribir ejemplos de entrenamiento de los que un modelo pueda aprender.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Ajuste fino | seguir entrenando un modelo con tus ejemplos |
| Prompt | la mitad de entrada de un par de entrenamiento |
| Completion | la mitad de respuesta de un par de entrenamiento |
| JSONL | un archivo con un objeto JSON en cada línea |
| Etiqueta | una palabra fija que nombra una clase |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un par en cada línea
Un archivo JSONL guarda un ejemplo por línea. Cada línea es un objeto JSON pequeño con un prompt y un completion.
Una línea se revisa fácilmente sola. Si la línea 90 está rota, las líneas 1 a 89 siguen sirviendo. Por eso esta forma es habitual en los archivos de entrenamiento.
Ejemplo resuelto: tres líneas
| Línea | Qué contiene | Veredicto |
|---|---|---|
| 1 | prompt "Me han cobrado dos veces", completion "factura" | Correcta |
| 2 | prompt "Factura equivocada" y ningún completion | Falta completion |
| 3 | prompt "Me encanta vuestra tienda", completion "Otro" | Etiqueta desconocida: la mayúscula está mal |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Mantén siempre la misma forma
Un modelo aprende el patrón de tus pares, también los fallos. Si "factura" se escribe también "Factura" y "facturas", aprende tres respuestas.
Elige una lista fija de etiquetas, con una grafía para cada una y un solo formato para todos los prompts. Después revisa el archivo con un programa, no a ojo.
Un error frecuente
Advertencia
Mucha gente cree que cuantos más ejemplos, mejor, siempre. Cien pares limpios enseñan más que mil desordenados, porque el modelo copia también los fallos. Arregla primero el archivo y añade más después.
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 líneas, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const LABELS = [\"factura\", \"envio\", \"otro\"];' 'const lines = [' ' JSON.stringify({ prompt: \"Me han cobrado dos veces\", completion: \"factura\" }),' ' JSON.stringify({ prompt: \"¿Dónde está mi paquete?\", completion: \"envio\" }),' ' JSON.stringify({ prompt: \"Me encanta vuestra tienda\", completion: \"Otro\" }),' ' JSON.stringify({ prompt: \"Factura equivocada\" }),' ' JSON.stringify({ prompt: \"\", completion: \"otro\" }),' ' \"esto no es json\",' ' JSON.stringify({ prompt: \"La caja llegó aplastada\", completion: \"envio\" }),' '];' > adapt2.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 líneas, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function check(line) {' ' let row;' ' try { row = JSON.parse(line); } catch (e) { return \"no es JSON\"; }' ' if (row === null || typeof row === \"string\" || typeof row === \"number\") return \"no es un objeto\";' ' if (typeof row.prompt === \"undefined\" || typeof row.prompt === \"number\") return \"falta prompt\";' ' if (typeof row.completion === \"undefined\" || typeof row.completion === \"number\") return \"falta completion\";' ' if (row.prompt.trim() === \"\") return \"prompt vacío\";' ' if (LABELS.includes(row.completion) === false) return \"etiqueta desconocida\";' ' return \"\";' '}' >> adapt2.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 líneas, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' let ok = 0;' ' lines.forEach(function (line, i) {' ' const why = check(line);' ' if (why === \"\") ok = ok + 1;' ' else console.log(\"línea \" + (i + 1) + \": \" + why);' ' });' ' console.log(ok + \" de \" + lines.length + \" líneas correctas\");' ' const q = \"En una frase, ¿por qué cada ejemplo de entrenamiento debe escribir la etiqueta igual?\";' ' const sample = \"El modelo aprende cada grafía como una respuesta distinta, así que las grafías mezcladas dividen lo que aprende.\";' ' const reply = await ask([{ role: \"user\", content: q }], sample, 40);' ' console.log(\"el modelo dijo: \" + reply.text);' '}' 'main();' >> adapt2.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 líneas
docker exec -w /home/node/project agent node adapt2.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 encontró el revisor
Las siete líneas son inventadas. El revisor lee cada una sola y dice el primer fallo que encuentra, así que corriges un fallo cada vez.
La última línea es una llamada corta al modelo. Sin modelo imprime una Muestra grabada.