Cambia tema

Controllo dei costi degli agenti IA: routing dei modelli, budget degli strumenti, cache e retry

Easton editorial illustration: agent rollout and rollback rail
7
Livelli di budget
user, tenant, workflow, task, tool, retry, cache.
4
Azioni di controllo
route, degrade, pause, abort.
3
Tipi di cache
prompt prefix cache, business result cache, tool response cache.
数据来源: Questa checklist di engineering deriva dalla ricerca sui documenti ufficiali della fase 1; prezzi, sconti e disponibilità dei modelli vanno ricontrollati sulle pagine ufficiali prima della pubblicazione.

"OpenAI API Pricing"

Alle 3 di notte, un report Agent in background restituisce una risposta vuota. Lo stato HTTP è 200, ma il body è vuoto. La logica di retry controlla solo lo status code, quindi continua a riprovare. Ogni richiesta invia 500 token in input. Dopo 1.500 retry, sono partiti 750.000 token. La mattina dopo, la fattura chiarisce subito il problema.

La causa non è “abbiamo scelto un modello costoso”. Mancavano tre cose: circuit breaker, controllo del budget e classificazione degli errori. I costi di un Agent tendono a scappare in tre modi:

Retry senza limite. I failure mode non sono classificati, quindi una risposta vuota diventa un errore recuperabile. Manca il circuit breaker, perciò nemmeno 1.500 errori consecutivi fermano l’esecuzione. Ogni retry reinvia tutto il contesto e moltiplica il costo di 2-5x.

Contesto che si gonfia. Un task lungo gira per 6 ore e la cronologia della conversazione cresce fino a 80K tokens. Senza checkpoint, un errore fa ripartire tutto da capo e ogni passaggio viene pagato di nuovo.

Uso eccessivo del modello. Tutti i task usano un frontier model perché non c’è una strategia di routing. Anche una classificazione semplice passa dal percorso più caro e spreca il 70% dei token.

Il controllo dei costi di un Agent non è una singola ottimizzazione. È un design a strati: oggetti di budget, strategia di routing, cache hit, circuit breaker dei retry, log di costo e soglie di alert. Questi sei oggetti di engineering vanno trasformati in tabelle decisionali o check eseguibili.

Oggetti di budget: cosa registrare, dove metterlo e quando interrompere

Il controllo dei costi parte da un oggetto di budget, non da un totale unico. Senza livelli, un picco in fattura non dice quale utente, task o strumento ha bruciato il budget.

Sette livelli di budget

Gli oggetti di budget si dividono dal livello più ampio al più fine:

Livello di budgetOggetto di budgetLimite consigliatoTrigger di alert
Layer 1userLimite giornaliero/mensile per utenteAlert se restante < 20%
Layer 2tenantPool di budget separato per tenantAlert se restante < 30%
Layer 3workflowBudget separato per tipo di workflowAlert se restante < 40%
Layer 4taskBudget separato per tipo di taskAlert se restante < 50%
Layer 5toolBudget per chiamata di strumentoSaltare lo strumento oltre il limite
Layer 6retryLimite di retry + circuit breakerDisattivare lo strumento dopo N errori consecutivi
Layer 7cacheMonitoraggio del cache hit rateAlert se l’hit rate è sotto l’atteso

I limiti esatti dipendono dal modello business e sono configurazione mutevole. La struttura a livelli è più stabile. Il campo di budget residuo va scritto nei log di costo, così alert e circuit breaker possono usarlo.

Campi da registrare per ogni livello

Ogni livello di budget deve registrare questi campi:

Nome campoUsoTipoPerché registrarlo
modelIdentificare il modellostringCapire se il routing dei modelli è ragionevole
inputTokensNumero di token in inputintegerCalcolare il costo dell’input
outputTokensNumero di token in outputintegerIl costo dell’output va tracciato a parte
cachedTokensToken serviti da cacheintegerMisurare il risparmio della cache
costEstimateStima del costo di questa chiamatafloatAccumulare costi in tempo reale
budgetRemainingBudget residuofloatBase per decisioni del circuit breaker

