Skip to content

fix(finops-framework): correct 1000x overstated cost and rescale the demo quotas - #399

Merged
Alex Vieira (vieiraae) merged 2 commits into
Azure-Samples:mainfrom
jk99k:fix/finops-pricing-1000x
Sep 16, 2026
Merged

Alex Vieira (vieiraae) merged 2 commits into
Azure-Samples:mainfrom
jk99k:fix/finops-pricing-1000x

Conversation

@jk99k

Copy link
Copy Markdown
Contributor

Fixes #397. Two commits: correct the prices, then rescale the quotas that were calibrated against the wrong ones.

The prices

The Retail Prices API returns Foundry token meters with unitOfMeasure of 1K, so retailPrice is already a per-1000-token price. The notebook multiplies it by 1000 before writing it to PRICING_CL, but every consuming query already divides by 1000:

| extend InputCost  = PromptTokens     * InputTokensPrice
| extend OutputCost = CompletionTokens * OutputTokensPrice
| extend TotalCost  = (InputCost + OutputCost) / 1000

Each token ends up charged the price of a thousand tokens. For 1M input tokens on gpt-4.1-mini that's 400 USD reported instead of 0.40 USD.

The same KQL backs alert-suspend-sub and alert-activate-sub, so cost quotas trip about a thousand times too early and subscriptions get suspended almost as soon as they serve traffic.

The quotas

Correcting the prices on their own would leave the lab's central scenario unable to fire, so the second commit deals with that.

costQuota is 15/10/5 USD. Those values only work because costs are inflated: reaching the silver quota of 5 USD takes roughly 1,000 tokens today. With correct prices it takes 1,000,000, and the monthly tokenQuota of 1,000,000 is hit first, so no subscription can ever exceed its cost quota and the suspend/activate Logic App never runs.

Scaling the quotas by the same factor the prices moved, to 0.015/0.010/0.005, restores the previous behaviour exactly: whatever traffic tripped a quota before still trips it, and the dashboard shows the same relationship between CostQuota and TotalCost.

The variables cell now says these are demo-sized, so they aren't mistaken for realistic budgets and raised back to a magnitude that can't be reached.

Breaking change

No. Rows already in PRICING_CL keep their values, but consumers read with arg_max(TimeGenerated, *) by Model, so the corrected row wins on the next ingestion. Anyone who already tuned costQuota for their own traffic will want to rescale it the same way.

Type

Bugfix.

How to test

The premise needs no deployment:

curl -s --get 'https://prices.azure.com/api/retail/prices' \
  --data-urlencode "currencyCode='USD'" \
  --data-urlencode "\$filter=serviceName eq 'Foundry Models' and armRegionName eq 'swedencentral' and skuName eq 'gpt 4.1 mini Inp glbl'"

One item, retailPrice: 0.0004, unitOfMeasure: 1K. All six meters in the default models_config behave the same.

I also deployed the lab, ingested the corrected prices and ran the workbook's own KQL against the workspace. 1135 prompt + 1135 completion tokens on gpt-4.1 gives 0.01135; the same query on the old values gives 11.35. result.png here shows TotalCost: 10.072 for 2.27k tokens, which is that inflated magnitude.

What to check

The KQL is deliberately untouched. The workbook, dashboard and both alert rules already assume a per-1K price, so correcting the ingested value is enough and nothing else has to move.

The display-only table earlier in the notebook keeps its *1000; only its column header changed, to state the unit. That value is never ingested.

The markdown note that stated the incorrect assumption is corrected.

Other

Introduced in c329179 (#140). One file, +9/-6.

result.png still shows the old magnitudes and would want regenerating at some point, though that needs a run in your environment rather than mine.

…tion

The Azure Retail Prices API returns Foundry Models token meters with
`unitOfMeasure` of `1K`, i.e. `retailPrice` is already the price per 1000
tokens (for example `gpt 4.1 mini Inp glbl` in swedencentral returns
`retailPrice: 0.0004`).

The notebook multiplied that value by 1000 before writing it to the
`PRICING_CL` custom table, while every cost query consuming the table
computes:

    | extend InputCost  = PromptTokens     * InputTokensPrice
    | extend OutputCost = CompletionTokens * OutputTokensPrice
    | extend TotalCost  = (InputCost + OutputCost) / 1000

Those queries already divide by 1000, so they expect a per-1K price. The
extra multiplication made every reported cost 1000x too high: 1M input
tokens on gpt-4.1-mini was reported as 400 USD instead of 0.40 USD.

This affects the cost analysis workbook, the dashboard, and the
`alert-suspend-sub` / `alert-activate-sub` scheduled query rules, which
means cost quotas could suspend an APIM subscription almost immediately.

Store `retailPrice` as returned. The consuming KQL is left unchanged
since it is already consistent with a per-1K price. The display-only
pricing table keeps its multiplication, and its column is renamed to
make the unit explicit. The markdown note that described the incorrect
scaling is corrected as well.
…ices

The `costQuota` values were calibrated against prices that were
overstated by 1000x, so they were effectively expressed in units of a
thousand tokens' worth of cost. With the prices corrected in the
previous commit, the same traffic produces costs a thousand times
smaller, and the quotas can no longer be reached: a test run that
previously exceeded the silver quota of 15 USD now costs about a cent,
and the monthly `tokenQuota` of 1,000,000 tokens is reached long before
the cost quota is.

That would leave the lab's central scenario, a subscription exceeding
its cost quota and being suspended by the alert-driven Logic App, unable
to fire at all.

Scale the three quotas by the same factor the prices moved, restoring
the previous behaviour exactly: whatever traffic tripped a quota before
still trips it now, and the dashboard shows the same relationship
between CostQuota and TotalCost.

Also note in the variables cell that these values are sized for a short
demo run, so they are not mistaken for realistic budgets and raised back
to a magnitude that can no longer be reached.
@jk99k

Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree company="Microsoft"

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Correct the pricing-unit note and remove its unconditional request-count claim.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This PR fixes a 1000× overstatement in Foundry token costs and rescales demo quotas accordingly.

Changes:

  • Removes the erroneous * 1000 price transformation.
  • Rescales demo quotas to 0.015/0.010/0.005.
  • Updates pricing labels and documentation.
File summaries
File Summary
labs/finops-framework/finops-framework.ipynb Corrects pricing ingestion, quotas, display units, and related documentation.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread labs/finops-framework/finops-framework.ipynb
@vieiraae
Alex Vieira (vieiraae) merged commit 1679e31 into Azure-Samples:main Sep 16, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finops-framework: reported cost is 1000x too high (retail price is already per 1K tokens)

3 participants