Cómo prever lo que cuesta una función
El coste de una función de IA es el número de llamadas que pagas por el precio de una llamada. Una caché reduce el primer número, porque una pregunta repetida se contesta desde la memoria.
El módulo sobre coste, trazas y fiabilidad muestra cómo se hace una clave de caché y cuándo caduca. Esta lección va más allá: cuenta los aciertos de una semana de tráfico y prevé un mes.
Al final de esta lección
Nota
Puedo prever lo que costará una función y cuánto ahorra una caché.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Caché | un almacén de respuestas que ya pagaste | |
| Acierto | una petición contestada desde la caché | |
| Fallo | una petición que la caché no puede contestar, así que pagas | |
| Tasa de aciertos | el porcentaje de peticiones que son aciertos | 50 |
| Caducidad | cuánto tiempo sigue siendo útil una respuesta guardada | |
| Previsión | una cuenta que predice el futuro a partir del pasado |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Lo que cuesta una llamada
Una llamada cuesta sus tokens de entrada por el precio de entrada, más sus tokens de salida por el precio de salida. La salida suele costar más.
Para que las cuentas sean números enteros, cuenta en unidades. Una unidad es una millonésima de euro. Los precios de aquí son inventados.
Ejemplo resuelto: una llamada
| Parte | Tokens | Precio por token | Unidades |
|---|---|---|---|
| Entrada | 120 | 3 | 360 |
| Salida | 80 | 15 | 1200 |
| Una llamada | 200 | 1560 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un error frecuente
Advertencia
Mucha gente cree que una caché ahorra lo mismo en todas las funciones. Ahorra solo lo que permitan las preguntas repetidas. Una función donde nadie pregunta lo mismo dos veces casi no ahorra nada.
Reproducir tráfico a través de una caché
Para medir una tasa de aciertos, reproduce peticiones reales o con semilla. Númeralas desde 0. Una petición es un acierto si la misma pregunta se guardó hace menos de ttl peticiones.
Un acierto no renueva la respuesta guardada. Caduca con su propio reloj, así que una pregunta popular recibe una respuesta nueva cuando se acaba su tiempo.
Ejemplo resuelto: ttl de 3
| Número de petición | Pregunta | Guardada en | Resultado |
|---|---|---|---|
| 0 | a | Nada | Fallo, se guarda en 0 |
| 1 | a | 0 | Acierto, 1 es menos que 3 |
| 2 | b | Nada | Fallo, se guarda en 2 |
| 3 | a | 0 | Fallo, 3 no es menos que 3, se guarda en 3 |
| 4 | a | 3 | Acierto |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Prever un mes a partir de una semana
Suma una semana de peticiones. Un mes son unos 30 días, así que las peticiones del mes son la semana por 30, entre 7.
Solo pagas los fallos. Multiplica por 100 menos la tasa de aciertos, divide entre 100 y luego multiplica por el coste de una llamada.
Ejemplo resuelto: una semana de 835 peticiones
| Paso | Cuenta | Resultado |
|---|---|---|
| Total de la semana | 120 + 135 + 150 + 160 + 170 + 60 + 40 | 835 |
| Peticiones del mes | 835 por 30 entre 7 | 3578 |
| Llamadas pagadas con un 50 por ciento | 3578 por 50 entre 100 | 1789 |
| Coste en unidades | 1789 por 1560 | 2790840 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
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 script de la caché, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'function next(seed) { return (seed * 75 + 74) % 65537; }' 'const table = [0, 0, 0, 1, 1, 2, 3, 4, 5, 6];' 'function traffic(seed, count) {' ' const out = [];' ' for (let i = 0; i < count; i++) { seed = next(seed); out.push(\"q\" + table[seed % 10]); }' ' return out;' '}' > cache.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 script de la caché, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function replay(requests, ttl) {' ' const stored = {};' ' let hits = 0;' ' requests.forEach(function (key, i) {' ' if (key in stored && i - stored[key] < ttl) hits = hits + 1;' ' else stored[key] = i;' ' });' ' return hits;' '}' 'const week = [120, 135, 150, 160, 170, 60, 40];' 'const perCall = 120 * 3 + 80 * 15;' >> cache.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 script de la caché, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const requests = traffic(7, 40);' ' console.log(\"primeras 8: \" + requests.slice(0, 8).join(\" \"));' ' for (const ttl of [5, 10, 20]) {' ' const hits = replay(requests, ttl);' ' const percent = Math.floor(hits * 100 / 40);' ' const month = Math.floor(week.reduce(function (a, b) { return a + b; }, 0) * 30 / 7);' ' const paid = Math.floor(month * (100 - percent) / 100);' ' console.log(\"ttl \" + ttl + \": \" + hits + \" aciertos, \" + percent + \" por ciento, el mes paga \" + paid + \" llamadas, \" + paid * perCall + \" unidades\");' ' }' >> cache.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 script de la caché, parte 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' const reply = await ask([{ role: \"user\", content: \"En una frase corta, ¿por qué una caché puede abaratar una función?\" }], \"Una pregunta repetida se contesta desde la memoria, así que no se paga otra llamada.\", 60);' ' console.log(\"el modelo dijo: \" + reply.text);' ' console.log(\"tokens de salida: \" + (reply.outTokens === null ? \"no informado\" : reply.outTokens));' '}' 'main();' >> cache.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 reproducción de la caché
docker exec -w /home/node/project agent node cache.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 |
|---|---|
| primeras 8: q6 q6 q0 q2 q0 q0 q5 q0 | El tráfico con semilla, igual para todos |
| ttl 5: 16 aciertos, 40 por ciento | Una caducidad corta da menos aciertos |
| ttl 20: 27 aciertos, 67 por ciento | Una caducidad más larga da más aciertos y una factura menor |
| el modelo dijo: ... | Una frase del laboratorio. Una muestra grabada si ningún modelo responde |
| tokens de salida: ... | El recuento que informa la respuesta, o no informado |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.