Il punto dell’oggetto di budget è contabilizzare per dimensione, non “salvare solo total_cost”. In multi-tenant, il costo va ripartito per tenantId. In un sistema con molti strumenti, toolName è il modo per aprire la scatola nera.

Logica di circuit breaker

Quando il budget residuo scende sotto una soglia, attiva il circuit breaker:

def check_budget_before_retry(budget_remaining, retry_cost_estimate):
    if budget_remaining < retry_cost_estimate:
        return "skip_retry"  # Saltare il retry perché supererebbe il budget
    if budget_remaining < threshold:  # threshold ad esempio 20%
        return "wait_approval"  # Budget basso, attendere approvazione
    return "continue"

Il circuit breaker controlla il budget prima del retry, non dopo. Prima di ogni retry stima il costo e ferma l’esecuzione se la prossima prova supererebbe il budget. Così eviti il caso “risposta vuota riprovata 1.500 volte”.

L’articolo sul context engineering della stessa serie spiegherà quale contesto entra in un prefix stabile e quale resta variabile di runtime.

Strategia di routing dei modelli: non tutti i task richiedono il modello più caro

Un ticket triage Agent spesso ha questa distribuzione: 70% dei task sono classificazioni semplici, 20% richiedono una bozza di risposta e solo 10% dovrebbe salire a un frontier model prima di inviare un’email al cliente. Una strategia di routing può risparmiare il 40-85% dei costi.

Routing a livello di modello

Il routing per modello segue la complessità del task:

Livello taskTask tipiciLivello modello consigliatoQuotaProfilo di costo
70% - livello SClassificazione, estrazione, filtro, Q&A semplicenano/flash (più economico)70%Output breve, pochi turni, pochi tool call
20% - livello MBozza, riassunto, generazione codice, ragionamento mediomid-tier (prezzo medio)20%Output medio, possibile uso di strumenti
10% - livello LReview, architettura, ragionamento complesso, coordinamento multi-strumentofrontier (più caro)10%Output lungo, molti turni, strumenti frequenti

La strategia ha tre passaggi:

Primo passaggio: classificare il task. Per ogni workflow definisci criteri S/M/L: lunghezza dell’output, numero di tool call, profondità di ragionamento e livello di rischio.

Secondo passaggio: partire dal livello S. Si sale a M o L solo quando compaiono segnali di complessità.

Terzo passaggio: routing a cascata. Se S fallisce, sali a M. Se M fallisce, sali a L. Se L fallisce, passa all’intervento umano. Prima di ogni upgrade controlla il budget residuo; se non basta, salta l’upgrade.

Routing a livello di servizio

Lo stesso modello può essere diviso anche per latency priority. Sconti e finestre di completamento cambiano, quindi verifica i prezzi ufficiali prima della pubblicazione.

Livello servizioSconto costoTempo di completamentoCaso adatto
Realtime APINessuno scontoRisposta immediataChat Agent interattiva, task ad alta priorità
Batch API50% cost discount (da ricontrollare)24-hour turnaround (da ricontrollare)eval batch, classificazione, embedding, elaborazione di repository di contenuti
Flex ProcessingCosto più basso (da ricontrollare)Risposta più lenta, indisponibilità occasionaleTask asincroni a bassa priorità, model evaluations, data enrichment

Checklist per il routing offline:

  • Serve una risposta immediata? Sì -> Realtime API, con routing del modello.
  • Può aspettare 24 ore? Sì -> Batch API.
  • È a bassa priorità e tollera errori occasionali? Sì -> Flex Processing.
  • È lavoro batch come eval, classificazione o embedding? Sì -> Batch API.

Livelli di rischio

I task vanno classificati anche per rischio:

Livello di rischioOperazione tipicaStrategia di routingRamo di budget
Basso rischioClassificazione, estrazione, riassunto internoModello S + percorso automaticoNessuna approvazione, limite più largo
Rischio medioBozza di risposta cliente, suggerimento di modifica codiceModello M + approvazione opzionaleSe supera il budget, richiedere approvazione
Alto rischioInviare email al cliente, addebito, modifica architetturaleModello L + approvazione obbligatoriaAttesa, rifiuto e timeout diventano rami di budget

L’articolo Human-in-the-Loop della stessa serie copre come attesa, rifiuto e timeout di approvazione cambiano i rami di budget.

