Jangada AIJangada AI

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 import nunca 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 agora

Default 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 usage traz a duração (audio_seconds): passe response_format="verbose_json" na transcrição ou informe a duração no Audio.from_bytes(dados, mime, duration=...). Registre/ajuste o preço por minuto com register_audio_price:

    from jangada_ai import register_audio_price
    register_audio_price("whisper-1", 0.006)   # USD por minuto
  • Detecção: detect_objects/adetect_objects devolvem só list[Detection] (sem custo). Para o custo, use detect_objects_full/adetect_objects_full, que devolvem um DetectionResult com .detections e .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

O que mudou na 1.9.0

Contrato de usage

Todos os adapters devolvem usage no mesmo formato:

ChaveSignificado
input_tokenstotal de input, já incluindo tokens de cache
output_tokenstotal de output (no Gemini inclui os tokens de thinking)
cache_read_tokensparte do input lida do cache (opcional)
cache_write_tokensparte do input gravada no cache (opcional)
reasoning_tokensparte do output gasta raciocinando (só informativa)
server_tool_requestschamadas 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 no Completion.cost. Cotas gratuitas não são descontadas.
  • O casamento de modelo ganhou fronteira: claude-opus-4 volta a custar 15/75 (não herda o preço do Opus 4.5+), gpt-5-pro/o3-mini não pegam a regra do modelo base, e um modelo sem regra devolve None em vez de um preço errado.
  • Um hit de cache da própria lib devolve cost=0.0 e cached=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().

On this page