Behaviour for computing the cost of an LLM call.
Hardcoded prices go stale fast, so Baton does not ship authoritative prices. Instead it defines this behaviour and calls whichever module the host configures:
config :baton, pricing: MyApp.LLMPricingYour implementation receives a usage map and returns a cost as Decimal.t(),
or nil if the model is unknown (cost is then recorded as nil rather than a
wrong number).
defmodule MyApp.LLMPricing do
@behaviour Baton.Pricing
@impl true
def cost(%{model: "claude-sonnet-4-" <> _, input_tokens: i, output_tokens: o}) do
Decimal.add(
Decimal.mult(Decimal.new(i), Decimal.from_float(3.0 / 1_000_000)),
Decimal.mult(Decimal.new(o), Decimal.from_float(15.0 / 1_000_000))
)
end
def cost(_usage), do: nil
endBaton.Pricing.Default is provided as a starting point and for tests, but
you should supply your own and keep it current.
Summary
Callbacks
Return the cost in USD for a usage map, or nil if it can't be priced.
Functions
Compute cost via the configured pricing module.
Types
@type usage() :: %{ :model => String.t() | nil, optional(:input_tokens) => non_neg_integer(), optional(:output_tokens) => non_neg_integer(), optional(:cache_read_tokens) => non_neg_integer(), optional(:cache_write_tokens) => non_neg_integer() }