Vincoli chiave

Il routing ha bisogno di vincoli chiari:

  • Non hardcodare i prezzi: i prezzi cambiano. Registra model + pricingVersion invece di fissare una formula di costo nella logica business.
  • Controlla il budget residuo: prima di salire di livello, verifica budgetRemaining. Se non basta, salta l’upgrade o richiedi approvazione.
  • Classifica gli errori: separa limiti recuperabili del modello da errori non recuperabili di parametro o permesso.

Budget delle chiamate agli strumenti: per-tool budget, timeout e limiti di retry

Le chiamate agli strumenti hanno un doppio costo: schema e API. Ogni chiamata invia schema, argomenti e contesto di parsing della risposta; inoltre l’API esterna può rate-limitare o andare in timeout. Questi costi sono separati dalla chiamata al modello.

Controllo del budget degli strumenti

Ogni strumento deve avere controlli propri:

ControlloConfigurazione consigliataCampo di monitoraggioAzione
Per-tool budgetLimite per chiamatatool_cost_estimateSaltare lo strumento o degradare
Tool timeoutTimeout dell’API esternatool_durationMarcare il timeout come errore recuperabile
Retry limit per toolLimite di retry per strumentotool_retry_countAbbandonare lo strumento, senza loop di retry

Gli strumenti che chiamano API esterne, come ricerca, database o servizi terzi, hanno bisogno di contabilità propria. Altrimenti il tool calling diventa una scatola nera di costo.

Classificazione degli errori degli strumenti

Gli errori degli strumenti si dividono in recuperabili e non recuperabili:

Tipo di erroreErrori tipiciStrategiaImpatto sul costo
Errore recuperabileTimeout di rete, 503 Service Unavailable, 429 Rate LimitRetry automatico con exponential backoff e retry-afterOgni retry invia tutto il contesto
Errore non recuperabile403 Permission Denied, 400 Bad Request, strumento inesistenteNon riprovare; iniettare l’errore perché il modello decidaNessun retry, niente spreco ripetuto

La regola è semplice: si riprovano solo errori temporanei causati da condizioni esterne. Gli errori di configurazione interna non si riprovano.

Circuit breaker

Dopo N errori consecutivi, disattiva lo strumento:

def circuit_breaker_tool(tool_name, consecutive_failures, threshold=5):
    if consecutive_failures >= threshold:
        return "disable_tool"  # Disattivare lo strumento
    return "continue"

Lo stato del circuit breaker va nei log, così puoi spiegare perché uno strumento è stato disattivato. Dopo lo scatto, attendi intervento umano o un controllo di recovery automatico, invece di chiamare di nuovo uno strumento instabile.

Le basi del tool calling sono in Tool Calling. Qui le estendiamo con per-tool budget, timeout e limiti di retry.

Design di Prompt Caching: prefix stabile, variabili e soglia di 1024 token

Prompt Caching ottimizza il costo dei token in input per un prompt prefix stabile. Non è una cache di risultato business. Instrada richieste con lo stesso prompt prefix verso un server che ha elaborato di recente quel prefix, riducendo latenza e costo di input.

Prompt Caching non è cache di risultato

Prompt Caching salva un prompt prefix stabile, non un risultato business. La differenza conta:

  • Prompt Caching: salva un prompt prefix stabile, come system prompt o tool schema. Un hit risparmia token in input, ma l’inferenza viene comunque eseguita.
  • Cache di risultato business: salva un output completo, come risultato di uno strumento o query di database. Un hit risponde direttamente senza chiamare il modello.

Gli obiettivi sono diversi. Prompt Caching riduce il costo dei token in input; la cache business riduce il costo dell’intera chiamata. Possono convivere: prefix stabili su Prompt Caching, risultati frequenti degli strumenti su cache business.

Requisiti strutturali

La chiave è separare prefix stabile e variabili di runtime:

Tipo di contenutoPosizioneProbabilità di cache hitEsempi
Prefix stabile (entra in cache)Inizio del promptAltaSystem prompt, Tool schema, documenti Policy, esempi Few-shot
Variabili di runtime (fuori cache)Più avanti nel promptBassaUser input, File fragments, Runtime state (turno corrente, variabili temporanee)

