Custo e tokens
Toda resposta bem-sucedida volta com usage (tokens) e cost (USD estimado).
comp = llm.complete("...")
print(comp.usage) # {"input_tokens": ..., "output_tokens": ...}
print(comp.cost) # ex.: 0.000123 (USD, aproximado)O cliente chama pricing.compute_cost() após cada sucesso e seta
Completion.cost. FlowResult e GraphResult agregam usage/cost ao
longo da cadeia.
Tabela de preços
Os preços vêm de um catálogo JSON (aproximados, por 1M de tokens). Você pode registrar/ajustar em runtime:
from jangada_ai import register_price, price_for
register_price("meu-modelo", 0.5, 1.5) # USD por 1M tokens (input, output)
print(price_for("gpt-4o-mini"))⚠️ Os valores são aproximados e servem para estimativa/observabilidade — não trate como fonte de billing.
Preços sempre atualizados (sem atualizar a lib)
Os preços moram num catálogo JSON (não mais hardcoded). A cópia embutida no
pacote é só o fallback offline; a jangada publica o catálogo em
jangada.dev.br/prices.json e o aplica sozinha, sem você escrever nada — e
sem precisar dar pip install -U.
Automático (padrão). Na primeira vez que um custo é calculado (logo abaixo de cada chamada de provider), a lib dispara em background um refresh do catálogo, cacheado por 1 dia. Você só usa o LLM normalmente:
comp = llm.complete("...")
print(comp.cost) # já tende a usar os preços do dia (refresh em background)- Não bloqueia: roda numa thread daemon; o
importnunca toca a rede. - No máximo 1x/dia: cache em
~/.cache/jangada/prices.json(e 1x por processo). - Resiliente: rede falhou? fica no cache/embutido — nunca levanta.
- Desligar: env
JANGADA_NO_PRICE_REFRESH=1.
Manual (refresh_prices). Para controle explícito/síncrono (boot, forçar agora,
URL custom):
jangada_ai.refresh_prices() # síncrono, respeita o cache
jangada_ai.refresh_prices(ttl=3600, force=True) # revalida / força agoraDefault da URL: https://jangada.dev.br/prices.json (override por url= ou env
JANGADA_PRICES_URL; não precisa de .env). O override manual (register_price)
tem prioridade sobre tudo.
Custo multimodal
-
Imagem (vision): não há preço separado — os providers já contam os tokens da imagem dentro de
input_tokens. O custo da imagem já sai pela tabela normal. -
Áudio (transcrição): é cobrado por minuto, não por token. O custo só sai quando o
usagetraz a duração (audio_seconds): passeresponse_format="verbose_json"na transcrição ou informe a duração noAudio.from_bytes(dados, mime, duration=...). Registre/ajuste o preço por minuto comregister_audio_price:from jangada_ai import register_audio_price register_audio_price("whisper-1", 0.006) # USD por minuto -
Detecção:
detect_objects/adetect_objectsdevolvem sólist[Detection](sem custo). Para o custo, usedetect_objects_full/adetect_objects_full, que devolvem umDetectionResultcom.detectionse.completion/.cost/.usage:from jangada_ai import detect_objects_full res = detect_objects_full(llm, "foto.jpg") print(res.detections, res.cost)
Onde isso aparece
Completion.cost/Completion.usageem cada chamada.- Totais agregados em Fluxos e Graph.
- No Debug passo a passo, o custo de cada etapa é exibido no trace.
O que mudou na 1.9.0
Contrato de usage
Todos os adapters devolvem usage no mesmo formato:
| Chave | Significado |
|---|---|
input_tokens | total de input, já incluindo tokens de cache |
output_tokens | total de output (no Gemini inclui os tokens de thinking) |
cache_read_tokens | parte do input lida do cache (opcional) |
cache_write_tokens | parte do input gravada no cache (opcional) |
reasoning_tokens | parte do output gasta raciocinando (só informativa) |
server_tool_requests | chamadas de tools nativas, ex. {"web_search": 2} |
compute_cost cobra o input não-cacheado a preço cheio, a leitura/escrita de cache
pelo preço de cache do modelo, o output uma única vez (reasoning não é cobrado
em dobro) e soma a taxa por chamada das tools nativas. Antes, cache e thinking
eram ignorados — Gemini com thinking e Claude com prompt caching saíam bem mais
baratos que a fatura real.
Preço de cache, faixa acima de 200k e taxas de tools
- Cada regra pode ter
cache_read/cache_write(USD por 1M tokens). Sem eles, a lib usa o multiplicador documentado da família (Claude 0,1×/1,25×; Gemini 0,1×; gpt-5 0,1×; gpt-4.1/o3/o4-mini 0,25×; gpt-4o/o1/o3-mini 0,5×; desconhecido 1×). above_200k=(in, out)aplica outro preço quando o prompt passa de 200k tokens (ex.: Gemini 2.5 Pro, 3.1 Pro).- Taxas por chamada de tools nativas (catálogo
tool_fees): web search da Anthropic e da OpenAI US$ 10/1k, Google Search no Gemini 3.x US$ 14/1k queries, file search da OpenAI US$ 2,50/1k, conectores da Mistral etc. Entram noCompletion.cost. Cotas gratuitas não são descontadas. - O casamento de modelo ganhou fronteira:
claude-opus-4volta a custar 15/75 (não herda o preço do Opus 4.5+),gpt-5-pro/o3-mininão pegam a regra do modelo base, e um modelo sem regra devolveNoneem vez de um preço errado. - Um hit de cache da própria lib devolve
cost=0.0ecached=True.
from jangada_ai import register_price
from jangada_ai.pricing import register_tool_fee, compute_cost
register_price(r"meu-modelo", 1.0, 4.0, cache_read=0.1, above_200k=(2.0, 8.0))
register_tool_fee("web_search", 12.0, provider="meu-provider") # USD por 1000 chamadas
compute_cost("claude-sonnet-5", {"input_tokens": 10_000, "cache_read_tokens": 8_000,
"output_tokens": 500,
"server_tool_requests": {"web_search": 1}},
provider="anthropic")O refresh remoto do catálogo agora só aceita https, valida tipos e tamanhos,
rejeita regex perigosa e substitui o lote remoto a cada atualização (antes
acumulava).
Exemplo
examples/retry_cost_example.py — script executável.
examples/pricing_refresh_example.py — preços dinâmicos com refresh_prices().