Índice de la sección
El coste de multiplicar agentes
Por qué un sistema multiagente multiplica los tokens, cómo medir el gasto por rol con usage y qué palancas lo reducen sin perder calidad.
Roadmap- Explicar por qué los tokens de entrada crecen con los pasos del bucle y con el número de subagentes.
- Implementar un contador de usage por rol (orquestador, subagente, síntesis) y calcular el coste con precios configurables.
- Comparar con datos un sistema multiagente frente a un agente único sobre las mismas preguntas.
Requiere: Paralelismo: lanzar y recoger · Coste y latencia: medir antes de optimizar
Al terminar esta lección sabrás de dónde sale el gasto de un sistema multiagente, lo medirás llamada a llamada con usage y podrás decidir con números si la versión multiagente compensa frente a un agente único.
La idea
El coste de un modelo se mide en tokens de entrada y de salida. En un chat, cada turno manda el historial y recibe una respuesta. En un agente, cada paso del Bucle agéntico vuelve a mandar todo: el Prompt de sistema, las definiciones de herramientas, la tarea y todos los resultados de herramientas acumulados. La entrada de un agente crece con cada paso, y lo que pagas es la suma de todas esas entradas.
En un sistema multiagente esto se repite en cada subagente y se añaden dos capas: el orquestador, que lee los informes, y la síntesis. Por eso el gasto se multiplica. Anthropic lo dice sin rodeos en How we built our multi-agent research system: su sistema gasta muchos más tokens que una conversación normal y solo tiene sentido en tareas de valor suficiente.
flowchart TD O[Orquestador: plan] --> S1[Sub 1: k pasos] O --> S2[Sub 2: k pasos] O --> S3[Sub 3: k pasos] S1 --> Y[Síntesis: lee 3 informes] S2 --> Y S3 --> Y
Hacer la cuenta antes de medir
Llama P al prefijo fijo de un subagente (sistema, herramientas y tarea), R a los tokens medios que añade cada paso (la respuesta del modelo más el resultado de la herramienta) y k al número de pasos. El paso i manda aproximadamente P + (i − 1)·R tokens. Sumando los k pasos, la entrada de un subagente es del orden de:
entrada ≈ k·P + R·k·(k − 1)/2Dos conclusiones salen de esa fórmula. El prefijo se paga una vez por paso, así que un prompt de sistema largo pesa mucho en agentes con muchos pasos. Y el término de los resultados crece con el cuadrado de los pasos: un subagente que hace el doble de búsquedas puede costar bastante más del doble si cada resultado es largo.
Multiplica por N subagentes y suma el orquestador y la síntesis. Con un ejemplo hipotético (P = 3.000, R = 1.500, k = 6, N = 4), cada subagente lee unos 18.000 + 22.500 = 40.500 tokens de entrada, y los cuatro unos 162.000, antes de contar orquestador y síntesis. Un agente único que resolviera la pregunta en 10 pasos con el mismo P y R leería unos 30.000 + 67.500 = 97.500. Son números inventados para la cuenta: los tuyos salen de medir.
Fíjate en que el agente único tampoco es gratis. Su historial crece sin parar porque acumula los resultados de todas las búsquedas. Esa es la razón por la que, en algunos casos, repartir contextos puede salir más barato o, sobre todo, dar mejor calidad con el mismo gasto. Solo lo sabrás midiendo.
Medir con usage
Cada respuesta trae usage con input_tokens, output_tokens, cache_creation_input_tokens y cache_read_input_tokens. Regístralo por rol en cada llamada.
from collections import defaultdict
from dataclasses import dataclass
# Precios por millón de tokens de tu modelo. Cópialos de la página de precios oficial:
# cambian con el tiempo y dependen del modelo.
PRECIOS = {"entrada": 0.0, "salida": 0.0, "cache_escritura": 0.0, "cache_lectura": 0.0}
@dataclass
class Gasto:
llamadas: int = 0
entrada: int = 0
salida: int = 0
cache_escritura: int = 0
cache_lectura: int = 0
def coste(self) -> float:
return (self.entrada * PRECIOS["entrada"] + self.salida * PRECIOS["salida"]
+ self.cache_escritura * PRECIOS["cache_escritura"]
+ self.cache_lectura * PRECIOS["cache_lectura"]) / 1_000_000
GASTOS: dict[str, Gasto] = defaultdict(Gasto)
def registrar(rol: str, resp) -> None:
u, g = resp.usage, GASTOS[rol]
g.llamadas += 1
g.entrada += u.input_tokens
g.salida += u.output_tokens
g.cache_escritura += u.cache_creation_input_tokens or 0
g.cache_lectura += u.cache_read_input_tokens or 0
def informe() -> None:
total = 0.0
for rol, g in GASTOS.items():
total += g.coste()
print(f"{rol:12} {g.llamadas:3} llamadas in={g.entrada:>8} out={g.salida:>7} "
f"cache_r={g.cache_lectura:>8} ${g.coste():.4f}")
print(f"{'TOTAL':12} ${total:.4f}")Llama a registrar("orquestador", resp), registrar("subagente", resp) o registrar("sintesis", resp) justo después de cada messages.create. Con subagentes en paralelo no hay problema de concurrencia: asyncio ejecuta un solo hilo y las sumas no se pisan.
input_tokens cuenta la entrada que no se leyó de caché ni se escribió en ella. Las otras dos columnas cubren esa parte, y por eso hay que sumar las tres para saber cuánta entrada procesó el modelo en total.
# salida de ejemplo
orquestador 3 llamadas in= 9120 out= 1840 cache_r= 0 $0.0000
subagente 22 llamadas in= 141300 out= 9650 cache_r= 48200 $0.0000
sintesis 1 llamadas in= 6400 out= 910 cache_r= 0 $0.0000
TOTAL $0.0000El coste sale a cero hasta que rellenes PRECIOS. Hazlo con los valores oficiales del modelo que uses.
Para estimar antes de ejecutar, client.messages.count_tokens(model=MODEL, messages=…) devuelve .input_tokens de una petición sin ejecutarla. Sirve para saber cuánto pesa tu prefijo P.
Palancas para reducir el gasto
Ordenadas de más a menos fáciles de aplicar:
- Menos subagentes. Limita el plan a las subtareas que de verdad son independientes. Dos buenas suelen valer más que cinco solapadas.
- Resultados de herramienta más cortos. Si
buscardevuelve páginas enteras, R se dispara. Devuelve fragmentos y URLs. Es la palanca con más efecto según la fórmula. - Menos pasos por subagente. Un criterio de terminado claro en la tarea (Pasar contexto entre agentes) y un
max_pasosbajo. - Prompt caching del prefijo. Todos los subagentes comparten sistema y herramientas. Cachearlo hace que las lecturas posteriores cuesten mucho menos. Lo verás con código en Control de costes y prompt caching.
- Un modelo más rápido y barato en los subagentes. Mide si la calidad aguanta con evals antes de cambiar.
max_tokensy Esfuerzo (effort) ajustados a lo que cada rol necesita. El informe de un subagente no necesita tanto margen de salida como la síntesis.
Errores frecuentes
- Contar solo los tokens de los subagentes y olvidar orquestador y síntesis.
- Mirar solo
input_tokensy no sumar las columnas de caché. - Copiar precios en el código sin fecha ni fuente y olvidar actualizarlos.
- Comparar una sola pregunta. La variación entre ejecuciones es grande: usa varias.
- Optimizar el gasto sin medir antes la calidad.
Ejercicio
EjercicioPistas
Reinicia GASTOS entre preguntas (GASTOS.clear()). Para los segundos, time.perf_counter() antes y después de cada ejecución. Si no tienes evals todavía, puntúa la calidad de 1 a 3 a mano con un criterio escrito antes de mirar las respuestas.
Resumen
- En un agente, cada paso vuelve a enviar todo el historial: la entrada crece con los pasos.
- En multiagente eso se repite por subagente y se suman orquestador y síntesis.
- Registra
usagepor rol en cada llamada y suma entrada, caché y salida. - Las palancas principales: menos subagentes, resultados cortos, menos pasos, caché del prefijo y modelo adecuado por rol.
- La decisión final compara coste y calidad sobre las mismas preguntas.