Passaggi di design:

  1. Metti System prompt, Tool schema e Policy all’inizio: sono stabili tra chiamate e hanno più probabilità di hit.
  2. Metti User input, File fragments e Runtime state dopo: cambiano a ogni chiamata e non devono entrare nel prefix stabile.
  3. Monitora Cache hit rate: registra cachedTokens e token totali in input, poi calcola l’hit rate. Oltre il 40% è sano; sotto il 20%, controlla la struttura del prompt.

Soglia ed effetto

La soglia automatica e l’effetto di Prompt Caching sono fatti mutevoli; ricontrolla la documentazione ufficiale prima della pubblicazione:

  • Soglia: attivazione automatica da 1024 tokens in su (da ricontrollare).
  • Effetto: gli hit possono ridurre costo e latenza (ricontrollare i rapporti esatti).
  • Verifica hit: campo usage.prompt_tokens_details.cached_tokens.

Modelli supportati, soglie e sconti di Prompt Caching possono cambiare. Verificali sulla pagina pricing ufficiale prima di pubblicare. Il principio stabile resta: contenuto statico davanti, contenuto variabile dietro.

Circuit breaker dei retry: idempotenza, checkpoint e budget residuo

I retry sono una delle maggiori fonti di costo fuori controllo. Un report Agent bloccato su uno strumento instabile può reinviare tutto il contesto a ogni errore; dopo 1.500 retry il costo è lontano dal percorso normale.

Controllare il budget prima del retry

Controlla il budget residuo prima di riprovare, non dopo:

def should_retry(error_type, budget_remaining, retry_cost_estimate):
    # Classificazione dell'errore
    if error_type in ["403", "400", "tool_not_exist"]:
        return False  # Errore non recuperabile, non riprovare

    # Controllo del budget
    if budget_remaining < retry_cost_estimate:
        return False  # Fuori budget, non riprovare

    return True  # Retry possibile

Il controllo del budget deve stare prima della logica di retry. Così eviti di spendere il budget giornaliero su una risposta vuota riprovata 1.500 volte.

Idempotenza

Un retry non deve ripetere effetti collaterali come inviare email o addebitare un pagamento:

  • Usa un id di idempotenza, come requestId, per le chiamate agli strumenti. Se l’API esterna riceve lo stesso ID, deve restituire il risultato in cache invece di rieseguire l’operazione.
  • Scrivi l’id di idempotenza nei log di costo per diagnosticare chiamate ripetute.

L’idempotenza serve a far sì che la stessa operazione non consumi due volte. Senza, i retry amplificano sia costo sia effetti collaterali.

Salvataggio dello stato (Checkpoint)

I task lunghi devono recuperare senza rieseguire tutto il workflow:

  • Salva un checkpoint sui nodi importanti, con passaggi completati, stato corrente e sintesi del contesto.
  • Dopo un errore, riprendi dal checkpoint, non dall’inizio.
  • Persisti il checkpoint. Tenerlo solo in memoria non basta.

Il design di checkpoint e thread state è trattato in Architettura Agent con LangGraph.

Strategia di retry

Ogni tipo di errore richiede una strategia diversa:

Tipo di erroreErrore tipicoStrategia di retryImpatto sul costo
Timeout di reteNessuna risposta dopo 10 secondiExponential backoff + retry-after, massimo 3 retryOgni retry invia tutto il contesto
503/429Service Unavailable, Rate LimitAttendere finestra di rate limit + retry-after, massimo 3 retryL’attesa non consuma token, il retry sì
403/400Permission Denied, Bad RequestNon riprovare; iniettare l’errore perché il modello decidaNessun retry, evita costo non valido

La regola: si riprovano solo errori recuperabili. Non mandare richieste non valide al modello ancora e ancora.

Circuit breaker

Dopo N errori consecutivi, ferma i retry e attendi intervento:

def circuit_breaker(consecutive_failures, threshold=5):
    if consecutive_failures >= threshold:
        return "stop_retry"  # Fermare i retry
    return "continue"

