What an AI agent actually costs on Google Cloud

I deployed an ADK agent on Google Cloud, ran it for three days, and pulled the cost from the billing export instead of estimating it. I built the experiment around three levers, two of them outside the model. The model was 87.7% of the bill, and 77.4% of everything it wrote never appeared in a response. The thing that dominated the bill was not on my list.

The video makes the argument. This is the version you can check. Every number here comes from a query in the repo.

What I measured

One agent, running Gemini 2.5 Flash. Three GCP projects, one per variable, because Vertex AI bills at project level and there is no resource to label. The project is the only attribution boundary that works.

LeverQuestion
A. Idle capacityCloud Run warm versus scaled to zero
B. Context sizeADK compaction on versus off
C. Hosting modelCloud Run versus Vertex AI Agent Engine

The load generator sends a fixed prompt on an absolute schedule, so request latency cannot shift the send rate. It records per-request token counts from the API response. Cost comes from the BigQuery billing export. The two meet on a run ID and a UTC window.

The video title counts 1,112 requests. evidence/ publishes 1,007 of them, 1,005 successful. The difference is runs I did not publish. Every per-request number below comes from the 1,007.

Total spend for the whole thing: $1.18.

Where the money went

costshare
model (Vertex AI)$1.03773287.7%
hosting (Cloud Run)$0.14574012.3%
everything else$0.0000220.0%

I predicted 70/30. I was out by a factor of two and a half on the part I had built the entire experiment around.

The ratio held independently in all three projects: 85%, 86% and 96% model. It is not an artefact of how one lever was configured.

The part of the bill you never see

I found this by accident. I was debugging a load generator that kept reporting numbers I did not trust, and started reading a raw response body to work out why.

Gemini returns thoughtsTokenCount separately from the visible answer. Those tokens never appear in the response. Google’s pricing page bills them at the output rate, in a row named “Text output (response and reasoning)”. There is no discounted tier.

Across 490 lever A requests:

tokens
input23,030
visible output44,400
reasoning152,189
billed total219,619

69.3% of the billed tokens were reasoning. 77.4% of everything the model wrote, I never saw.

Applying published rates: $1.02 per 1,000 invocations. Count only the prompt and the visible answer, the way most estimates do, and you get $0.24. Low by 4.2x.

Then the part I did not expect. Every one of those 490 requests sent an identical prompt. Input was exactly 47 tokens, every time.

reasoning tokens
min108
median277
p95760
max942

An 8.7x spread on identical input. That figure is pooled across all 490 lever A requests; per profile the spreads were 8.3x steady and 8.1x bursty. The top 5% of requests cost nearly three times the median. So cost per invocation is not a property of your workload. You cannot budget it from one measurement.

The three levers

A. Idle capacity. Six runs, three traffic shapes, two settings.

hostingtotal
min-instances 0$0.023890$0.263752
min-instances 1$0.063437$0.326090

Keeping one instance warm nearly tripled hosting. But hosting is 12% of the bill, so the total moved about a quarter. The lever works. It is attached to the wrong number.

Which is the part worth sitting with. I spent most of a week building an experiment around a knob that turned out to control an eighth of the thing I was measuring.

B. Context size. Same 120-turn conversation, twice, compaction off then on. Nothing else changed.

Billed tokens: 923,731 against 916,882. 0.74% apart, which is inside the noise of the reasoning variance above. Both arms grew at the same rate and neither showed a step down.

It never fired. The conversation reached 15,041 tokens against a context window of roughly a million, and compaction triggers near the limit, so it was never going to. At this scale it is a seatbelt for a much longer session rather than a cost lever.

I could have lowered the threshold until something moved. Then I would have been measuring my own threshold instead of the default, which is a different and much less interesting result.

C. Hosting model. Same agent, both hosts, same workload. Tokens came out within 1.1%.

The cost was never the interesting part. Agent Engine has no service URL. It exposes a resource name and class methods called through the Vertex API, with a different token type, a different endpoint, a different response shape, and no unary query method at all. I had to write a second client, not change a flag.

So the question I started with, which host is cheaper, assumes you can change your mind later. You can port the agent easily enough. Porting everything that calls it is the actual cost, and it does not appear in any pricing table.

What I would caveat

One region, one model, one agent, three days. The absolute numbers are cents, and they should not travel. What held up across every cut of the data was the ratios.

Two specifics worth knowing before you reuse any of this:

The hosting costs were never actually paid. Cloud Run’s free tier absorbed all 415 usage rows. The detailed export shows $0.14574 in cost against $0.14574 in credits, netting zero. The 166% increase between arms is a real measure of usage. The dollars are what someone past the free tier would owe.

Cold starts here are inferred from client latency, which is a proxy. Latency on identical requests varied 4x with no cold start involved, so the effect is smaller than the noise. Server-side startup metrics are the right source and I did not use them.

The specific figures will age. Models change and pricing changes. I would not build a forecast around my numbers. I would build the next experiment around the method.

Video - Repo - Queries - Raw data - Full findings

ยท 5 min read