¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Registrar con seguridad en una aplicación de IA

Después de esta lección: Puedo registrar lo bastante para depurar una petición y no más de lo debido.

Lección de 55 min6 comandosLaboratorio de agente de programación con IA: usa opencode para explicar y corregir código, y comprueba su trabajo

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

PalabraQué significaEjemplo
Registrouna línea que un programa escribe sobre un suceso
Identificador de peticiónuna etiqueta que une todos los registros de una peticiónr-001
Hashun código corto hecho de un valor que no se puede deshacer
Saluna palabra secreta que se mezcla antes del hash
Truncarrecortar 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

CampoRegistro en brutoRegistro seguroPor qué
request_idr-001r-001Une el registro con la petición
user_email[email protected]f7933bc3Un hash con sal aún cuenta a un usuario
messageReembolsa mi pedido, por favor30 (su longitud)Las palabras se quedan fuera del registro
ms420420Hace 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

Comando
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

Comando
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

Comando
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

Comando
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

Comando
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

Comando
docker exec -w /home/node/project agent node 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.

Lo que imprime el Run

LíneaQué muestra
r-001 original con correo: true | seguro con correo: falseEl 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: trueLa misma persona sigue uniéndose
r-001 y r-002 mismo usuario: falseDos 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.

Sobre este laboratorio y su código: Laboratorio de agente de programación con IA: usa opencode para explicar y corregir código, y comprueba su trabajo

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.