Usage, Quota & Spend Tracking (Português (Brasil))
Visão geral
Seção intitulada “Visão geral”Cada solicitação que passa pelo OmniRoute gera um registro de uso que captura:
- Identidade: qual chave de API, provedor, modelo e combo
- Tokens: tokens do prompt, tokens de conclusão, tokens em cache e total
- Custo: valor em USD (calculado a partir dos dados de preços)
- Temporização: latência e timestamps de início/fim
- Status: sucesso, erro, limitação de taxa etc.
Esses registros são agregados em análises, persistidos como snapshots de cota e usados para aplicar limites de orçamento por chave.
Solicitação ──▶ chatCore ──▶ usage.record() ──▶ SQLite │ ┌───────┼───────┐ ▼ ▼ ▼ análises cota cobrança (painel) (aplicação) (exportação)O que é registrado
Seção intitulada “O que é registrado”O serviço usage.ts captura um evento de uso para cada solicitação:
| Campo | Tipo | Origem |
|---|---|---|
id |
string | UUID gerado no momento do registro |
apiKeyId |
string | A chave de API que iniciou a solicitação |
provider |
string | ID do provedor (openai, anthropic etc.) |
model |
string | ID do modelo (gpt-5, claude-opus-4-6 etc.) |
comboId |
string? | ID do combo, caso o roteamento tenha sido feito por um combo |
promptTokens |
number | Obtido da resposta do upstream |
completionTokens |
number | Obtido da resposta do upstream |
cachedTokens |
number | Tokens de acerto de cache (cache de prompt da Anthropic etc.) |
totalTokens |
number | prompt + conclusão |
costUsd |
number | Calculado a partir dos dados de preços |
latencyMs |
number | Duração de ponta a ponta da solicitação |
status |
enum | success, error, rate_limited, timeout, cancelled |
errorClass |
string? | Classe do erro se o status != success |
timestamp |
string | ISO 8601 UTC |
metadata |
object | Dados personalizados injetados por plugins |
De onde vêm os tokens
Seção intitulada “De onde vêm os tokens”Os tokens são extraídos da resposta do provedor upstream no manipulador de resposta:
// De open-sse/handlers/chatCore.tsconst response = await providerExecutor.execute(provider, request);const usage = response.usage || { prompt_tokens: 0, completion_tokens: 0, cached_tokens: 0,};Para provedores que não retornam dados de uso (alguns provedores baseados em cookies da web), o OmniRoute estima os tokens usando uma heurística de ~4 caracteres por token (consulte open-sse/services/autoCombo/pipelineRouter.ts).
Tokens em cache
Seção intitulada “Tokens em cache”O OmniRoute rastreia cached_tokens separadamente de prompt_tokens porque:
- O cache de prompts da Anthropic cobra uma tarifa reduzida pelos tokens em cache (10% da tarifa normal)
- Alguns provedores retornam
cache_read_input_tokens, que devem ter preços calculados de forma diferente - As análises podem mostrar a taxa de acerto do cache =
cached_tokens / prompt_tokens
Cálculo de custos
Seção intitulada “Cálculo de custos”Os custos são calculados com base nos dados de preços sincronizados do LiteLLM (src/lib/pricingSync.ts):
| Modelo | Entrada $/1M | Saída $/1M | Cache $/1M |
|---|---|---|---|
| gpt-5 | $2.50 | $10.00 | — |
| claude-opus-4-6 | $15.00 | $75.00 | $1.50 |
| claude-sonnet-4-5 | $3.00 | $15.00 | $0.30 |
| gemini-2.5-pro | $1.25 | $10.00 | — |
A fórmula de custo (src/lib/usage/costCalculator.ts):
cost = (prompt_tokens - cached_tokens) * input_price + cached_tokens * cached_price + completion_tokens * output_price;Por que subtrair os tokens em cache do prompt? A parte em cache é tarifada separadamente; aplicar o preço de entrada ao prompt inteiro resultaria em uma cobrança excessiva.
Sincronização de preços
Seção intitulada “Sincronização de preços”Os dados de preços são sincronizados automaticamente do LiteLLM por meio do endpoint /api/pricing/sync (acionado pela tarefa cron integrada, e não por uma variável de ambiente acessível ao usuário):
# Acionamento manualcurl -X POST http://localhost:20128/api/pricing/syncPara modelos sem dados de preços, o OmniRoute recorre à estimativa de custo usando taxas médias internas (obtidas dos dados de preços do LiteLLM).
Agregação por intervalo de datas
Seção intitulada “Agregação por intervalo de datas”O módulo usageAnalytics.ts calcula os widgets do painel a partir dos dados brutos de uso. Ele oferece suporte a 7 intervalos de tempo:
| Intervalo | Período | Caso de uso |
|---|---|---|
1d |
Últimas 24 horas | Detecção de picos de custo por hora |
7d |
Últimos 7 dias | Revisão semanal |
30d |
Últimos 30 dias | Faturamento mensal |
90d |
Últimos 90 dias | Análise trimestral |
ytd |
Desde 1º de janeiro do ano atual | Acompanhamento do orçamento anual |
all |
Todo o período | Estatísticas acumuladas |
custom |
Início/fim definidos pelo usuário | Auditorias, consultas pontuais |
Widgets calculados no painel
Seção intitulada “Widgets calculados no painel”Para qualquer intervalo de datas, a camada de análise calcula:
| Widget | Descrição |
|---|---|
| Cartões de resumo | Total de solicitações, custo total, total de tokens, taxa de sucesso |
| Gráfico de tendência diária | Custo + tokens por dia, empilhados por modelo |
| Mapa de calor de atividade | Grade de hora do dia × dia da semana, cor = número de solicitações |
| Detalhamento por modelo | Gráfico de pizza do custo por modelo |
| Detalhamento por provedor | Gráfico de barras das solicitações por provedor |
| Principais chaves de API | Tabela das 10 principais chaves por custo |
| Análise de erros | Taxa de erros ao longo do tempo, principais classes de erro |
Acesso programático
Seção intitulada “Acesso programático”import { computeAnalytics } from "@/lib/usageAnalytics";
const analytics = await computeAnalytics( history, // registros do histórico de uso "7d", // intervalo de tempo: "1d" | "7d" | "30d" | "90d" | "ytd" | "all" | "custom" connectionMap, // mapa de conexões do provedor (connectionId → nome da conta) { startDate: "2025-01-01", // opcional: para o intervalo "custom" endDate: "2025-06-01", // opcional: para o intervalo "custom" });
console.log(analytics.summary.totalCost); // 12.34 (centavos)console.log(analytics.byModel[0]); // { model, cost, requests, promptTokens, completionTokens }
---
## Aplicação de cotas
A cota por chave de API é aplicada em dois pontos:
1. **Limite flexível** (`quotaWarnAt`): aviso no painel quando o uso excede o limite2. **Limite rígido** (`quotaLimit`): solicitação rejeitada com HTTP 429 quando excedido
### Configuração
```ts// Por chave de APIawait updateApiKey(keyId, { quotaWarnAt: 5_00, // $5.00 — exibir aviso quotaLimit: 10_00, // $10.00 — interrupção obrigatória quotaWindow: "month", // "day" | "week" | "month" | "all"});Fluxo de aplicação
Seção intitulada “Fluxo de aplicação”Solicitação ──▶ quotaCheck() │ ├── Dentro do limite? ──▶ permitir │ └── Acima do limite? ──▶ 429 Too Many Requests com o cabeçalho Retry-AfterSnapshots de cota
Seção intitulada “Snapshots de cota”A tabela quotaSnapshots armazena o estado histórico das cotas para análise de tendências:
| Campo | Descrição |
| ———– | –––––––––––––––– | —— | —–– |
| apiKeyId | A chave que está sendo monitorada |
| window | “day” | “week” | “month” |
| used | Custo usado nesta janela (centavos) |
| limit | O limite (centavos) |
| resetAt | Quando a janela é redefinida |
| createdAt | Quando o snapshot foi obtido |
Os snapshots são obtidos em cada solicitação que usa um custo > 0 e são usados para:
- Renderizar a barra de progresso da cota no painel
- Exibir gráficos de tendência da cota dos últimos 30 dias
- Disparar alertas quando o uso se aproxima do limite
API REST
Seção intitulada “API REST”Listar registros de uso
Seção intitulada “Listar registros de uso”GET /api/usage?range=7d&limit=100GET /api/usage?apiKeyId=key-123&range=30dGET /api/usage?provider=openai&range=1dResposta:
{ "records": [ { "id": "uuid", "apiKeyId": "key-123", "provider": "openai", "model": "gpt-5", "promptTokens": 1234, "completionTokens": 567, "totalTokens": 1801, "costUsd": 0.005, "latencyMs": 1234, "status": "success", "timestamp": "2026-06-08T12:00:00Z" } ], "total": 1234, "nextCursor": "..."}Obter resumo analítico
Seção intitulada “Obter resumo analítico”GET /api/usage/analytics?range=7d&groupBy=modelResposta:
{ "summary": { "totalCost": 12.34, "totalRequests": 5678, "totalTokens": 12345678, "successRate": 0.987, "avgLatencyMs": 1234 }, "models": [ { "model": "gpt-5", "cost": 8.5, "requests": 1234, "tokens": 4567890 }, { "model": "claude-opus-4-6", "cost": 3.84, "requests": 234, "tokens": 234567 } ], "daily": [ { "date": "2026-06-01", "cost": 1.5, "requests": 800 }, { "date": "2026-06-02", "cost": 2.0, "requests": 1000 } ]}Consultar análises de uso
Seção intitulada “Consultar análises de uso”Os dados de uso são acessados pelo painel ou pelas ferramentas MCP, e não por endpoints REST de exportação direta. Análises disponíveis:
/api/usage/analytics— métricas de uso agregadas (agrupadas por modelo, provedor e chave)/api/usage/quota— status atual da cota por chave de API/api/usage/history— logs do histórico de solicitações
Ferramentas MCP
Seção intitulada “Ferramentas MCP”Duas ferramentas MCP expõem dados de uso aos agentes (consulte open-sse/mcp-server/tools/):
| Ferramenta | Descrição |
|---|---|
omniroute_cost_report |
Gera um relatório de custos por chave para um determinado período |
omniroute_check_quota |
Retorna o status atual da cota de uma chave de API |
Exemplo de invocação por um agente:
{ "tool": "omniroute_cost_report", "args": { "period": "week" }}Retenção e Limpeza
Seção intitulada “Retenção e Limpeza”Os dados de uso aumentam em aproximadamente 1-10KB por solicitação. Em escala, isso pode ser significativo.
Configurações de Retenção
Seção intitulada “Configurações de Retenção”A retenção do histórico de uso é configurada por meio das Configurações do Banco de Dados na interface ou por meio de /api/settings/database.
Por padrão, o histórico de uso é retido por 90 dias.
Limpeza
Seção intitulada “Limpeza”Os registros antigos são limpos por src/lib/db/cleanup.ts:
- Acionada pelo processo cron em segundo plano
- Exclui registros de
usage_historymais antigos que o período configurado na opção de retençãousageHistory
Estimativa de Armazenamento
Seção intitulada “Estimativa de Armazenamento”| Taxa de solicitações | Armazenamento por 30 dias | Armazenamento por 90 dias |
|---|---|---|
| 100 sol./dia | ~3MB | ~9MB |
| 1.000 sol./dia | ~30MB | ~90MB |
| 10.000 sol./dia | ~300MB | ~900MB |
| 100.000 sol./dia | ~3GB | ~9GB |
Para tráfego muito alto, considere:
- Reduzir o período de retenção por meio das Configurações do Banco de Dados
- Usar
aggregated_metricsem vez de registros brutos (somente para análises)
Dicas de Otimização de Custos
Seção intitulada “Dicas de Otimização de Custos”1. Use o Modelo Adequado
Seção intitulada “1. Use o Modelo Adequado”# Resposta rápida — use um modelo barato e rápidocurl -d '{"model":"auto/fast","messages":[...]}'
# Tarefa complexa — priorize a qualidadecurl -d '{"model":"auto/smart","messages":[...]}'2. Habilite o Cache
Seção intitulada “2. Habilite o Cache”O cache de prompts da Anthropic proporciona uma economia de 90% em contextos repetidos:
// O cache é automático — basta incluir o mesmo prompt de sistema extensoconst response = await openai.chat({ model: "claude-sonnet-4-5", system: longSystemPrompt, // Será armazenado em cache automaticamente messages: [{ role: "user", content: "..." }],});3. Use Compressão
Seção intitulada “3. Use Compressão”A compressão RTK + Caveman proporciona uma economia de 15-95% em sessões com uso intensivo de ferramentas:
const config = { compression: { engine: "rtk", intensity: "aggressive", },};4. Defina Cotas por Chave
Seção intitulada “4. Defina Cotas por Chave”Sempre defina quotaLimit para evitar custos descontrolados:
await updateApiKey(keyId, { quotaLimit: 10_00 }); // Limite de US$ 10/mês5. Audite os Maiores Consumidores
Seção intitulada “5. Audite os Maiores Consumidores”Use o painel ou /api/usage/analytics para agrupar por chave de API e ordenar por custo:
GET /api/usage/analytics?groupBy=apiKeySolução de Problemas
Seção intitulada “Solução de Problemas”“O custo está acima do esperado”
Seção intitulada ““O custo está acima do esperado””- Verifique
/api/usage/analytics?groupBy=model— encontre o modelo caro - Verifique
/api/usage/analytics?groupBy=apiKey— encontre o maior consumidor - Verifique se os dados de preços estão atualizados:
POST /api/pricing/sync
“Registros ausentes”
Seção intitulada ““Registros ausentes””- Verifique as configurações de retenção do banco de dados em Painel → Banco de Dados → Limpeza — os registros antigos são excluídos pela tarefa de limpeza periódica (
src/lib/db/cleanup.ts) - Verifique se há erros em
src/lib/db/usage*.ts— as falhas de gravação no banco de dados são registradas em log, mas não são exibidas - Verifique se a solicitação realmente chegou a
chatCore— confira o roteamento combinado
“A cota não está sendo aplicada”
Seção intitulada ““A cota não está sendo aplicada””- Verifique a configuração
quotaLimitda chave - Verifique se
quotaWindowestá definido corretamente - Procure registros de
quotaSnapshots— eles devem ser criados a cada solicitação
Consulte Também
Seção intitulada “Consulte Também”- DATABASE_GUIDE.md — Esquema das tabelas de uso
- ENVIRONMENT.md — Variáveis de ambiente para sincronização de preços
- AUTO-COMBO.md — Como
auto/fasteauto/cheapreduzem os custos - API_REFERENCE.md — Referência completa de
/api/usage/* - Código-fonte:
open-sse/services/usage.ts,src/lib/usageAnalytics.ts,src/lib/db/usage*.ts
HagiCode
HagiCode é um ambiente de programação com agentes, fluxos estruturados, execução multiagente e visualizações Hero Dungeon.
Transforme ideias em software útil com um fluxo de trabalho com agentes mais inteligente, rápido e agradável.

- SmartFluxos estruturados transformam intenções em um caminho executável da ideia à entrega.
- EfficientFluxos multiagente mantêm pesquisa, implementação e revisão em andamento simultaneamente.
- FunO Hero Dungeon torna longas sessões de programação mais visuais e colaborativas.