Inicio / Artículos / Menos tokens no es más barato: los agentes de código desperdician trabajo, no tokens

Menos tokens no es más barato: los agentes de código desperdician trabajo, no tokens

Comprimir la salida de las herramientas puede encarecer toda una tarea de código. Por qué medir el coste por tarea completada, mantener una vía de recuperación y diseñar herramientas para agentes.

2258 palabras

Desde que los agentes de código despegaron, los desarrolladores se han obsesionado con una cifra: los tokens. ¿Cuántos generó el modelo, cuántos devolvió una herramienta, qué tamaño tiene el contexto, cuántos consumió el agente? El razonamiento parece impecable. Menos tokens deberían significar una factura menor.

El análisis de GitHub sobre el agente de código de Copilot muestra por qué esa suposición es arriesgada. Recortar cada respuesta de una herramienta puede encarecer toda la tarea si el texto recortado contenía algo importante. El agente vuelve a ejecutar comandos, rescata la salida original, gasta turnos extra de razonamiento y arrastra un contexto más grande por todo lo que viene después.

Así que la interacción más barata no es automáticamente la que tiene menos tokens. Lo que de verdad quieres es la tarea de software terminada con el mínimo trabajo desperdiciado, y eso cambia cómo deberías juzgar el rendimiento de un agente.

La trampa de la optimización local

Supongamos que un agente ejecuta un comando de tests:

npm test

Imprime 50.000 tokens. Parece un derroche, así que escribes un wrapper que reduce la salida a 2.000. Sobre el papel es una victoria: 48.000 tokens menos.

Ahora supón que esos 2.000 tokens dejan fuera lo que el agente necesitaba. Responde algo así:

I need more information about the failing test.

Así que vuelve a ejecutar el comando, busca en la salida guardada, abre el archivo de log o prueba un comando más acotado. El flujo pasa a ser este:

Original command
      ↓
Compressed output
      ↓
Missing information
      ↓
Agent searches again
      ↓
Command runs again
      ↓
More context
      ↓
More reasoning

El paso individual se abarató y la tarea se encareció. GitHub se topó con esto al probar formas de recortar la salida de Copilot. En un experimento se usó una herramienta llamada RTK para acortar la salida de la shell, y los agentes reabrían o repetían comandos con frecuencia cada vez que el detalle que faltaba era importante. El resultado fueron más turnos y, de media, más tokens y una finalización más lenta. Visto ahora parece obvio, pero es fácil pasarlo por alto cuando optimizas la cifra equivocada.

Juzga la tarea, no la llamada

Un agente existe para terminar una tarea de software, no para minimizar el coste de una petición a la API. La distancia entre ambos objetivos es mayor de lo que parece. Comparemos dos agentes. El agente A:

Task
↓
8 tool calls
↓
100K tokens
↓
Completed in 4 minutes

y el agente B:

Task
↓
15 tool calls
↓
80K tokens
↓
Completed in 9 minutes

Si solo miras los tokens, gana B. Pero si diriges una organización de ingeniería, la respuesta es más turbia. A terminó antes, probablemente necesitó menos reintentos, quizá usó menos cómputo, quizá produjo un parche mejor y redujo el tiempo de espera de los desarrolladores. Si alguien tuvo que vigilar a B cinco minutos más, el coste real de B sube todavía más.

Por eso GitHub sostiene que el número de tokens por interacción dice poco sobre la eficiencia de un agente. Lo que hay que optimizar es el resultado de la tarea completa.

Un modelo de coste de principio a fin

Los ingenieros con experiencia ya lo saben por otros trabajos. Bajar una consulta a la base de datos de 200 ms a 100 ms suena a una mejora clara. Pero si la nueva consulta hace que otro servicio lance tres peticiones extra, el sistema puede acabar siendo más lento en conjunto. Se optimiza el sistema, no una operación aislada.

Con los agentes rige la misma regla. Un modelo mental útil del coste total:

Total agent cost =
model inference
+ tool execution
+ retries
+ repeated work
+ context growth
+ developer waiting
+ infrastructure

Y un patrón que aparece a menudo:

smaller response
+
missing context
=
more recovery work

Por eso la ingeniería de IA se parece cada vez más a la ingeniería de sistemas.

No toda la salida vale lo mismo

Un hallazgo notable es que la densidad de información de la salida de los comandos varía mucho. Los logs repetitivos de instalación, compilación, tests y progreso pueden estar llenos de ruido. En cambio, la salida parecida a código fuente y los resultados de comandos arbitrarios pueden contener justo lo que el agente necesita. En lugar de una única regla de compresión para todo, GitHub construyó un enfoque selectivo. En concepto funciona así:

Command output
      │
      ▼
┌──────────────────────┐
│ What kind of output? │
└──────────┬───────────┘
           │
     ┌─────┼─────┐
     │     │     │
     ▼     ▼     ▼
 Source  Search  Noise
 output  results logs
     │     │     │
     ▼     ▼     ▼
  Keep   Reorganize Compress
  all     without   selectively
          losing
          content

