跳到正文
GitHub·· 7 天前AI 评分36

llm-bill-analyzer:把 LLM 用量导出变成账单分析

AlexRyan92/llm-bill-analyzer

AI 导读

开源工具 llm-bill-analyzer 可将 Anthropic Console、OpenAI Platform 导出的用量 CSV 在本地完成账单分析,数据不出本机。它按模型和日期估算花费,给出实际缓存命中率与已节省金额、稳定前缀缓存机会,以及把高价模型流量按比例迁移到低价模型的节省测算,支持 CLI 与库调用,价格表可替换。

正文

Turn a raw LLM usage export into the analysis the invoice never gives you. Zero dependencies, fully local: your billing data never leaves your machine.

Drop in the CSV from your provider console (Anthropic Console → Usage → Export, OpenAI Platform → Usage → Export) and get:

  • Spend by model and by day, estimated against a hand-verified price table (or your own)
  • Your actual cache hit rate, and what cache reads already saved you
  • The caching opportunity: what caching a stable prefix share of your uncached input is worth
  • The routing question: what moving a share of your most expensive model's traffic to a cheaper model saves (the quality side is an evals question; this is the money side)

Export formats drift, so columns are detected heuristically and the mapping is overridable. There is a hosted version that runs entirely in the browser tab.

Install

npm install llm-bill-analyzer   # library
npx llm-bill --help             # CLI, no install

CLI

$ npx llm-bill usage.csv --route-to haiku-4-5 --route-share 30
estimated spend:  $1,826
tokens:           499.93M in / 89.99M out / 35.26M cache-read
cache hit rate:   6.6%

by model:
  claude-opus-5-5               $1,013   55.5%
  claude-haiku-4-5                $595   32.6%
  gpt-6-sol                       $217   11.9%

caching:
  realized savings:     $60.37
  opportunity at 60% stable prefix: $514

routing:
  moving 30% of claude-opus-5-5 to Claude Haiku 4.5: $229
  run it behind an eval gate before you believe it.

--prices my-prices.json swaps the bundled snapshot for your own table (same shape: { models: [{ id, name, in, out }] }, USD per million tokens). --json emits the full report.

Library

import { analyze, parseCSV, detectColumns, matchModel } from 'llm-bill-analyzer';

const report = analyze(csvText, priceTable, {
  stablePrefixShare: 0.6,
  routeTo: priceTable.find(m => m.id === 'haiku-4-5'),
  routeShare: 0.3,
});
report.estimatedTotal;    // USD
report.cacheHitRate;      // 0..1
report.perModel;          // Map<rawName, { input, output, estimatedCost, matched, ... }>
report.cache;             // { realizedSavings, opportunity, hitRate, ... }
report.routing;           // { fromModel, toModel, savings }

Assumptions, stated plainly

Cache economics are Anthropic-style (reads at 10% of input price, writes at 125%); unmatched model names fall back to your cost column when the export has one. Daily-aggregate exports cannot show per-request shapes, so routing reprices tokens, not requests. The bundled price snapshot in data/models.json carries its verification date and source; it is a convenience, not an oracle. This is a planning tool, not an invoice.

License

MIT © Alexander Ryan. Price data snapshot from the LLM Model Reference, verified by hand and dated.

来源:GitHub · github.com