DEV Community

Juan Torchia
Juan Torchia

Posted on • Originally published at juanchi.dev

Medí cuánto me cuesta en tokens cada decisión de diseño de mi agente (y los números me incomodan)

Estuve seis meses diseñando agentes convencido de que el mayor costo era el modelo en sí. Me concentré en elegir el modelo correcto, en optimizar cuántas veces lo llamaba, en cachear respuestas. Todo eso está bien. Pero me estaba perdiendo la mitad del problema.

El verdadero gasto estaba en las decisiones que tomé antes de la primera inferencia. La arquitectura del prompt. Cómo estructuré las tool calls. Si acumulé contexto o lo resumí. Esas decisiones, que tomé en diez minutos cada una, me están costando tokens todos los días. Y yo ni lo sabía hasta que me puse a medir en serio.

Esto no es un benchmark de laboratorio. Son mis agentes, corriendo en producción, con números reales.

Tokenizer costs en agentes: el problema que no estás mirando

Cuando escribí sobre CodeBurn y el análisis de costo real por tarea, me enfoqué en cuántos tokens gasta cada tarea. Era la pregunta obvia. Pero hay una pregunta anterior que casi no toqué: cuántos tokens pesa cada decisión de diseño que tomé al construir el agente.

Son preguntas distintas. La primera es operativa. La segunda es arquitectónica. Y la segunda es más difícil de ver porque el costo está distribuido: no lo pagás una vez, lo pagás en cada llamada, para siempre.

La discusión de HN sobre tokenizer costs de Claude 4.7 lo plantea en abstracto. Yo lo quiero plantear en concreto, con los tres vectores que más me impactaron cuando los medí:

  1. Prompt largo vs prompt corto — cuánto pesa la verbosidad del system prompt
  2. Tool calls vs texto plano — el overhead real del JSON de herramientas
  3. Contexto acumulado vs contexto resumido — el efecto compuesto que te destruye en conversaciones largas

Los números reales: prompt largo vs prompt corto

Tengo un agente que curó información técnica — el mismo problema que describí cuando construí el sistema de curación auto-regulado. El system prompt original tenía 847 tokens. Lo escribí pensando en ser exhaustivo: reglas de formato, ejemplos de output, casos edge, instrucciones de fallback.

Lo reescribí en 180 tokens. Misma funcionalidad. Probé con 50 tareas distintas. La calidad de output cayó en... cero casos medibles. Literalmente ninguno.

El ahorro:

// Medición real con tiktoken para Claude
import Anthropic from '@anthropic-ai/sdk';

// Función para estimar tokens antes de enviar
async function estimarCostoPrompt(client: Anthropic, systemPrompt: string, userMessage: string) {
  // Usamos el endpoint de conteo de tokens de Anthropic
  const response = await client.messages.countTokens({
    model: 'claude-opus-4-5',
    system: systemPrompt,
    messages: [{ role: 'user', content: userMessage }]
  });

  return response.input_tokens;
}

// System prompt verboso — versión original
const promptVerboso = `Sos un agente de curación técnica.
Tu objetivo es evaluar recursos técnicos y determinar si son relevantes.
Cuando recibís un recurso:
1. Analizá el título
2. Analizá la descripción
3. Verificá la fuente
4. Considerá la fecha
5. Determiná la relevancia en escala 1-10
Formato de respuesta: JSON con campos score, reason, tags.
Si el score es menor a 6, descartá el recurso.
Si el score es mayor a 8, marcalo como prioritario.
Ejemplo de output esperado:
{ "score": 7, "reason": "Relevante pero no urgente", "tags": ["typescript", "performance"], "priority": false }
No incluyas explicaciones adicionales fuera del JSON.`;
// Resultado: 156 tokens solo el system prompt

// System prompt conciso — versión optimizada
const promptConciso = `Evaluá recursos técnicos. Respondé JSON: {score:1-10, reason:string, tags:string[], priority:bool}. Priority=true si score>8.`;
// Resultado: 32 tokens

// Diferencia: 124 tokens por llamada
// A 1000 llamadas/día: 124,000 tokens de input extra
// Con Claude Opus a $15/MTok: ~$1.86/día, ~$55/mes
// Por un system prompt que podría haber escrito mejor desde el principio
Enter fullscreen mode Exit fullscreen mode

55 dólares por mes. Por un prompt que redacté mal. Esto es exactamente lo que menciono cuando hablo de la escasez real en modelos frontier — el costo no es solo el modelo, es todo lo que lo rodea.


El overhead de tool calls: el número que no esperaba

Acá es donde los números me incomodaron de verdad.

Un tool call en Claude no es gratis. El schema JSON de cada herramienta que definís se tokeniza y se envía en cada llamada, la uses o no. Medí esto en el agente que mencioné en el post sobre SPICE y Claude Code: ese agente tiene acceso a 8 herramientas.

// Comparación: mismo agente con y sin tools definidas

