fix(aio): stop over-billing cache-heavy gemini generations - #79781
Closed
fivestarspicy wants to merge 1 commit into
Closed
fix(aio): stop over-billing cache-heavy gemini generations#79781fivestarspicy wants to merge 1 commit into
fivestarspicy wants to merge 1 commit into
Conversation
The exclusive-reporting fallback treated any `input < cache_read + cache_write` as proof that a provider reports cache tokens as a separate pool. Inclusive providers can break that invariant by a few percent without changing accounting model: with Gemini explicit context caching, `cached_content_token_count` is counted when the cache is created while `prompt_token_count` is counted per request, so the two land slightly apart. Flipping those events to exclusive bills the full input at the prompt rate and the cache again at the cache rate, so a nearly fully cached prompt bills several times over. Require the cache pool to exceed input by more than 1.5x before resolving exclusive, and clamp the residual text pool to zero on every path so a small overshoot cannot bill a negative residual. Generated-By: PostHog Code Task-Id: 06160e48-feb9-4d39-8b7b-3dcfd1d9ca24
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
5 tasks
Contributor
Author
|
Closing in favor of posthog-python#860, which declares Gemini's cache accounting model in the SDK rather than inferring it in ingestion. The approach here layered a tolerance on top of the existing inference, which meant a threshold constant tuned against observed token shapes. Declaring the accounting model at the source removes the need to infer it at all for providers we know. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
cached_content_token_countis counted when the cache is created andprompt_token_countis counted per request, so the two counts land a few percent apart.input < cache_read + cache_writeas proof of exclusive accounting.Changes
clampTextTokensnow clamps the residual text pool to zero on every path, not only when modality tokens are present.I picked 1.5x by measuring both populations on production generations. Reporting slop on inclusive providers clusters within roughly 8% over input. Genuine exclusive reporting sits about three orders of magnitude higher. The threshold sits in the empty band between them, so neither population is near it.
Note
An exclusive-reporting integration whose cache pool sits between 1x and 1.5x of input now resolves inclusive and is slightly underbilled. #74183 already documented and accepted that direction of error. The reverse direction is the expensive one, and this PR closes it.
How did you test this code?
npx jest src/ingestion/pipelines/ai/costs/ src/ingestion/pipelines/ai/process-ai-event.test.ts. All suites pass.handles negative token counts gracefully. It asserted a negative cost for negative input tokens, which is the behavior this PR removes. It now asserts zero.Automatic notifications
Docs update
None.
products/ai_observability/skills/exploring-llm-costs/references/cache-accounting.mddescribes ingestion as auto-detecting the value, which stays true.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
I (the PostHog Slack app, running Claude) investigated this from a Slack thread on Gemini cost reconciliation, and a PostHog engineer directed the fix. I did not set an assignee because I could not verify their GitHub handle in session.
Skills invoked:
/writing-code-comments,/writing-tests,/writing-pr-descriptions.Before settling on the threshold I checked two other explanations and ruled both out. I traced the Gemini path in posthog-python and confirmed it copies both counts off a single
usage_metadataobject with no arithmetic, so the skew is not a mapping bug. I then found a real asymmetry inmerge_usage_stats, where cumulative mode overwritesinput_tokenson every chunk but only writescache_read_input_tokenswhen it is above zero, which would let the two counts come from different chunks. That path needs streaming, and the affected calls are non-streaming, so it is not the cause here.I also considered setting
$ai_cache_reporting_exclusiveexplicitly in the Gemini wrapper. That is correct and worth doing separately, but it only reaches updated SDKs and does not cover OTel or manual capture, so it does not recover the affected population on its own.Public artifact: no customer or session material reached this PR. The token values in the new tests are invented to exercise the ratio boundary.
Created with PostHog from a Slack thread