Saltar al contenido
astorlm
Idioma: Español
← Mapa

Nivel 8

Caché de prompts

En cada turno, el bucle le vuelve a mandar al modelo el pedido entero. Casi todo es igual que la vez anterior, y el proveedor puede recordarlo, siempre que no cambies cómo empieza.
1/35 Pliegues del bandoneón:
  • user
  • assistant
  • tool_result
Noche de juegos. En cada turno, el bucle le manda al Oráculo el pedido entero otra vez, así que Astor lo toca en el Simon: una luz por bloque, primero el system prompt y las herramientas, después cada mensaje.

EventBus

El problema

Un modelo no recuerda nada entre llamadas, así que el bucle reenvía todo en cada turno: el system prompt, la lista de herramientas y el historial entero. En un agente que corre diez turnos, las instrucciones largas de arriba viajan diez veces, y se pagan diez veces.

Y lo hacen más lento: antes de escribir una sola palabra, el modelo tiene que volver a leer el pedido entero, desde el primer token.

La solución

Los proveedores guardan una memoria de corta duración de los pedidos que acaban de leer. Cuando un pedido nuevo empieza exactamente igual que uno reciente, reutilizan la parte que coincide y solo procesan el resto. Esa parte se cobra a una fracción del precio (muchas veces un décimo, según el proveedor y el modelo), y la respuesta empieza antes.

La regla está en la palabra empieza: la coincidencia se cuenta desde el primer token y se corta en el primero que es distinto. Un agente encaja naturalmente, porque cada pedido es el anterior más unos pocos mensajes al final. Lo único que tienes que hacer es no romperlo:

  • Algo que cambia, arriba de todo

    la hora, un id de pedido, el nombre del usuario

    Mantén fijo el system prompt. Lo que cambia va en el último mensaje, al final.

  • Herramientas que se mueven

    otro orden, una herramienta agregada a mitad de camino

    Arma la lista de herramientas una vez, en un orden fijo, y manda la misma en cada turno.

  • Reescribir el pasado

    editar, recortar o resumir mensajes viejos

    Solo agrega al final. Cuando tengas que reescribir, todo lo que viene después de ese punto se paga de nuevo.

  • Cambiar de modelo

    un modelo más barato para un turno

    Cada modelo tiene su propia caché. Un cambio la empieza de cero.

Algunos proveedores cachean solos cuando el pedido es lo bastante largo: OpenAI lo hace desde 1.024 tokens. Otros, como Anthropic, solo cachean donde lo marcas. En cualquier caso, el uso que devuelven dice cuántos tokens de entrada salieron de la caché, así que puedes comprobarlo.

El elenco

El mismo elenco de siempre, en una noche de juegos.

El Simon el pedido
Cada ronda repite la secuencia entera y le agrega algo al final, como cada turno reenvía el pedido.
Las luces sus bloques
Amarillas para el system prompt y las herramientas, y después una por mensaje, con los colores del historial.
Astor el bucle
Le toca al Oráculo la secuencia entera en cada turno, y después ejecuta las herramientas como siempre.
El Oráculo el modelo
Su globo es la caché del proveedor: las luces que ya conoce, desde la primera.
El marcador el uso
Tokens de entrada enviados, leídos de la caché y pagados, con los cacheados a un décimo.
El living las herramientas
La repisa de juegos y el teléfono: game_shelf y order_pizza.

El código

Con astorlm: el agente arma su system prompt una vez y lo reenvía sin cambios en cada turno, con las mismas herramientas en el mismo orden, y el historial solo crece al final. Tu parte es dejar lo que cambia fuera de systemPrompt. Cada turn_end trae cacheReadTokens, que OpenAIProvider lee de la respuesta.

Desde cero: el bucle del nivel 2, con su comienzo fijo armado una vez fuera del bucle, y una línea que registra cached_tokens del uso de cada respuesta.

import { OpenAIProvider, createLocalAgent, tool } from 'astorlm'
import { z } from 'zod'

const gameShelf = tool({
  name: 'game_shelf',
  description: 'List the board games on the living-room shelf.',
  schema: z.object({}),
  execute: async () => home.shelf(), // your code
})

const orderPizza = tool({
  name: 'order_pizza',
  description: 'Order pizza for delivery. Returns how long it will take.',
  schema: z.object({ size: z.enum(['medium', 'large']), count: z.number().int().min(1) }),
  execute: async ({ size, count }) => pizzeria.order(size, count), // your code
})

const agent = await createLocalAgent({
  // Any OpenAI-compatible endpoint: OpenAI, Ollama, LM Studio, vLLM, a proxy…
  provider: new OpenAIProvider({
    baseURL: 'http://localhost:11434/v1', // e.g. Ollama's default address
    model: 'your-model', // e.g. 'llama3.1', 'gpt-4o-mini'
    apiKey: 'YOUR_API_KEY', // local servers usually ignore it
  }),
  // The start of every request. astorlm builds it once and resends it unchanged every turn.
  // Nothing that changes goes here: no clock, no request id, no user name.
  systemPrompt: HOUSE_RULES, // a long, fixed text: the more of it, the more the cache saves
  tools: [gameShelf, orderPizza], // same tools, same order, every turn
  maxTurns: 10,
})

// OpenAI caches long prompts on its own (from 1,024 tokens), and says how much it reused.
agent.on('event', (event) => {
  if (event.type !== 'turn_end' || !event.usage) return
  const { inputTokens, cacheReadTokens = 0 } = event.usage
  console.log(`turn ${event.turn}: ${cacheReadTokens} of ${inputTokens} input tokens from cache`)
})

// Need the time? Put it at the end, in the message, where it only changes what comes after it.
const now = new Date().toLocaleTimeString()
await agent.run(`Game night for four: see what games we have, and order pizza. (It is ${now}.)`)

Qué vigilar

  • La caché no dura. Vive unos pocos minutos sin uso. Un agente que espera una hora a una persona, o un heartbeat que late cada dos horas, vuelve a pagar entero su primer pedido.
  • La compactación y la caché tiran para lados opuestos. Achicar los mensajes viejos, el próximo nivel, reescribe el pasado, así que cada token después del primer cambio se paga entero en el turno siguiente. Compacta pocas veces, y en pasos grandes.
  • Los prompts cortos no se cachean. Por debajo del mínimo del proveedor, no hay nada que ahorrar. La caché rinde con system prompts largos, muchas herramientas o historiales largos: justo lo que tienen los agentes.
  • Mídelo. Si cacheReadTokens sigue en cero desde el segundo turno, algo del comienzo está cambiando. Compara dos pedidos lado a lado y busca la primera diferencia.
  • Solo ahorra en la entrada. Los tokens que escribe el modelo cuestan lo mismo. En los agentes, la entrada suele ser la mayor parte de la cuenta, así que sigue siendo el ahorro más grande que hay.