// Configuración CON tools (8 herramientas)
const configConTools = {
  model: 'claude-opus-4-5',
  max_tokens: 1024,
  tools: [
    {
      name: 'leer_archivo',
      description: 'Lee el contenido de un archivo del sistema',
      input_schema: {
        type: 'object',
        properties: {
          path: { type: 'string', description: 'Ruta absoluta del archivo' }
        },
        required: ['path']
      }
    },
    // ... 7 herramientas más con esquemas similares
  ],
  messages: [{ role: 'user', content: mensajeUsuario }]
};
// Tokens de input medidos: 847 (con mensaje simple de 12 tokens)
// Solo los schemas de tools: ~835 tokens de overhead

// Configuración SIN tools — texto plano
const configSinTools = {
  model: 'claude-opus-4-5',
  max_tokens: 1024,
  messages: [
    { 
      role: 'user', 
      content: `${mensajeUsuario}\n\nPara leer archivos, respondé con: READ_FILE:<path>` 
    }
  ]
};
// Tokens de input medidos: 28
// Diferencia: 819 tokens por llamada

// ¿Cuándo vale la pena el overhead de tools?
// Si el agente va a usar herramientas en >60% de las llamadas: tools formales
// Si el agente raramente las usa: parsing de texto plano
// Si necesitás structured output confiable: tools formales siempre
Enter fullscreen mode Exit fullscreen mode

819 tokens de overhead por definir 8 herramientas. En un agente que llama al modelo 500 veces por día, eso es 409,500 tokens de input extra. Todos los días. Sin que el agente haya hecho nada todavía.

La solución no es eliminar las tools. Es ser selectivo sobre cuáles tools exponés en cada contexto. Si en el 70% de los flujos el agente solo necesita 2 de las 8 herramientas, creá un cliente con solo esas 2 para ese flujo. El overhead cae de 835 a ~200 tokens.

Esto aplica también cuando integrás inferencia en el edge — si estás usando Cloudflare como capa de inferencia para tus agentes, multiplicá este overhead por cada worker que instanciás. La latencia y el costo escalan juntos.


El efecto compuesto: contexto acumulado vs resumido

Este es el más traicionero porque es incremental. No lo ves hasta que ya te comió.

Medí una conversación de soporte técnico de 20 turnos con un agente que acumula contexto completo:

// Estrategia 1: Acumulación de contexto completo
// Cada mensaje nuevo se suma a toda la historia

class AgenteContextoCompleto {
  private messages: Array<{role: string, content: string}> = [];

  async responder(userInput: string): Promise<string> {
    this.messages.push({ role: 'user', content: userInput });

    const response = await client.messages.create({
      model: 'claude-opus-4-5',
      max_tokens: 1024,
      messages: this.messages
    });

    const assistantMessage = response.content[0].text;
    this.messages.push({ role: 'assistant', content: assistantMessage });

    // Tokens de input en turno 20: ~18,400 tokens
    // Tokens totales acumulados en 20 turnos: ~127,000 tokens
    return assistantMessage;
  }
}

// Estrategia 2: Ventana deslizante con resumen
class AgenteContextoResumido {
  private summary: string = '';
  private recentMessages: Array<{role: string, content: string}> = [];
  private readonly VENTANA = 4; // últimos 4 turnos

  async responder(userInput: string): Promise<string> {
    this.recentMessages.push({ role: 'user', content: userInput });

    // Si superamos la ventana, resumimos los más viejos
    if (this.recentMessages.length > this.VENTANA * 2) {
      const paraResumir = this.recentMessages.splice(0, 4);
      this.summary = await this.resumir(this.summary, paraResumir);
    }

    const mensajesConContexto = [
      ...(this.summary ? [{ role: 'user', content: `Contexto previo: ${this.summary}` }] : []),
      { role: 'assistant', content: 'Entendido.' },
      ...this.recentMessages
    ];

    const response = await client.messages.create({
      model: 'claude-opus-4-5',
      max_tokens: 1024,
      messages: mensajesConContexto
    });

    // Tokens de input en turno 20: ~2,100 tokens (constante)
    // Tokens totales en 20 turnos: ~42,000 tokens
    // Ahorro vs acumulación completa: ~85,000 tokens

    const assistantMessage = response.content[0].text;
    this.recentMessages.push({ role: 'assistant', content: assistantMessage });
    return assistantMessage;
  }

  private async resumir(summaryActual: string, mensajes: Array<{role: string, content: string}>): Promise<string> {
    // Llamada separada y barata para comprimir contexto
    const response = await client.messages.create({
      model: 'claude-haiku-4-5', // modelo más barato para resumir
      max_tokens: 256,
      messages: [{
        role: 'user',
        content: `Resumí en 2 oraciones: ${summaryActual}\n${JSON.stringify(mensajes)}`
      }]
    });
    return response.content[0].text;
  }
}
Enter fullscreen mode Exit fullscreen mode