Eso es mejor que la alternativa burda:

if output.length > X:
    truncate()

La regla tosca optimiza una cifra. La selectiva optimiza la capacidad del agente para seguir trabajando.

Lo que enseña git diff

Imagina un agente que ha editado cinco archivos y ahora ejecuta:

git diff

La salida es larga. Un compresor ingenuo diría que es grande y la reduciría. Pero el diff puede contener exactamente lo que el agente necesita para juzgar si sus cambios son correctos. GitHub cuenta que las primeras versiones de su compresor sí comprimían git diff, y los benchmarks mostraron agentes reabriendo la salida original para recuperar la información. Así que ese filtro se eliminó.

Es una gran lección propia de la IA: no puedes decir que algo es inútil solo porque es grande. Algunas salidas grandes son contexto de mucho valor y algunas diminutas no valen nada. El número de tokens no sabe distinguirlas.

Diseñar tus propias herramientas

Si estás construyendo un agente de código, podrías escribir esto:

const result = await exec(command);

seguido de un límite fijo:

return result.stdout.slice(0, 5000);

Parece razonable, pero supone en silencio que los primeros 5.000 caracteres contienen todo lo que el agente necesita. Un diseño más inteligente clasifica primero la salida. Se empieza igual:

const result = await exec(command);

Luego se ramifica según el tipo de salida:

const outputType = classifyOutput(result);switch (outputType) {
  case "source":
    return result.stdout;  case "search":
    return reorganize(result.stdout);  case "repetitive-log":
    return compress(result.stdout);  default:
    return result.stdout;
}

Incluso eso necesita una salida de emergencia para que el agente pueda recuperar el original:

return {
  summary,
  compressedOutput,
  fullOutputAvailable: true
};

El agente recibe una vista compacta y en realidad no ha desaparecido nada. Para sistemas autónomos es un diseño mucho mejor.

La compresión debe aplazar, no borrar

Comprimir no debería significar borrar información. Debería significar aplazarla hasta que haga falta. Compara los dos enfoques. La mala compresión tiene este aspecto:

Original output
       ↓
Throw away 90%
       ↓
Agent cannot recover it

Una compresión mejor deja abierto el camino de vuelta:

Original output
       ↓
Create useful summary
       ↓
Agent continues
       ↓
Needs more detail?
       ↓
Retrieve original

Se parece más a cómo funciona la caché en el software normal. El agente no lo necesita todo de inmediato, pero no debería perder el acceso a nada importante. El enfoque que GitHub ha puesto en producción ofrece una vía directa de recuperación una vez comprimida la salida.

A veces más contexto sale más barato

Suena al revés. Los desarrolladores llevan años reduciendo el contexto. Pero más contexto puede evitar más trabajo. Supón que el agente ve un fallo resumido:

Test failed:
Expected 401
Received 500

La salida completa quizá también habría mostrado esto:

Database connection refused
JWT middleware initialized correctly
Request reached /api/auth/login
PostgreSQL timeout after 5 seconds

La versión corta le dice al agente que algo ha fallado. La completa le dice que la lógica de autenticación probablemente no tiene la culpa y que el problema es la conexión a la base de datos. La segunda cuesta más tokens y puede ahorrar cinco llamadas a herramientas. El contexto tiene un coste, y la falta de contexto también. El reto de ingeniería es equilibrar ambos.

Por qué los agentes parecen dar vueltas

Seguramente has visto a un agente hacer algo así:

Run command
↓
Read partial output
↓
Run another command
↓
Search same file
↓
Run original command again
↓
Read more output
↓
Change code
↓
Run test
↓
Go back to original command

Parece confusión, y a veces lo es. Pero otras veces la infraestructura simplemente no le dio al modelo información suficiente, y el agente está compensando una interfaz incompleta. Si un agente pide una y otra vez lo mismo, puede que el fallo esté en el diseño de las herramientas y no en el modelo.

Diseñar herramientas es hacer UX para modelos

Los desarrolladores suelen juzgar las APIs por entradas, salidas, latencia, errores y autenticación. Las herramientas para IA necesitan una pregunta más: ¿cómo afecta esta salida a la siguiente decisión del modelo? Toma dos respuestas. La API A:

{
  "status": "failed"
}

y la API B:

{
  "status": "failed",
  "error": "PostgreSQL connection timeout",
  "service": "auth-api",
  "retryable": true,
  "attempt": 2,
  "duration_ms": 5040
}

B contiene más, pero puede reducir el coste total del sistema, porque el agente puede decidir bien a la primera. El objetivo no es el JSON más pequeño posible. Es la información que permite al agente tomar la siguiente decisión correcta.

Afinar todo el bucle

