Cómo funciona un presupuesto de contexto
Un presupuesto de contexto es el número de tokens que dejas usar a cada parte de un prompt. Un modelo solo puede leer una cantidad limitada de una vez. Si las partes suman demasiado, algo tiene que quedarse fuera.
El módulo sobre coste, trazas y fiabilidad presupuesta dinero y llamadas. Esta lección va más allá: presupuesta la ventana misma, decide qué parte sale primero y dice al usuario qué se quedó fuera.
Al final de esta lección
Nota
Puedo decidir qué cabe en una ventana y qué va primero.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Token | un trozo pequeño de texto que un modelo cuenta | Más o menos una palabra |
| Ventana | el máximo de tokens que un modelo lee y escribe en una llamada | |
| Presupuesto | los tokens que puede usar una parte del prompt | |
| Prioridad | lo importante que es una parte. La 0 nunca se descarta | |
| Recortar | acortar una parte para que quepa | |
| Reserva | el hueco que se deja libre para la respuesta |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
La respuesta también necesita hueco
La ventana la comparten el prompt y la respuesta. Si el prompt la llena, la respuesta se corta o la llamada falla.
Por eso primero se deja hueco para la respuesta. Después se deja un pequeño margen de seguridad, porque tu recuento es solo una estimación. Lo que queda es el presupuesto del prompt.
Ejemplo resuelto: el presupuesto del prompt
| Paso | Tokens | Motivo |
|---|---|---|
| Ventana | 4000 | Lo máximo que el modelo puede manejar |
| Reserva para la respuesta | 500 | La respuesta necesita espacio |
| Seguridad, 5 por ciento | 200 | El 5 por ciento de 4000, por si el recuento falla un poco |
| Presupuesto del prompt | 3300 | 4000 menos 500 menos 200 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un error frecuente
Advertencia
Mucha gente cree que la ventana es solo para el prompt. También guarda la respuesta. Un prompt que llena toda la ventana no deja sitio para contestar.
¿Qué parte va primero?
Da una prioridad a cada parte. Las reglas y la pregunta del usuario son de prioridad 0: nunca se descartan. Si no caben, el prompt está roto y debes decirlo.
Después toma el resto por orden de importancia. Conserva una parte si cabe. Si no cabe, descártala, pero otra más pequeña posterior aún puede entrar.
Ejemplo resuelto: un presupuesto de 3300
| Parte | Tokens | Prioridad | Total hasta ahora | Resultado |
|---|---|---|---|---|
| Reglas | 300 | 0 | 300 | Conservada |
| Pregunta | 100 | 0 | 400 | Conservada |
| Documento A | 900 | 1 | 1300 | Conservada |
| Documento B | 800 | 2 | 2100 | Conservada |
| Documento C | 700 | 2 | 2800 | Conservada |
| Historial | 1400 | 3 | 4200 se pasaría | Descartada |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Recortar en vez de descartarlo todo
Descartar el historial pierde toda la conversación. Es mejor recortarlo: conserva los mensajes más nuevos que quepan.
Recorre desde el mensaje más nuevo hacia atrás. Para en el primero que no quepa, porque un hueco en medio de una conversación no tiene sentido.
Ejemplo resuelto: quedan 500 tokens
| Mensaje | Tokens | Total | Resultado |
|---|---|---|---|
| El más nuevo | 200 | 200 | Conservado |
| El anterior | 250 | 450 | Conservado |
| Dos antes | 300 | 750 se pasaría | Aquí se para |
| El más viejo | 40 | No se llega | Descartado, aunque cabría |
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 del presupuesto, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'function tokens(text) { return text.split(\" \").length; }' 'const parts = [' ' { name: \"reglas\", tokens: 60, priority: 0 },' ' { name: \"pregunta\", tokens: 25, priority: 0 },' ' { name: \"doc A\", tokens: 120, priority: 1 },' ' { name: \"doc B\", tokens: 90, priority: 2 },' ' { name: \"historial\", tokens: 150, priority: 3 },' ' { name: \"doc C\", tokens: 80, priority: 2 },' '];' > budget.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 del presupuesto, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function assemble(parts, budget) {' ' const order = parts.slice().sort(function (a, b) { return a.priority - b.priority; });' ' const kept = [];' ' let used = 0;' ' for (const p of order) {' ' if (p.priority === 0 || used + p.tokens <= budget) { kept.push(p.name); used = used + p.tokens; }' ' }' ' return { kept: kept, used: used };' '}' >> budget.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 del presupuesto, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' for (const budget of [350, 600]) {' ' const r = assemble(parts, budget);' ' const names = parts.map(function (p) { return p.name; });' ' console.log(\"presupuesto \" + budget + \": conservadas \" + names.filter(function (n) { return r.kept.includes(n); }).join(\", \"));' ' console.log(\" descartadas \" + (names.filter(function (n) { return r.kept.includes(n) === false; }).join(\", \") || \"ninguna\") + \", usados \" + r.used);' ' }' >> budget.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 del presupuesto, parte 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' const q = \"En una frase corta, ¿qué debe perder primero un prompt demasiado largo?\";' ' const sample = \"Debe perder primero lo más viejo o menos útil, y nunca las reglas ni la pregunta.\";' ' const reply = await ask([{ role: \"user\", content: q }], sample, 60);' ' console.log(\"el modelo dijo: \" + reply.text);' ' console.log(\"mi recuento \" + tokens(q) + \", recuento del modelo \" + (reply.inTokens === null ? \"no informado\" : reply.inTokens));' '}' 'main();' >> budget.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 presupuesto
docker exec -w /home/node/project agent node budget.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 |
|---|---|
| presupuesto 350: conservadas reglas, pregunta, doc A, doc B | Las partes que caben, en su orden primero |
| descartadas historial, doc C, usados 295 | Lo que quedó fuera y los tokens usados |
| presupuesto 600: conservadas ... y descartadas ninguna | Con espacio de sobra, entra todo |
| el modelo dijo: ... | Una frase del laboratorio. Una muestra grabada si ningún modelo responde |
| mi recuento 12, recuento del modelo ... | Mi recuento de palabras junto al del modelo, o no informado |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.