En 20 turnos: 127,000 tokens con acumulación completa vs 42,000 con resumen deslizante. Un 67% menos. Y la calidad de las respuestas en las tareas que probé fue indistinguible — el agente resumido no perdió información relevante porque el resumen captura lo que importa.


Errores comunes al medir tokenizer costs en agentes

No medir el overhead de tools en el flujo completo. Muchos miden el costo del output pero ignoran que los schemas de herramientas se cuentan como input en cada llamada. Medí siempre el input total, no solo el mensaje del usuario.

Asumir que más contexto = mejor respuesta. En tareas acotadas (clasificar, extraer, evaluar), el modelo no necesita los últimos 15 turnos de conversación. Probá con ventanas cortas antes de asumir que necesitás todo.

Optimizar para latencia y no para costo (o viceversa). Reducir tokens de input baja el costo pero también puede bajar la latencia. Son objetivos alineados. Si estás pagando por latencia en el edge, esto importa doble.

No separar el costo del resumen del costo del agente principal. Si resumís con Haiku para alimentar a Opus, ese costo de Haiku existe. Es pequeño, pero existe. Contalo.

No versionar los system prompts. Cambié mi prompt de 847 a 180 tokens y no guardé el costo anterior. Ahora registro versión, token count y fecha de cada cambio. Si algo falla silenciosamente después de optimizar, podés hacer rollback con contexto.


FAQ: tokenizer costs en agentes — preguntas reales

¿Cuántos tokens ocupa en promedio un schema de tool en Claude?
Depende de la complejidad del schema. Una herramienta simple con 2 parámetros ocupa entre 80-120 tokens. Una con schema anidado y descripciones detalladas puede llegar a 300-400 tokens. Con 8 herramientas complejas, tranquilamente superás 1500 tokens de overhead solo en tools antes de que el usuario haya escrito una letra.

¿Vale la pena usar modelos más baratos para resumir contexto?
Sí, con una condición: que el resumen sea para consumo del agente, no del usuario. Haiku es excelente para comprimir contexto antes de pasarlo a Opus. El costo de Haiku para resumir es 10-15x más barato que pasar el contexto completo a Opus. Matemáticamente siempre gana si la conversación supera los 6-8 turnos.

¿Cómo sé si mi system prompt es demasiado largo?
Prima facie: si escribiste más de 500 tokens en el system prompt, justificá cada sección. Hacé esta prueba: sacá un párrafo, corrí 20 tareas reales, mirá si el output cambió. Si no cambió, el párrafo no era necesario. Repetí hasta que algo empiece a romperse. Eso te da el mínimo viable real.

¿El prompt caching de Anthropic cambia esta ecuación?
Cambia el costo, no el overhead. Con prompt caching, los tokens que se cachean (generalmente el system prompt) se cobran a 10% después del primer hit. Eso baja el costo de tener un prompt largo, pero no elimina el costo. Y el caching no aplica a los mensajes del usuario ni al contexto de conversación — que es donde el problema de acumulación vive.

¿Cuánto impacta el formato de respuesta (JSON vs texto) en el costo de output?
El JSON estructurado tiende a ser más compacto en tokens que el texto explicativo para el mismo contenido, especialmente si el modelo no agrega prose innecesaria. Pero si forzás JSON sin que el modelo lo genere naturalmente (sin tools formales), el modelo puede agregar markdown alrededor del JSON o texto introductorio que infla el output. Las tool calls formales dan output más predecible y generalmente más compacto.

¿Existe un tamaño óptimo de ventana de contexto para agentes de soporte?
De lo que medí: 4-6 turnos recientes más un resumen de 100-150 tokens captura el 90% de la información relevante para tareas de soporte. Para agentes que hacen razonamiento complejo multi-paso (como el que describí en el post de SPICE), necesitás más — el contexto del paso anterior es a veces input técnico del paso siguiente. No hay número universal, pero 4 turnos es un buen punto de partida para validar antes de ir a ventanas más grandes.


Lo que cambiaría si empezara de nuevo

Haría las mediciones antes de escribir el primer prompt. No después de que el agente esté en producción.

La secuencia correcta es: definí la tarea mínima viable, escribí el prompt mínimo que la resuelve, medí los tokens, evaluá la calidad, expandí solo si la calidad falla. Yo lo hice al revés — escribí primero, medí después, y descubrí que había estado pagando de más por meses.

También separaría los agentes por complejidad de tools mucho antes. No todos los flujos necesitan las 8 herramientas. El overhead de exponer tools que no se usan es puro desperdicio.

La lección incómoda es que la mayoría de los tokenizer costs en agentes no son del modelo — son de las decisiones de diseño que tomaste antes de la primera llamada. Son evitables. Y son acumulativos.

Si estás construyendo agentes y no tenés un número exacto de tokens por decisión arquitectónica, no sabés realmente cuánto te cuesta lo que estás construyendo. Yo tampoco lo sabía. Ahora sí, y no me gusta todo lo que veo — pero al menos lo puedo cambiar.

Top comments (0)