Un registro que ayuda y no filtra
Un registro es una anotación que una aplicación escribe sobre lo que hizo. Cuando una respuesta es lenta o errónea, es donde miras.
Un registro descuidado copia cada mensaje y cada correo en un archivo que mucha gente puede leer. El objetivo es guardar lo bastante para arreglar cosas y no más.
Al final de esta lección
Nota
Puedo registrar lo bastante para depurar una petición y no más de lo debido.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Registro | una línea que un programa escribe sobre un suceso | |
| Identificador de petición | una etiqueta que une todos los registros de una petición | r-001 |
| Hash | un código corto hecho de un valor que no se puede deshacer | |
| Sal | una palabra secreta que se mezcla antes del hash | |
| Truncar | recortar un valor a unos pocos caracteres |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Guarda lo que necesitas para depurar
Pregúntate para qué usarás el registro. Para arreglar una respuesta lenta necesitas el identificador, la hora, el modelo y la longitud. No necesitas las palabras.
Un registro sin las palabras aún se puede unir a su petición. El identificador de petición es la clave que los une.
Ejemplo resuelto: un registro, antes y después
| Campo | Registro en bruto | Registro seguro | Por qué |
|---|---|---|---|
| request_id | r-001 | r-001 | Une el registro con la petición |
| user_email | [email protected] | f7933bc3 | Un hash con sal aún cuenta a un usuario |
| message | Reembolsa mi pedido, por favor | 30 (su longitud) | Las palabras se quedan fuera del registro |
| ms | 420 | 420 | Hace falta para hallar respuestas lentas |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un hash oculta el valor, no la persona
Un hash convierte un correo en un código corto. El mismo correo da siempre el mismo código, así que aún puedes contar usuarios. Nadie puede deshacer el código con solo leerlo.
Una sal hace el código más difícil de adivinar. Truncar es recortar un valor: guardar solo los 8 primeros caracteres de un hash, por ejemplo. Decide también quién puede leer el registro. Un registro que nadie necesita leer no debería existir.
Un error frecuente
Advertencia
Mucha gente cree que un hash es anónimo. No lo es. Quien tenga una lista de correos puede aplicarles el hash a todos y comparar los códigos. Un hash es un seudónimo, y el registro sigue siendo de datos personales. Usa una sal y guárdala lejos del registro.
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 registrador seguro, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const crypto = require(\"crypto\");' 'const raw = [' ' { request_id: \"r-001\", user_email: \"[email protected]\", message: \"Reembolsa mi pedido, por favor\", model: \"lab\", ms: 420 },' ' { request_id: \"r-002\", user_email: \"[email protected]\", message: \"Llámame al 600000001\", model: \"lab\", ms: 380 },' ' { request_id: \"r-003\", user_email: \"[email protected]\", message: \"¿Dónde está mi paquete?\", model: \"lab\", ms: 910 },' '];' > logsafe.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 registrador seguro, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function hash8(v) {' ' return crypto.createHash(\"sha256\").update(\"sal-lab:\" + v).digest(\"hex\").slice(0, 8);' '}' 'function safe(r) {' ' return { request_id: r.request_id, user: hash8(r.user_email), length: r.message.length, model: r.model, ms: r.ms };' '}' 'function holdsEmail(r) {' ' return Object.values(r).some(function (v) { return typeof v === \"string\" && v.includes(\"@\"); });' '}' >> logsafe.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 registrador seguro, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const out = raw.map(safe);' ' raw.forEach(function (r, i) {' ' console.log(r.request_id + \" original con correo: \" + holdsEmail(r) + \" | seguro con correo: \" + holdsEmail(out[i]));' ' console.log(\" \" + JSON.stringify(out[i]));' ' });' ' console.log(\"r-001 y r-003 mismo usuario: \" + (out[0].user === out[2].user));' ' console.log(\"r-001 y r-002 mismo usuario: \" + (out[0].user === out[1].user));' ' const q = \"En una frase corta, ¿por qué registrar la longitud de un mensaje y no el mensaje?\";' ' const sample = \"Una longitud ayuda a depurar respuestas lentas y no guarda nada de la persona.\";' ' const reply = await ask([{ role: \"user\", content: q }], sample, 60);' ' console.log(\"el modelo dijo: \" + reply.text);' '}' 'main();' >> logsafe.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 registrador seguro
docker exec -w /home/node/project agent node logsafe.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 Run
| Línea | Qué muestra |
|---|---|
| r-001 original con correo: true | seguro con correo: false | El registro seguro no tiene correo |
| {"request_id":"r-001","user":"f7933bc3",...} | El hash y la longitud, nada más |
| r-001 y r-003 mismo usuario: true | La misma persona sigue uniéndose |
| r-001 y r-002 mismo usuario: false | Dos personas siguen separadas |
| el modelo dijo: ... | Una frase. Las palabras cambian en cada ejecución |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.