On-demand vs provisioned throughput, batch inference, scelta del modello e token caching — con numeri alla mano.
TL;DR — Cinque strategie che, combinate, portano a un risparmio del 60-80% su Bedrock:
- Batch inference per workloads asincroni → sconto del 50%, nessun impatto sulla qualità
- Prompt caching per contesti ricorrenti → 90% in meno sui token di input messi in cache
- Model routing (modelli economici per task semplici) → riduzione dei costi del 40-70%
- Benchmarking + LLM-as-a-judge per verificare che i modelli più economici siano sufficientemente validi
- Observability (OTel + DoiT GenAI Intelligence) per intercettare le derive e consolidare i risparmi nel tempo
Con questo playbook abbiamo portato un cliente da 40K $/mese a 18K $. I dettagli più sotto.
Guido il team di ingegneria APAC di DoiT. Lo scorso trimestre, un cliente del settore dei servizi finanziari mi ha chiesto di rivedere la sua spesa su Bedrock. Usava Claude Sonnet per qualunque cosa — classificazione dei ticket, estrazione documentale, chat verso il cliente — e la fattura mensile era silenziosamente arrivata a superare i 40K $. Due settimane dopo, era scesa a 18K $ senza alcun calo nella qualità dell'output.
Questo è quel playbook. Se è responsabile dei costi di Bedrock per un team di engineering o data, queste sono le leve che incidono davvero sulla fattura.
Gli esempi di clienti citati in questo articolo sono casi compositi basati su pattern ricorrenti in più progetti, non singoli case study.
Capire i due modelli di pricing
Bedrock prevede due modelli di pricing, e ho visto errori costosi in entrambe le direzioni. (Per un'analisi dettagliata del funzionamento del pricing di Bedrock — inclusi i costi di fine-tuning, la stima dei token e le strategie di tagging — veda la guida CloudOps al pricing di Bedrock di Josh Palmer. Questo articolo si concentra sulle decisioni ingegneristiche che riducono la fattura.)
Pricing on-demand
Si paga per token, con prezzi distinti per input e output. Nessun impegno, nessun minimo.
È la scelta giusta quando l'utilizzo è discontinuo, quando si è ancora in fase di sperimentazione o quando la spesa mensile resta sotto il punto di crossover (ne parliamo più sotto).
Il punto su cui molti inciampano: i token di output costano in genere 3-5 volte più dei token di input. Quel cliente del settore finanziario di cui parlavo? Stimava i costi basandosi solo sul prezzo dei token di input e sottostimava la fattura reale di quasi 3 volte. Un task che consuma 1.000 token di input ma ne genera 2.000 di output è dominato dal costo dell'output. Modelli sempre entrambi i lati.
Provisioned throughput
Si acquistano model unit a ore (o con commitments di 1 o 6 mesi). Una model unit è la porzione di capacità riservata di Bedrock — la pensi come "una corsia in autostrada" che si paga a ore, che la si usi o no.
È la scelta giusta quando si hanno workloads sostenuti e prevedibili, quando l'utilizzo supera costantemente la soglia di crossover e quando serve una latenza garantita.
L'anno scorso ho lavorato con un'azienda media che aveva un provisioned throughput in funzione al 15% di utilizzo. L'aveva configurato durante un test di carico, si era dimenticata di tornare indietro e aveva bruciato denaro per tre mesi prima che qualcuno se ne accorgesse. Passare a on-demand è stata una modifica di una sola riga di config che ha generato risparmi nell'ordine delle migliaia di dollari nell'immediato. Provisioned throughput con basso utilizzo è in assoluto l'errore più costoso su Bedrock.
Trovare il punto di crossover
Monthly on-demand cost = (input_tokens × input_price) + (output_tokens × output_price)Monthly provisioned cost = model_units × hourly_rate × 730 hoursPer la maggior parte dei modelli, il provisioned diventa più conveniente attorno al 60-70% di utilizzo sostenuto di una model unit. La parola chiave è "sostenuto" — non guardi al picco. Un traffico che resta intorno al 70% per tutta la giornata con piccole oscillazioni è un buon candidato; un traffico che resta in idle al 10% e schizza al 100% per cinque minuti ogni ora non lo è.
Batch inference: lo sconto del 50% che quasi nessuno sfrutta
È probabilmente l'argomento che mi piace di più affrontare con i clienti, perché la reazione è sempre la stessa: "Aspetta, possiamo davvero... pagare la metà?"
Sì. Bedrock prezza i batch token a circa il 50% delle tariffe on-demand sui modelli supportati. Stessi modelli, stessa qualità, metà del prezzo. (Al momento in cui scriviamo — controlli la pagina del pricing prima di costruirci sopra una roadmap.) Il compromesso è uno SLA di 24 ore senza streaming: i job vanno in coda e si completano in modo asincrono.
È candidato qualunque workload che non richieda una risposta in tempo reale. Categorizzazione dei ticket di supporto, processing di corpus documentali per RAG, generazione di descrizioni prodotto, esecuzione di suite di valutazione, estrazione di dati strutturati da documenti non strutturati. Stimerei che la maggior parte dei team abbia il 30-40% del proprio workload Bedrock spostabile in batch senza alcun impatto utente.
Ecco un esempio concreto. Prenda 10.000 richieste con una media di 500 token di input e 200 token di output ciascuna, su Claude Sonnet (pricing on-demand in ap-southeast-2):
| Modalità | Costo input | Costo output | Totale |
|---|---|---|---|
| On-demand | $15.00 | $37.50 | $52.50 |
| Batch | $7.50 | $18.75 | $26.25 |
26,25 $ risparmiati su una singola esecuzione batch. Pipeline giornaliere portano il risparmio a migliaia di dollari al mese. E l'implementazione è semplicemente file JSONL su S3 — è un cambio di plumbing, non di architettura.
La scelta del modello come strategia di costo
Scegliere il modello giusto è una decisione di costo con una varianza di 10-60 volte. La maggior parte dei team adotta di default qualcosa di più costoso del necessario, perché lo ha scelto in fase di prototipazione e non è più tornata sulla scelta.
L'architettura a tier
Le implementazioni Bedrock più cost-effective che ho visto utilizzano i tier:
- Tier 1 (Haiku, Mistral 7B, Llama 3 8B) — classificazione, routing, estrazione, Q&A semplice. Frazioni di centesimo per richiesta. Dovrebbe coprire il 60-80% del traffico.
- Tier 2 (Sonnet, Mistral Large, Llama 3 70B) — ragionamento complesso, generazione sfumata. 5-10 volte più economico del top tier.
- Tier 3 (Opus, Claude 3.5 Sonnet) — solo i task più difficili. Pricing premium, riservato a ciò che lo richiede davvero.
Il pattern del router
Bedrock offre una soluzione integrata solo per il routing all'interno della stessa famiglia. Intelligent Prompt Routing mette a disposizione un singolo endpoint serverless che instrada le richieste tra modelli della stessa famiglia in base alla complessità del prompt. Si specifica l'ARN di una famiglia di modelli (ad esempio Anthropic Claude), e Bedrock decide se ogni richiesta va a Haiku o a Sonnet. AWS dichiara fino al 30% di riduzione dei costi — da quanto ho visto sui clienti, è una stima ragionevole. Zero codice custom: basta sostituire l'ID del modello con l'ARN del prompt router.
Per il routing cross-family (Haiku per la classificazione, Mistral per l'estrazione, Sonnet per il ragionamento complesso), bisogna costruirsi qualcosa in casa. E a essere onesti, è quello che fa la maggior parte dei team in produzione. Non esiste un framework off-the-shelf abbastanza maturo da poterlo consigliare senza riserve.
Tre pattern che funzionano, in ordine indicativo di maturità:
Classificazione rule-based è il punto di partenza per molti team, e per molti anche il punto di arrivo. Si scrivono 5-10 regole su segnali strutturali — keyword del tipo di task, lunghezza dell'input, formato di output atteso, profondità della conversazione. Niente ML, niente dipendenze, deployabile in un giorno. Gestisce correttamente il 70-80% delle decisioni di routing. Sono solo poche centinaia di righe di logica condizionale.
Cascading basato sulla confidenza è il pattern con il ROI più alto che mi sia capitato di vedere. Ogni richiesta va prima al modello più economico. Si verifica la risposta cercando linguaggio evasivo, output malformato o campi richiesti mancanti. In caso di esito negativo, si scala al tier successivo. Si aspetti la latenza extra di una chiamata aggiuntiva sul ~5-15% delle richieste escalate. Un team con cui ho lavorato — una piattaforma e-commerce che processava query sui prodotti — è passato da 38K $/mese a 15K $/mese in questo modo. Il loro tasso di escalation era solo dell'8%. Non serve che il classificatore sia perfetto: deve essere corretto abbastanza spesso da far gestire le eccezioni dall'escalation. Se il tasso di escalation supera il 25-30%, sistemi il classificatore.
Regole ibride + classificatore ML è lo step di maturazione successivo. Quando ha qualche settimana di traffico in produzione con outcome etichettati, addestra un piccolo classificatore (DistilBERT o regressione logistica su TF-IDF) che aggiunge meno di 5 ms di latenza. Il classificatore in sé dovrebbe aggiungere millisecondi a singola cifra; il vero costo è la disciplina ingegneristica di etichettare i dati e riaddestrare periodicamente. I team che adottano questo approccio in genere migliorano l'accuratezza del routing dal ~78% al ~91%.
Ho guardato attentamente i framework esistenti. RouteLLM del team LMSys ha basi di ricerca solide ma è di fatto un router a due modelli addestrato su dati di chat generici — per workloads Bedrock domain-specific andrebbe riaddestrato. LiteLLM è eccellente sul piano infrastrutturale (API unificata, fallback, retry) ma il suo routing è di load balancing, non scelta del modello basata sulla qualità. Nessuno dei due è una soluzione drop-in per il problema cross-family.
Inizi da Intelligent Prompt Routing. Quando avrà evidenze che il routing cross-family farebbe risparmiare cifre significative, costruisca un classificatore rule-based. È prevedibile, debuggabile, e i team con cui lavoro che hanno seguito questa strada riportano costantemente riduzioni di costo del 40-70%.
Benchmark di qualità del modello vs costo
Non dia per scontato di aver bisogno del modello più costoso. Esegua i suoi task reali su più modelli e misuri l'accuratezza sul suo specifico use case, il costo per task (non per token) e la latenza.
Abbiamo fatto questo esercizio con il cliente del settore finanziario. Il task di classificazione dei ticket ha ottenuto il 94% di accuratezza su Haiku contro il 97% su Sonnet — a 1/15 del costo. Quel gap del 3% non era rilevante per il loro caso d'uso. I numeri saranno diversi per lei, ma il pattern è coerente: faccia benchmark prima di impegnarsi.
Automatizzare la valutazione della qualità con LLM-as-a-judge
Per classificazione o estrazione la qualità si può validare in modo programmatico, ma per la generazione open-ended — riassunti, spiegazioni, risposte ai clienti — la valutazione richiedeva tradizionalmente revisori umani. Non è scalabile.
Bedrock offre una risposta integrata: la valutazione del modello LLM-as-a-judge. Lei fornisce un dataset di prompt (opzionalmente con risposte ground truth), sceglie un modello valutatore, e Bedrock fa passare gli output del modello candidato attraverso il giudice su metriche come correttezza, completezza, utilità, coerenza, rilevanza e sicurezza. Viene eseguito come job gestito: riceve in output punteggi per prompt e aggregati, salvati su S3.
L'obiettivo è dimostrare che un modello che costa 5-15 volte meno per token sia "abbastanza buono" prima di spostarci traffico reale. Prepari un file JSONL con i suoi prompt rappresentativi, esegua lo stesso job di valutazione su Haiku, Sonnet e qualunque altro modello stia considerando, e confronti i punteggi affiancati. AWS ha pubblicato un walkthrough con esempi di codice e c'è anche un Jupyter notebook complementare su GitHub.
Alcune cose che ho imparato usandolo con i clienti.
Usi lo stesso modello valutatore per tutti i confronti — se giudica l'output di Haiku con un modello e quello di Sonnet con un altro, sta misurando differenze fra valutatori, non fra modelli.
Includa i suoi prompt di produzione reali, non benchmark generici. MT-Bench va bene per un sanity check, ma i suoi prompt di classificazione dei ticket si comporteranno in modo diverso dal question-answering accademico.
La valutazione stessa ha un costo (il modello giudice processa ogni output), quindi inizi con 200-500 prompt rappresentativi anziché con l'intero dataset. È in genere abbastanza per capire se il modello economico è chiaramente peggio, chiaramente adeguato, o "da approfondire".
La ground truth è opzionale ma preziosa: per i task in cui dispone di output noti come corretti, le metriche di fedeltà e correttezza diventano molto più significative.
benchmark_bedrock.py cattura costo e latenza; LLM-as-a-judge valuta la qualità. Esegua entrambi e avrà il quadro completo costo-vs-qualità senza revisione manuale.
Prompt caching: 90% di risparmio sui contesti ricorrenti
Mi sorprende quanto pochi team abbiano questa funzionalità attivata. I token di input messi in cache vengono fatturati con uno sconto del 90% rispetto al pricing standard.
Quando invia una richiesta con caching abilitato, Bedrock memorizza il prefisso del prompt. Le richieste successive che condividono quel prefisso colpiscono la cache. Gli hit di cache costano circa il 10% della tariffa normale. Le scritture in cache (prima richiesta) costano leggermente di più, quindi il risparmio si concretizza solo se riutilizza lo stesso prefisso più volte — ma se ha un system prompt o esempi few-shot, il payback è immediato.
Dove dà il meglio: system prompt oltre i 1.500 token, esempi few-shot statici, contesto documentale condiviso in applicazioni RAG, cronologia di conversazioni multi-turn.
I numeri sono impietosi. Un system prompt di 2.000 token con 10.000 richieste/giorno su Claude Sonnet:
| Scenario | Costo giornaliero (porzione system prompt) |
|---|---|
| Senza caching | 2.000 × 10.000 × $0.003/1K = $60.00 |
| Con caching (99% hit rate) | ~$7.00 |
53 $/giorno. Oltre 1.500 $/mese. Solo sul system prompt. Ho mostrato questo calcolo a un cliente il mese scorso e ha attivato il caching prima che la call finisse.
Attenzioni da tenere a mente:
- La lunghezza minima del prefisso cacheable varia da modello a modello (in genere 1.024-2.048 token)
- Matching esatto del prefisso: spazi e ordinamento contano
- TTL / scadenza dopo inattività (la cache si raffredda se il traffico cala)
- Non tutti i modelli supportano ancora il caching: controlli la documentazione aggiornata
Costruire un framework di benchmarking
Le sue decisioni di ottimizzazione dovrebbero essere guidate dai dati dei suoi workloads reali. Ecco cosa raccomanda il mio team.
Per ogni modello e configurazione testati, registri: costo per task, conteggi di token input/output, latenza (tempo al primo token e totale), e un punteggio di qualità specifico per il task.
Il processo: scelga 3-5 task che rappresentano il mix di workload reale, prepari 100-500 esempi di test per task con output noti come corretti, esegua ogni task su ciascun modello candidato, calcoli il costo per task (non per token — i modelli tokenizzano in modo diverso), e tracci costo vs qualità per individuare il "ginocchio" della curva. Anche un semplice scatter plot è sufficiente: sta cercando "stessa qualità, molto più economico" oppure "qualità leggermente peggiore, drasticamente più economico".
Ho messo insieme uno script Python (benchmark_bedrock.py) che automatizza tutto questo: esegue prompt su più modelli Bedrock, registra conteggi di token e latenza, produce CSV, stampa statistiche di sintesi. Lo forki, lo adatti ai suoi workloads.
Nell'interpretare i risultati, cerchi modelli in cui la qualità raggiunge un plateau (Haiku al 93% vs Sonnet al 95% — quel 2% vale 10 volte tanto?), outlier di latenza, differenze di efficienza dei token (un modello più economico per token ma 2 volte più verboso non è davvero più economico) e candidati per il batch.
Visibilità unificata sui costi GenAI con DoiT GenAI Intelligence
La maggior parte dei team con cui lavoro non usa solo Bedrock. Ha OpenAI per alcuni workloads, Anthropic in diretta per altri, magari Vertex AI in un progetto GCP. I dati di costo finiscono dispersi su quattro console con dimensioni incompatibili.
Abbiamo costruito GenAI Intelligence proprio per risolvere questo. Consolida i dati di costo e utilizzo AI da Bedrock, Vertex AI, Azure ML, Databricks, Anthropic e OpenAI in un'unica vista normalizzata. La sua spesa Bedrock appare insieme a tutto il resto. Nessun ETL custom.
Per Bedrock, il valore sta nelle label normalizzate. Model / Model Family traccia il costo per modello tra provider. Usage Type scompone la spesa per token di input vs output — la suddivisione che la maggior parte dei team sottostima. Cached mostra se le operazioni hanno usato token in cache, così può misurare il ROI del caching dai dati di fatturazione. GenAI Spend etichetta tutti i costi di AI generativa indipendentemente dal provider, per il tracking del budget complessivo.
Può porre domande come "Quanto ci hanno fatto risparmiare i token in cache su Claude Sonnet il mese scorso?" o "Qual è la suddivisione della spesa tra Haiku e Sonnet per la classificazione dei ticket?" — su tutti i provider, in un unico posto.
Il dashboard include report preimpostati: spesa per provider (mensile), costo per famiglia di modelli (giornaliero per gli ultimi 14 giorni — intercetta i picchi rapidamente), suddivisione dei token per modello (30 giorni), e utilizzo orario dei token per provider (ultimi 2 giorni — utile per correlare con i deployment). Dato che i dati GenAI confluiscono nel nostro motore Cloud Analytics, ottiene anche budget, allocazioni, anomaly detection e forecasting sulla spesa AI.
Ipotizziamo che stia usando Haiku per la classificazione e Sonnet per il ragionamento, con caching su entrambi:
| Modello | Cached | Costo mensile | Utilizzo token |
|---|---|---|---|
| Claude Haiku | true | $45 | 18M token |
| Claude Haiku | false | $320 | 12M token |
| Claude Sonnet | true | $180 | 4M token |
| Claude Sonnet | false | $2,100 | 6M token |
Il cache hit rate di Haiku è solido (60% dei token in cache). Quello di Sonnet è scarso (40%). Sistemare il caching di Sonnet potrebbe far risparmiare centinaia di dollari al mese — e l'ha individuato senza scrivere una singola query CloudWatch.
Per iniziare: connetta il suo account AWS a DoiT, vada su Dashboards → GenAI Intelligence, e i dati Bedrock si popolano automaticamente. Nessuna instrumentazione necessaria sul lato Bedrock.
Observability con OpenTelemetry
Il benchmarking le dà uno snapshot puntuale. I workloads in produzione derivano nel tempo: i prompt cambiano, i pattern di traffico si spostano, escono nuovi modelli. GenAI Intelligence copre il lato fatturazione della visibilità continua. Per l'instrumentazione a livello applicativo — latenza, decisioni di routing, hit di cache per richiesta — OpenTelemetry è la mia raccomandazione.
Le convenzioni semantiche GenAI fanno sì che qualunque backend OTel-compatible (Grafana, Datadog, Honeycomb) riconosca i suoi span. Avvolga ogni invocazione Bedrock in uno span con questi attributi:
gen_ai.system—"aws.bedrock"gen_ai.request.model— l'ID del modellogen_ai.usage.input_tokens/output_tokens— dai metadati della responsegen_ai.usage.cost— calcolato dalla sua tabella di pricingtask.type— il nome del task a livello applicativo
Cosa ottiene: trend di costo per task nel tempo (intercetta la deriva dei prompt prima che colpisca la fattura), validazione del routing dei modelli (in un caso il Tier 1 di un cliente gestiva il 40% del traffico invece del 70% atteso — un bug che costava 800 $/mese in più), e monitoraggio del cache hit rate (intercetta i cali in poche ore, non a fine ciclo di fatturazione).
Ottiene anche i dati per correlare con ModelUnitUtilization di CloudWatch nelle decisioni sul provisioned throughput.
Instrumentazione minima:
from opentelemetry import trace
tracer = trace.get_tracer("bedrock-client")
def invoke_with_telemetry(client, model_id, prompt, max_tokens, task_type="unknown"): with tracer.start_as_current_span("bedrock.invoke") as span: span.set_attribute("gen_ai.system", "aws.bedrock") span.set_attribute("gen_ai.request.model", model_id) span.set_attribute("gen_ai.request.max_tokens", max_tokens) span.set_attribute("task.type", task_type)
resp = client.invoke_model(modelId=model_id, body=body, contentType="application/json") data = json.loads(resp["body"].read())
in_tok = data["usage"]["input_tokens"] out_tok = data["usage"]["output_tokens"] span.set_attribute("gen_ai.usage.input_tokens", in_tok) span.set_attribute("gen_ai.usage.output_tokens", out_tok)
return dataDa lì, costruisca quattro pannelli — costo giornaliero per modello, costo per task per modello, cache hit rate, latenza p50/p95 — e li riveda settimanalmente.
Errori più frequenti
Gli errori che vedo più spesso, in ordine indicativo di quanti soldi sprecano:
Monitori l'utilizzo del provisioned throughput su base settimanale. Sotto il 50% sostenuto? Passi a on-demand. Quell'azienda media stava sprecando più in capacità provisioned in idle che in inferenza reale.
Modelli e metta un cap ai token di output. I token di output costano 3-5 volte più di quelli di input. Un team ha tagliato del 40% i costi di output semplicemente aggiungendo "rispondi in JSON, senza spiegazioni" ai propri prompt di estrazione.
Metta in batch tutto ciò che non richiede latenza sotto le 24 ore. Sconto del 50%. Nessun compromesso sulla qualità.
Non lasci che Sonnet sia il default. Usarlo per tutto perché ha funzionato in fase di prototipazione è la forma di overspend più comune che vedo.
Attivi il caching ovunque riutilizzi i prompt. System prompt statico o esempi few-shot? Pochi minuti di lavoro, risparmio immediato.
Misuri per task, non per token. Un modello più economico che produce output più verbosi può costare di più per task. Faccia benchmark a livello di task.
Mettendo tutto insieme
Il percorso di ottimizzazione che faccio fare alla maggior parte dei team:
- Batch inference — sposti i workloads asincroni. 50% di risparmio immediato, zero impatto sulla qualità.
- Prompt caching — lo abiliti per i contesti ricorrenti. Pochi minuti di lavoro.
- Faccia benchmark di alternative — probabilmente scoprirà che il 60-80% del workload gira benissimo su Tier 1.
- Model routing — costruisca un classificatore. Inizi con le regole.
- Provisioned throughput — solo dopo che i punti precedenti sono stabili e l'utilizzo è prevedibile.
Questi effetti si sommano. Il cliente del settore finanziario citato all'inizio? Ha eseguito i passi 1-4 in sei settimane. La batch inference ha portato un 22% di risparmio. Il caching un 18%. Il model routing un altro 25%. Totale: da 40K $ a 18K $.
Non è però un progetto una tantum. Il panorama di Bedrock si muove di continuo. Quando è uscito Claude 3.5 Haiku, era nettamente migliore di Claude 3 Haiku a un prezzo praticamente identico — i team che avevano gli ID dei modelli hardcoded hanno mancato l'upgrade per mesi. AWS ha rivisto il pricing di Bedrock più volte senza grande clamore. E anche il suo workload deriva: i prompt si allungano, vengono aggiunti nuovi tipi di task, le proporzioni di traffico cambiano.
Cosa funziona: una review trimestrale leggera. Riesegua i benchmark sui nuovi modelli (richiede un pomeriggio con lo script di benchmarking). Usi LLM-as-a-judge per verificare che la qualità non sia regredita. Controlli i dashboard OTel per la deriva del routing — il Tier 1 sta ancora gestendo la percentuale di traffico che si aspetta? Il cache hit rate è cambiato?
Se è su DoiT, GenAI Intelligence le mostrerà i trend di costo per modello che rendono evidente quando qualcosa si è mosso. L'intera review prende mezza giornata, una volta che l'ha fatta la prima volta.
L'azienda media che ho menzionato prima ha scoperto durante una di queste review che una modifica al prompt aveva silenziosamente abbassato il loro cache hit rate dal 94% al 61% — 2K $/mese in più che nessuno aveva notato.
Se oggi è su Bedrock e vuole un secondo paio di occhi sulla sua fattura, sono sempre felice di dare un'occhiata — soprattutto se è in APAC. E se è già cliente DoiT, ha il dashboard GenAI Intelligence — lo usi come punto di partenza per quella review trimestrale.
Lo script di benchmarking citato in questo articolo è disponibile all'indirizzo https://github.com/p-obrien/bedrock-cost-model-blog. Lo esegua sui suoi workloads per generare i dati che le servono per decisioni informate.