La decisione del circuit breaker va nei log per spiegare perché i retry si sono fermati. Poi attendi intervento umano o recupero del budget, invece di richiamare uno strumento o modello instabile.

Log di costo e alert: quali campi e quali soglie

L’osservabilità dei costi è il prerequisito del controllo dei costi. Se i campi di log sono incompleti, non trovi il problema.

OpenTelemetry trace span attributes

Progetta i log di costo su tre livelli di span:

Agent run span (livello superiore):

Nome campoUsoTipoPerché registrarlo
runIdIdentificare una specifica esecuzionestringDistingue run ripetuti dello stesso workflow
tenantIdIdentificare il tenantstringRipartisce costi in sistemi multi-tenant
userIdIdentificare l’utentestringSegue trend di costo per utente
workflowNameIdentificare il workflowstringSegue costi per tipo di workflow
totalCostCosto totale stimatofloatAccumula costi in tempo reale
budgetRemainingBudget residuofloatBase per decisioni del circuit breaker
totalRetriesNumero totale di retryintegerMostra l’amplificazione da retry

Model call span (span figlio):

Nome campoUsoTipoPerché registrarlo
modelIdentificare il modellostringCapire se il routing è corretto
pricingVersionVersione di pricingstringEvita formule di costo hardcodate
inputTokensToken in inputintegerCalcola costo di input
outputTokensToken in outputintegerTraccia costo di output separatamente
cachedTokensToken in cacheintegerCalcola risparmio della cache
costEstimateStima di costo della chiamatafloatAccumula costi in tempo reale
latencyMsLatenza della chiamataintegerAiuta a decidere se Batch/Flex è adatto

Tool call span (span figlio):

Nome campoUsoTipoPerché registrarlo
toolNameIdentificare lo strumentostringLocalizza overhead dei tool call
toolBudgetLimite budget dello strumentofloatBase per circuit breaker
toolTimeoutTimeout dello strumentointegerClassifica errori di timeout
retryCountNumero di retryintegerMisura amplificazione da retry
errorTypeTipo di errorestringSepara recuperabile e non recuperabile

Non registrare solo total_cost. Dividi per dimensione. Senza questi campi, un picco in fattura dice solo “oltre budget”; non dice quale utente, strumento o retry lo ha causato.

Il design completo di log, alert e recovery è in Monitoraggio e recovery degli Agent. Questo articolo aggiunge campi di costo e oggetti di budget.

Soglie di alert

Imposta soglie per dimensione:

Dimensione alertSoglia alertCanaleAzione
Consumo budget globale70%, 90%, 100%Slack/email70% avviso, 90% degradazione, 100% interruzione
Consumo di un user/tenantOltre 3x la mediaSlack/emailControllare chiamate anomale
Tasso di errore di un modello> 5%DashboardControllare routing o stato servizio
Retry di uno strumento> sogliaDashboardControllare stabilità dello strumento
Cache hit rate< valore attesoDashboardControllare struttura del prompt

Le soglie devono stare nella logica di costo, così alert e circuit breaker scattano automaticamente.

Strategia di degradazione

Dopo un alert, la degradazione può seguire questi percorsi:

Percorso di degradazioneMetodoCaso adattoImpatto sul costo
Degradazione del modelloModello grande -> modello piccoloUn modello ha alto tasso di erroreCosto più basso, possibile calo qualità
Degradazione del percorsoRealtime API -> Batch API -> Flex ProcessingBudget globale consumato troppo in frettaPiù latenza, costo minore
Degradazione funzionaleDisattivare strumenti non essenzialiUno strumento ha troppi retryRiduce overhead degli strumenti
Degradazione utenteRate limit, coda, messaggio “riprova più tardi”Consumo anomalo di un utenteEvita che un utente bruci il budget

La degradazione deve vivere nella logica di budget. Quando scatta un alert, il sistema dovrebbe degradare automaticamente, non aspettare intervento manuale.

Prossimi passi

