API e SDKGuida
Traccia il costo in token di un agente AI in Python: usage, budget, stop
Registra il campo usage di ogni richiesta, sommali per attività e ferma l'agente a un budget in dollari. Esempio Python funzionante per un'API compatibile con OpenAI.

In questa pagina
Il tuo agente ha girato per dieci minuti e il conto è più grande del compito. Per capire perché, leggi l'oggetto usage in ogni risposta API, sommali per attività e moltiplica per il prezzo del modello per 1M di token. Per limitarlo, confronta quel totale progressivo con un budget dopo ogni passo e interrompi il ciclo quando viene superato. Qui sotto c'è una piccola classe Python che fa esattamente questo.
L'esempio usa l'endpoint compatibile con OpenAI https:/ e l'id del modello deepseek- (contesto 380K, fino a 32.768 token di output per risposta). Se vuoi stimare un'esecuzione prima di iniziarla, è un altro discorso, e Come stimare il costo di un agente AI lo copre. Questo articolo riguarda la misurazione e il limite durante l'esecuzione.
Dove sono i numeri: l'oggetto usage#
Ogni chat completion non in streaming torna con un oggetto usage. Il riferimento API di DeepSeek (verificato il 26 ottobre 2026) elenca questi campi:
prompt_tokens— tutto ciò che hai inviato questa volta: system prompt, cronologia, risultati degli strumenti.completion_— ciò che il modello ha scritto in risposta.tokens total_tokens— i due sommati insieme.
DeepSeek documenta anche extra opzionali: prompt_ e prompt_ (si sommano a prompt_tokens), e completion_ per i modelli di thinking. La pagina non mostra una data di pubblicazione, e questi extra sono estensioni del formato OpenAI, quindi il codice sotto li tratta come opzionali e si affida solo ai primi due campi.
Perché registrare ogni passo e non solo l'ultimo? Perché un agente reinvia il suo contesto in crescita ogni volta. Il passo 1 potrebbe inviare 2.000 token di input, il passo 30 potrebbe inviarne 9.000, e il conto è la somma di tutti. Il motivo è spiegato in perché una chat lunga costa di più, e la divisione input/output in token di input vs output.
Un contatore che ferma l'agente#
Ecco tutto: un contatore che somma i token, stampa una riga per passo e solleva un errore quando il budget viene superato, più un ciclo agente essenziale attorno ad esso. Installa l'SDK con pip install openai e metti la tua chiave in CHEAPTOKENS_.
import os
from openai import OpenAI
client = OpenAI(
base_url='https://api.cheaptokens.dev/v1',
api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'
# example prices, USD per 1M tokens: use the current ones from the pricing table
PRICE_IN = 0.10
PRICE_OUT = 0.40
class BudgetExceeded(Exception):
pass
class TaskMeter:
def __init__(self, budget_usd):
self.budget = budget_usd
self.steps = 0
self.tokens_in = 0
self.tokens_out = 0
self.reasoning = 0
@property
def cost(self):
return (self.tokens_in * PRICE_IN + self.tokens_out * PRICE_OUT) / 1_000_000
def add(self, usage):
self.steps += 1
self.tokens_in += usage.prompt_tokens
self.tokens_out += usage.completion_tokens
details = getattr(usage, 'completion_tokens_details', None)
self.reasoning += getattr(details, 'reasoning_tokens', 0) or 0
print(f'step {self.steps}: in={usage.prompt_tokens} '
f'out={usage.completion_tokens} task=${self.cost:.4f}')
if self.cost > self.budget:
raise BudgetExceeded(
f'budget ${self.budget:.2f} crossed at step {self.steps}: '
f'${self.cost:.4f}')
def run_task(goal, budget_usd=0.50, max_steps=40):
meter = TaskMeter(budget_usd)
messages = [
{'role': 'system', 'content': 'Work step by step. Reply DONE when finished.'},
{'role': 'user', 'content': goal},
]
for _ in range(max_steps):
resp = client.chat.completions.create(
model=MODEL, messages=messages, max_tokens=1024)
meter.add(resp.usage) # log first, then decide
reply = resp.choices[0].message.content or ''
messages.append({'role': 'assistant', 'content': reply})
if 'DONE' in reply:
break
messages.append({'role': 'user', 'content': 'Continue.'})
return meter
try:
meter = run_task('Summarise the main risks of a database migration.')
print(f'finished: {meter.steps} steps, ${meter.cost:.4f}')
except BudgetExceeded as err:
print('stopped:', err)Tre scelte lì dentro valgono la pena di essere copiate.
Registra prima di decidere. meter.add registra prima il passo e solo dopo controlla il budget, così un'esecuzione interrotta lascia comunque una traccia completa. Il controllo avviene dopo la chiamata che ha superato la linea, quindi puoi sforare al massimo di un passo. max_tokens=1024 limita l'output di quell'ultimo passo.
Due stop netti, non uno. max_steps cattura un agente che va in loop senza spendere molto; il budget in dollari cattura quello che spende molto per passo. Li vuoi entrambi.
I prezzi vivono in un unico posto. PRICE_IN e PRICE_OUT sono numeri segnaposto. Copia i valori attuali per il tuo modello dalla pagina dei prezzi; al momento DeepSeek-V4-Flash è $0.015 per 1M di token di input e $0.10 per 1M di token di output.
A quanto ammonta un'esecuzione di 40 passi#
Diciamo che il tuo agente faccia 40 passi, e poiché il contesto cresce, un passo medio invia 6.000 token di input e ne riceve 400 indietro. Sono 40 × 6.000 = 240.000 token di input e 40 × 400 = 16.000 token di output per l'attività.

Su DeepSeek-V4-Flash questo costa $0.0052. La tabella esegue lo stesso carico di lavoro sugli altri modelli e mette il prezzo di riferimento di OpenRouter accanto al nostro:
| Modello | Input $/1M | Output $/1M | Costo | OpenRouter |
|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.0054 | $0.0111 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.0052 | $0.0139 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.0144 | $0.0912 |
240.000 token di input e 16.000 token di output in totale. I prezzi per 1M di token sono attuali e cambiano insieme alle nostre tariffe; la colonna OpenRouter mostra i prezzi di riferimento per lo stesso carico di lavoro.
In totale, contando input e output insieme, DeepSeek-V4-Flash risulta più economico di OpenRouter per questa attività. Nota anche dove sono i token: 240.000 dei 256.000 sono input. Il contesto che il tuo agente si trascina dietro è il conto, ed è per questo che il numero in= per passo nel tuo log è quello da tenere d'occhio. Un budget di $0,50 per attività nell'esempio sopra è un limite a una corsa sfrenata, non un obiettivo.
Cambiare modello significa solo cambiare MODEL. Scegli l'id dalla documentazione CheapTokens: i nomi differiscono tra i provider, e un id breve da un'etichetta di prezzo non funzionerà nell'API. Per lunghi cicli agente, DeepSeek-V4-Flash ha un unico prezzo a qualsiasi ora del giorno, quindi un'attività costa lo stesso a mezzogiorno e alle 3 del mattino. Vedi la pagina DeepSeek per i suoi limiti.
Quando il modello sta pensando#
Se una risposta è molto più lunga in token rispetto al testo che vedi, guarda reasoning_tokens. I token di thinking contano come output, quindi un passo ad alto ragionamento può produrre molti più token di output di quanto suggerisca il testo visibile, e vengono fatturati come output. Il contatore sopra li raccoglie in meter.reasoning quando l'API restituisce il campo e lo lascia a 0 quando non lo fa, quindi non va mai in crash su una chiave mancante. Stampalo accanto a out= se vuoi vedere quanto dell'output era thinking. Sforzo di ragionamento e token di thinking spiega perché.
Streaming: l'usage arriva per ultimo#
Se il tuo agente fa streaming, non c'è usage nei chunk normali. Nel formato OpenAI lo richiedi con stream_. Il riferimento di DeepSeek (verificato il 26 ottobre 2026) dice che l'opzione funziona solo insieme a stream=True (altrimenti l'API risponde 400), che usage è null in ogni chunk tranne uno, e che l'ultimo chunk prima di data: [DONE] porta i totali per l'intera richiesta. Quindi in un ciclo di streaming, chiama meter.add una volta, sul chunk dove usage non è vuoto. Il ciclo non in streaming sopra è il punto di partenza più semplice; streaming in Python ha il ciclo stesso.
Se i numeri sembrano sbagliati#
usageè None. Stai facendo streaming senzainclude_usage. Aggiungilo, o passa a una chiamata non in streaming.- Il totale è inferiore al calo del saldo. Controlla che ogni chiamata passi attraverso il contatore: i retry, una chiamata di riepilogo o una chiamata di selezione degli strumenti fatta fuori da
run_tasksono facili da dimenticare. Avvolgiclient.in un'unica funzione e fai passare tutto da lì.chat. completions. create - Il costo per passo continua a salire. È normale per un ciclo che aggiunge tutto a
messages. Taglia il vecchio output degli strumenti o riassumi la cronologia; output degli strumenti fuori contesto mostra l'idea. BudgetExceededscatta al passo 2. Il tuo budget è più piccolo di un passo. Controlla chePRICE_INsia per 1M di token, non per 1K.
Per memorizzare i numeri, scrivi meter.steps, meter.tokens_in, meter.tokens_out e meter.cost come una riga JSON per attività. Una settimana di quelle righe ti dice i token reali per passo del tuo agente, che è il numero da inserire in ogni stima successiva. Modelli, prezzi e la prima richiesta sono nella documentazione; le chiamate agli strumenti sono trattate in function calling in Python.



