¿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

Cómo guardar en caché respuestas de un modelo

Después de esta lección: Puedo guardar en caché respuestas de un modelo con seguridad y decir qué hace que haya un acierto.

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

No pagues dos veces por una respuesta

Guardar en caché una respuesta de un modelo es almacenarla y devolverla cuando llega la misma petición. Importa porque una llamada cuesta dinero y segundos, y muchas peticiones se repiten.

Una página de ayuda pide al modelo que resuma la misma política de devoluciones para cada visitante. Sin caché, mil llamadas pagan mil veces la misma respuesta. Con caché basta una llamada, y las otras novecientas noventa y nueve son aciertos.

Al final de esta lección

Nota

Puedo guardar en caché respuestas de un modelo con seguridad y decir qué hace que haya un acierto.

Palabras clave

PalabraQué significa
Cachéun almacén de respuestas que ya pagaste
Clave de cachéel valor que decide si dos peticiones coinciden
Aciertouna petición respondida desde la caché
Fallouna petición que tiene que llamar al modelo
Caducidadel momento en que una entrada se descarta
Dato personaltodo lo que identifica a una persona

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

La clave se construye con toda la petición

Dos peticiones solo pueden compartir respuesta si el modelo ve lo mismo. Por eso la clave de caché cubre todo lo que cambia la respuesta. Eso es el modelo, cada mensaje con su rol y los parámetros, como la temperatura y el límite de respuesta.

Si dejas uno fuera, sirves la respuesta equivocada. Un hash, un resumen criptográfico de ese texto, mantiene la clave corta.

Ejemplo resuelto: qué cambia la clave

Cambio¿Misma clave?Por qué
Mismo modelo, mensajes y parámetrosSíEl modelo ve la misma petición
Una palabra distinta en un mensajeNoLos mensajes forman parte de la clave
Temperatura 0 y luego 1NoLas respuestas pueden diferir
Otro modeloNoOtro modelo responde distinto

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Las entradas caducan y lo personal queda fuera

Una respuesta envejece. Dale a cada entrada una caducidad: un tiempo de vida en segundos. Pasado ese tiempo se descarta y la siguiente petición es un fallo.

No guardes nunca lo personal. Una respuesta hecha con el correo o el pedido de un usuario podría servirse al siguiente que tenga la misma clave. Revisa la petición antes de buscar y salta la caché para ella.

Un error frecuente

Advertencia

Mucha gente cree que la caché siempre es segura, porque la respuesta es solo texto. Una respuesta guardada con los datos de una persona puede mostrarse a otra. Decide qué se puede guardar antes de guardar la primera entrada.

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 la caché, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const crypto = require(\"crypto\");' 'const { ask } = require(\"./model\");' '' 'let now = 0; // segundos, en un reloj que movemos nosotros' 'const TTL = 60; // una entrada vive 60 segundos' 'const cache = new Map();' > cache2.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 caché, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// La clave se construye con toda la petición: modelo, mensajes y parámetros.' 'function keyOf(request) {' '  const whole = JSON.stringify([request.model, request.messages, request.temperature, request.max_tokens]);' '  return crypto.createHash(\"sha256\").update(whole).digest(\"hex\").slice(0, 12);' '}' '// Los datos personales no se guardan nunca. Aquí: un correo o un número largo.' 'function personal(request) {' '  return /@|[0-9]{7,}/.test(JSON.stringify(request.messages));' '}' >> cache2.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 caché, parte 3

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function answer(request, sample) {' '  if (personal(request)) return \"omitida, es personal\";' '  const key = keyOf(request);' '  const found = cache.get(key);' '  if (found && found.expires > now) return \"acierto\";' '  const reply = await ask(request.messages, sample, request.max_tokens);' '  cache.set(key, { text: reply.text, expires: now + TTL });' '  return found ? \"caducado, fallo\" : \"fallo\";' '}' >> cache2.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 caché, parte 4

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const tip = [{ role: \"user\", content: \"Da un consejo sobre cachés, en una frase.\" }];' '  const base = { model: \"lab\", temperature: 0, max_tokens: 40, messages: tip };' '  const other = { ...base, temperature: 1 };' '  const secret = { ...base, messages: [{ role: \"user\", content: \"Escribe a [email protected] un consejo.\" }] };' '  const sample = \"Guarda solo lo que es igual para todos.\";' '  for (const at of [0, 30, 90]) {' '    now = at;' '    console.log(\"t=\" + at + \" s: \" + (await answer(base, sample)));' '  }' '  console.log(\"misma clave con otra temperatura: \" + (keyOf(base) === keyOf(other)));' '  console.log(\"petición personal: \" + (await answer(secret, sample)));' '}' 'main();' >> cache2.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 la caché

Comando
docker exec -w /home/node/project agent node cache2.js

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Esto es una maqueta

El laboratorio no tiene servidor de caché. La caché es un Map en el script y el reloj es un número que fija el script. Un sistema real usa un servicio de caché real que comparten todos los servidores.

Las reglas son las mismas: una clave con toda la petición, una caducidad y una revisión de datos personales.

Una salida posible

LíneaQué muestra
t=0 s: falloLa primera petición llama al modelo
t=30 s: aciertoLa misma petición, respondida desde la caché
t=90 s: caducado, falloLa entrada tenía 60 segundos, así que se vuelve a llamar
misma clave con otra temperatura: falseUn parámetro nuevo es una clave nueva
petición personal: omitida, es personalNunca se tocó la caché

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.