Il controllo dei costi degli Agent dipende anche da monitoraggio, tool calling e context engineering:

  • Pubblicato: Monitoraggio e recovery degli Agent: campi di log, alert e recovery degli errori. Questo articolo aggiunge campi di costo e oggetti di budget.
  • Pubblicato: Architettura Agent con LangGraph: checkpoint, thread state e recovery per task lunghi.
  • Pubblicato: Tool Calling: basi delle chiamate agli strumenti. Questo articolo aggiunge per-tool budget, timeout e limiti di retry.
  • Stessa serie: context engineering: prefix stabili, cache hit e quali contesti stanno nel prefix stabile rispetto alle variabili di runtime.
  • Stessa serie: Human-in-the-Loop: attesa, rifiuto, timeout di approvazione e impatto su costi e retry.

Parti dalla difesa a livello di sessione: imposta un per-session cost limit e termina automaticamente la sessione quando supera il budget. È la prima protezione più rapida contro un task impazzito che brucia il budget del giorno. Poi estendi il design a livelli di budget, routing dei modelli, budget degli strumenti, Prompt Caching, circuit breaker dei retry e log di costo.

Progettare budget di costo e circuit breaker per Agent

Usa oggetti di budget, routing dei modelli, routing del livello di servizio, cache, budget degli strumenti e circuit breaker dei retry per anticipare il controllo dei costi prima di ogni run.

⏱️ Estimated time: 45 min

  1. 1

    Step 1: Elencare tutti i percorsi di costo

    Elenca chiamate ai modelli, chiamate agli strumenti, letture di file, API esterne, processi batch, cache e percorsi di retry dell'Agent.
  2. 2

    Step 2: Definire l'oggetto di budget

    Registra il budget per tenant, user, run, workflow, model, tool, retry, cache e time window.
  3. 3

    Step 3: Impostare la strategia di routing

    Definisci routing dei modelli e routing del livello di servizio per diversi tipi di task: online, batch, flex e queue.
  4. 4

    Step 4: Progettare i cache hit

    Metti il contesto stabile nel prompt prefix, i contenuti variabili dopo, e separa prompt caching, cache di risultato business e cache di risposta degli strumenti.
  5. 5

    Step 5: Limitare strumenti e retry

    Assegna a ogni strumento timeout, max retries, idempotency key, per-tool budget e fallback.
  6. 6

    Step 6: Registrare gli span di costo

    Su ogni run/span registra token, cached token, tool, retry, latency, estimated cost, budget remaining e traceId.
  7. 7

    Step 7: Configurare degradazione e circuit breaker

    Imposta soglie di degradazione, pausa, circuit breaker e alert, poi testale con casi di errore reali.

FAQ

Il costo di un Agent va tracciato per utente, sessione, task o strumento?
Usa più livelli: user, tenant, workflow, task, tool, retry e cache. Ogni livello deve avere budget e circuit breaker propri. Se salvi solo total_cost, non saprai quale utente, strumento o percorso di retry ha causato il picco.
Il routing dei modelli consiste solo nel mettere i task semplici su un modello più piccolo?
No. Serve anche routing del livello di servizio, come Batch/Flex/realtime, e classificazione del rischio. Lo stesso modello può essere diviso per latency priority. Il lavoro offline va bene per Batch API; i task a bassa priorità per Flex Processing.
Che differenza c'è tra Prompt Caching e una normale cache business?
Prompt Caching salva un prompt prefix stabile, come system prompt, tool schema e policy. Non salva il risultato business. Una cache business salva output completi o risposte degli strumenti. Risolvono problemi diversi e possono convivere.
Quante volte conviene riprovare una chiamata di strumento fallita?
Non usare solo un numero fisso. Guarda classe di errore, budget residuo e stato del circuit breaker. Ripeti poche volte gli errori recuperabili; non riprovare 403, 400 o strumenti inesistenti.
Cosa fare se un task Agent lungo sta finendo il budget a metà?
Meglio mettere in pausa, salvare un checkpoint e attendere recupero del budget o approvazione umana. Un errore secco perde progresso; una degradazione cieca può ridurre la qualità.
Quali campi deve registrare un log di costo?
Almeno runId, tenantId, workflow, model, input/output/cached tokens, toolName, retryCount, latency, costEstimate, budgetRemaining, decision e traceId.

15 min di lettura · Pubblicato il: 17 set 2026

Commenti

Accedi con GitHub per lasciare un commento

Easton BlogEaston Blog