Quitar datos personales y qué rompe
Ocultar datos personales es sacarlos de un mensaje antes de que vaya a ningún otro sitio. Una aplicación de soporte puede ocultar un teléfono antes de pedir una respuesta a un modelo.
El problema es que la respuesta puede necesitar ese número. Cómo lo ocultas decide si luego puedes volver a ponerlo.
Al final de esta lección
Nota
Puedo quitar datos personales de un texto y decir qué rompe eso.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Ocultar | sacar los datos personales de un texto | |
| Máscara | cambiar un valor por su tipo | [CORREO] |
| Token | un sustituto que se puede volver a cambiar | [CORREO_1] |
| Mapa | la lista privada de qué token es qué valor | |
| Restaurar | volver a poner los valores reales |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Hay tres formas de ocultar datos
Una máscara cambia un valor por su tipo, como [CORREO]. Dos correos distintos pasan a ser [CORREO], así que no puedes distinguirlos ni devolverlos.
Un token lleva número, como [CORREO_1]. Guardas un mapa privado de tokens y valores y nunca lo envías. Destruir un valor significa que desaparece para siempre y no se guarda ningún mapa.
Ejemplo resuelto: un correo, tres formas
| Método | Lo que ve el modelo | ¿Puede la respuesta nombrarlo? | ¿Puedes restaurarlo? |
|---|---|---|---|
| Máscara | [CORREO] | No | No |
| Token | [CORREO_1] | Sí, como token | Sí, con tu mapa |
| Destruir | Nada | No | No, a propósito |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Ocultar puede romper la respuesta
Si el modelo nunca ve el correo, no puede escribirlo. Una respuesta que dice «te escribiremos a tu dirección» está bien. Una respuesta que debe repetir la dirección necesita un token.
Los tokens traen un riesgo nuevo. El modelo puede perder uno o cambiarlo. Restaura solo los tokens que vuelven y comprueba que no queda ninguno sin cambiar.
Un error frecuente
Advertencia
Mucha gente cree que los tokens vuelven anónimos los datos. No es así. Sigues teniendo el mapa, así que puedes convertirlos de nuevo en personas. En las palabras del RGPD, el reglamento europeo de protección de datos, son datos seudonimizados y siguen siendo datos personales. Es un resumen sencillo, no asesoramiento legal.
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 ocultador, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const text = \"Escribe a [email protected] o llama al 600000001. Gracias, Ana.\";' 'const counts = {};' 'const map = {};' 'function clean(word) {' ' let w = word;' ' while (w.length > 0 && \".,;:?()\".includes(w[w.length - 1])) w = w.slice(0, -1);' ' return w;' '}' > redact.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 ocultador, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function kindOf(w) {' ' const at = w.indexOf(\"@\");' ' if (at > 0 && w.indexOf(\".\", at) > at + 1) return \"CORREO\";' ' const num = w.split(\"\").every(function (c) { return c >= \"0\" && c <= \"9\"; });' ' if (w.length === 9 && num && (w[0] === \"6\" || w[0] === \"7\")) return \"TELEFONO\";' ' return \"\";' '}' 'function mask(t) {' ' return t.split(\" \").map(function (word) {' ' const w = clean(word);' ' return kindOf(w).length === 0 ? word : \"[\" + kindOf(w) + \"]\" + word.slice(w.length);' ' }).join(\" \");' '}' >> redact.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 ocultador, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function tokenise(t) {' ' const known = {};' ' return t.split(\" \").map(function (word) {' ' const w = clean(word);' ' const kind = kindOf(w);' ' if (kind.length === 0) return word;' ' if (known[w] === undefined) {' ' counts[kind] = (counts[kind] || 0) + 1;' ' known[w] = \"[\" + kind + \"_\" + counts[kind] + \"]\";' ' map[known[w]] = w;' ' }' ' return known[w] + word.slice(w.length);' ' }).join(\" \");' '}' >> redact.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 ocultador, parte 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function restore(t) {' ' let out = t;' ' Object.keys(map).forEach(function (k) { out = out.split(k).join(map[k]); });' ' return out;' '}' 'async function main() {' ' const safe = tokenise(text);' ' console.log(\"enmascarado: \" + mask(text));' ' console.log(\"tokenizado: \" + safe);' ' console.log(\"mapa guardado aquí: \" + JSON.stringify(map));' ' const q = \"Escribe una respuesta corta a este mensaje. Copia cada token entre corchetes tal cual. \" + safe;' ' const sample = \"Gracias. Escribiremos a [CORREO_1] y llamaremos al [TELEFONO_1] hoy.\";' ' const reply = await ask([{ role: \"user\", content: q }], sample, 80);' ' console.log(\"respuesta: \" + reply.text);' ' console.log(\"restaurada: \" + restore(reply.text));' '}' 'main();' >> redact.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 ocultador
docker exec -w /home/node/project agent node redact.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 |
|---|---|
| enmascarado: ... [CORREO] ... [TELEFONO] ... | Solo los tipos; nada se puede devolver |
| tokenizado: ... [CORREO_1] ... [TELEFONO_1] ... | Sustitutos con número |
| mapa guardado aquí: {...} | La lista privada, que nunca se envía |
| respuesta: ... | Una respuesta con tokens. Grabada si ningún modelo responde |
| restaurada: ... | Los tokens vueltos a los valores inventados |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.