GitHub no lo trata como un único problema de compresión. Su artículo enumera varios cambios en el harness: conservar el contexto útil y recortar repeticiones, quitar el formato que no ayuda a la tarea, acortar instrucciones sin cambiar el comportamiento y evitar pasos de recuperación innecesarios en el trabajo en segundo plano. Cada cambio se evaluó offline con benchmarks de programación agéntica y luego se validó en experimentos online controlados antes de lanzarlo.

Eso es ingeniería de rendimiento para agentes. La pregunta pasa de cómo hacer más corta una respuesta a cómo ayudar al agente a terminar con menos trabajo desperdiciado, y es una pregunta mucho mejor.

Observabilidad para agentes

Esto cambia lo que mides en producción. En servicios normales vigilarías:

Latency
Error rate
CPU
Memory
Throughput

En los agentes, añade más:

Task completion rate
Tool-call count
Retry rate
Repeated-command rate
Context growth
Model escalation rate
Time to completion
Cost per completed task
Human intervention rate

La mayoría son métricas de flujo de trabajo, no de tokens. Los tokens siguen importando, pero alimentan la economía en lugar de definir la eficiencia.

Coste por tarea completada con éxito

El cambio más sencillo posible es dejar de medir esto:

cost per request

y medir en su lugar esto:

cost per successfully completed task

No son equivalentes. Piensa en un agente con estas cifras:

Agent A
$0.20/task
70% success rate

frente a este otro:

Agent B
$0.35/task
95% success rate

La petición más barata no es necesariamente el sistema más barato. Normalízalo:

Effective cost
= inference cost / successful tasks

Para A:

$0.20 / 0.70
≈ $0.286

Para B:

$0.35 / 0.95
≈ $0.368

Con esta métrica sencilla, A sigue ganando. Pero si A necesita mucha más supervisión por parte de los desarrolladores, las cuentas vuelven a cambiar, y por eso los equipos acaban necesitando una definición más amplia del coste de una tarea.

La misma idea sirve para elegir modelos

Esto conecta con el paso hacia el enrutamiento de modelos. La preview de investigación HydraFusion de GitHub ya trata los flujos de programación como un problema de optimización y elige para cada tarea entre un solo modelo, escalar a otros más potentes o un segundo modelo que actúa como crítico independiente. Según se informa, las pruebas offline en condiciones controladas mostraron grandes ahorros estimados, con una calidad en algunos benchmarks igual o superior a la referencia de Opus 5 que usaron.

Júntalo con la lección sobre la salida. Un agente inteligente no se limita a preguntar qué modelo es el más barato. Pregunta qué flujo de trabajo termina esta tarea con el menor desperdicio. Ese flujo podría combinar:

Cheap model
+
Good context
+
Efficient tools
+
Verification

y superar a este:

Expensive model
+
Poor context
+
Repeated tool calls

La inteligencia ya no vive solo en el modelo. Está repartida por todo el sistema.

Si construyes productos de IA

Es tentador optimizar primero las cifras evidentes: menos consumo de tokens, prompts más pequeños, salidas más cortas, modelos más baratos. No ajustes solo eso. Instrumenta todo el flujo de trabajo:

User request
    ↓
Model inference
    ↓
Tool call
    ↓
Tool response
    ↓
Model reasoning
    ↓
Another tool call
    ↓
Verification
    ↓
Final result

Mide cada etapa y luego pregúntate dónde hace el agente trabajo innecesario. Quizá la herramienta de base de datos devuelve muy poco contexto, o la de búsqueda devuelve demasiado material irrelevante. Quizá el agente reintenta sin necesidad, o tu prompt le obliga a planificar de forma redundante. Quizá un modelo más potente lo resolvería en la mitad de turnos, o uno más barato basta para un primer intento. Son problemas de ingeniería de software.

El futuro no son menos tokens

Es tentador reducir todo el problema del coste a esto:

tokens ↓
cost ↓

La relación real se parece más a esto:

Useful context
      ↓
Better decisions
      ↓
Fewer retries
      ↓
Fewer unnecessary tool calls
      ↓
Shorter task duration
      ↓
Lower total cost

A veces el camino hacia un coste menor empieza por darle al modelo más información. Esa es la parte contraintuitiva, y por eso la ingeniería de IA se está convirtiendo en una disciplina de sistemas y no en un ejercicio de escribir prompts.

Mide el trabajo terminado

Cuando evalúes un agente, no preguntes solo cuántos tokens usó. Pregunta cuánto software útil produjo y cuánto trabajo desperdició por el camino. Eso implica medir corrección, latencia, llamadas a herramientas, reintentos, tamaño del contexto, coste de inferencia, intervención humana y finalización con éxito.

El sistema de código ganador no será necesariamente el que emita menos tokens. Lo esperable es que gane la configuración que convierta cada token, cada llamada a herramienta y cada elección de modelo en progreso real. El trabajo reciente de ingeniería de GitHub marca la dirección: optimizar la tarea completa, conservar la información que el agente necesita y recortar trabajo solo cuando sabes que no ayuda. No se trata de que los agentes hagan menos. Se trata de que desperdicien menos.