El agente que olvidó el presupuesto
La memoria de un agente es lo que lleva de un paso, o de una ejecución, al siguiente. Un modelo no recuerda nada por sí solo: la memoria es texto que tu programa vuelve a meter en la instrucción.
Un agente de compras propone un abrigo de 60 euros a una clienta que dijo 30. El presupuesto se dijo en el paso uno y había desaparecido en el nueve.
Al final de esta lección
Nota
Puedo decidir qué recuerda un agente entre pasos y entre ejecuciones.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Bloc de notas | las notas que un agente guarda durante una ejecución | |
| Resumen | un texto más corto que representa uno más largo | |
| Almacén | memoria que se guarda entre ejecuciones | |
| Presupuesto de memoria | el máximo de texto que cabe en la memoria | 120 caracteres |
| Ventana de contexto | el máximo de texto que un modelo lee de una vez |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Tres clases de memoria
El bloc de notas es la lista de mensajes y notas de una sola ejecución. Un resumen cambia un historial largo por un texto corto. Un almacén vive entre ejecuciones, en un archivo o en una base de datos.
Las tres acaban en la instrucción. Por eso cada línea recordada se envía de nuevo en cada paso, y la pagas cada vez.
Ejemplo resuelto: las tres clases comparadas
| Clase | Dura | Crece con | Riesgo principal |
|---|---|---|---|
| Bloc de notas | Una ejecución | Cada paso | Llena la ventana de contexto |
| Resumen | Una ejecución o más | Se sustituye cada vez | Pierde un detalle que importaba |
| Almacén | Entre ejecuciones | Cada ejecución | Datos viejos que ya no son ciertos |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Escribir la ayuda 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\";' '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 || 200 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"estado \" + res.status);' ' return (await res.json()).choices[0].message.content;' > 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.
Escribir la ayuda del modelo, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' } catch (error) {' ' console.log(\"Muestra grabada: ningún modelo respondió (\" + error.message + \").\");' ' const list = [].concat(sample);' ' const turn = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' ' return list[Math.min(turn, list.length - 1)];' ' }' '}' '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.
Escribir la demo de memoria, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const notes = [' ' { text: \"La clienta es Lucía, un regalo para su hermano\", important: true },' ' { text: \"Hoy llueve\", important: false },' ' { text: \"El presupuesto es de 30 euros\", important: true },' ' { text: \"Unos guantes cuestan 4 euros\", important: false },' ' { text: \"Una bufanda cuesta 18 euros\", important: false },' ' { text: \"A Lucía no le gusta el rojo\", important: true },' '];' 'const BUDGET = 120;' 'const memory = [];' 'function size() { return memory.reduce(function (n, m) { return n + m.text.length; }, 0); }' > memory1.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribir la demo de memoria, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function remember(note) {' ' memory.push(note);' ' while (size() > BUDGET) {' ' const at = memory.findIndex(function (m) { return m.important === false; });' ' if (at === -1) break;' ' console.log(\" olvidada: \" + memory[at].text);' ' memory.splice(at, 1);' ' }' ' console.log(\"Añadida, \" + memory.length + \" notas, \" + size() + \" caracteres\");' '}' >> memory1.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribir la demo de memoria, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' notes.forEach(remember);' ' const joined = notes.map(function (n) { return n.text; }).join(\". \");' ' const request = [{ role: \"user\", content: \"Resume estas notas en una frase para un agente que continúa el trabajo: \" + joined }];' ' const sample = \"Lucía busca un regalo para su hermano, hasta 30 euros y nada rojo.\";' ' console.log(\"Resumen: \" + await ask(request, sample, 80));' '}' 'main();' >> memory1.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejecutar y ver qué se olvida
docker exec -w /home/node/project agent node memory1.jsSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Una salida posible
| Línea | Qué puede mostrar |
|---|---|
| Añadida, 4 notas, 113 caracteres | El número de notas y de caracteres tras cada nota |
| olvidada: Hoy llueve | La quinta nota, la bufanda, pasa de 120, así que se va la más antigua sin importancia |
| olvidada: Unos guantes cuestan 4 euros | Sigue por encima, así que se va la siguiente sin importancia |
| Añadida, 3 notas, 102 caracteres | Quedan las tres notas importantes y la bufanda; la sexta nota hace que se vaya también la bufanda |
| Resumen | Una frase que nombra el presupuesto y el color que se evita |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Decide qué merece recordarse
Guarda lo que necesita el paso siguiente. Eso incluye lo que pidió el usuario, los límites que fijó, las decisiones tomadas y los datos que devolvió una herramienta. Descarta la charla y la salida en bruto de las herramientas.
Guarda las notas importantes palabra por palabra. Un resumen lo escribe un modelo y puede cambiar una cifra. Resume la charla y fija los datos.
Un error frecuente
Advertencia
Mucha gente cree que más memoria hace un agente mejor. La memoria se paga en cada paso y las notas viejas pueden confundir. Guarda lo que necesita el paso siguiente, con un límite de tamaño y una forma de olvidar.