Module 2: The Bedrock Cost Model
1. Introduction: price per token, not per hour
Description
ADR-001-llm-as-escalation-path.md, the document that closed Module 1, left one row of its own table pointing directly at this module: "M2 — The Bedrock cost model | Prices the escalation path per token before a single resource is declared, so cost is a known input, not a surprise". This lesson opens that row. Before declaring a single Terraform resource (that's Module 3), before writing a guardrail (Module 4), Andes Cargo needs to answer a question none of the previous seven guides in this ecosystem had to answer this way: how much does invoking a Bedrock model cost, and why does that question break the intuition EC2, Lambda, and DynamoDB already taught you?
Connection to the module
This is the first of eight lessons. Its job is to install, with a concrete example, the underlying difference between "paying for something being on" and "paying for what that something processed" — the distinction lessons 2 through 8 of this module are going to develop in detail: Bedrock's five real pricing models (lesson 2), the quota limit no bill shows (lesson 3), inherited Infracost and its honest attempt against a Bedrock resource (lessons 4 and 5), why that tool can't solve this alone (lesson 6), the custom calculator that does solve it (lesson 7), and the document that closes the module with the final model and volume decision (lesson 8).
This module's map: the 8 lessons
M2 -- THE BEDROCK COST MODEL
1 Introduction price per token, not per hour (this lesson)
2 How Bedrock is billed 5 real pricing models, cited from AWS
3 Bedrock quotas the limit no bill shows
4 Hands-on: inherited Infracost --version / --help, zero reinstall
5 Hands-on: the honest attempt infracost scan on bedrock.tf, for real
6 Why Infracost can't solve this alone no plan describes a volume assumption
7 Hands-on: the custom calculator bedrock_cost_estimate.py + pytest, deterministic
8 Project: GENAI-COST-PROFILE.md chosen model, declared volume, projection
| # | Lesson | What you practice |
|---|---|---|
| 1 | Introduction (this one) | Why an AI workload's cost breaks the "on = costs money" intuition |
| 2 | How Bedrock is billed | On-Demand, Provisioned Throughput, Batch, Flex, Priority — with cited prices |
| 3 | Bedrock quotas | Invocations/tokens per minute, named, unable to be verified against a real account |
| 4 | Hands-on: inherited Infracost | Executed: infracost --version, infracost scan --help |
| 5 | Hands-on: the honest attempt | Executed (the attempt) + representative (the number): infracost scan andes-cargo-infra/ |
| 6 | Why Infracost can't solve this alone | No Terraform resource describes "one invocation" |
| 7 | Hands-on: the custom calculator | Executed: bedrock_cost_estimate.py, run with pytest against fixed cases |
| 8 | Project: GENAI-COST-PROFILE.md | Executed (the document): model, volume, projection — the module's deliverable |
Notice the progression: first you understand how something you never billed before gets billed (lessons 2 and 3), then you confirm, for real, exactly how far the tool you already trust reaches (lessons 4 through 6), and you close by building the missing piece (lessons 7 and 8) — the same "understand before automating" discipline finops-and-cost-guardrails-guide already applied to S3, Lambda, and DynamoDB, now one level harder.
Analogy: the roaming fee, not the fixed monthly plan
When you sign up for a cell phone plan with unlimited data in your own country, you know exactly what you're going to pay every month — the number is fixed before you use a single megabyte, and using more or less doesn't change the bill. That's the mental model EC2, and to a good extent Lambda and DynamoDB with reserved capacity, already taught you: you provision something, and the cost derives from how long that something exists, not from what it does during that time.
Now imagine that same phone crosses a border and activates international roaming. Suddenly, the fixed plan disappears: every megabyte you consume has an individual price, that price depends on which country you're visiting and which carrier serves you, and there's no way to know the total bill until the month ends — unless you do the math yourself, with an explicit assumption of how many megabytes you're going to use. Nobody sends you a mid-trip alert saying "you're already at $40 in roaming" unless you set that up yourself.
Invoking a Bedrock model is, in its cost structure, exactly roaming, not a fixed plan. You don't pay for having the model "on" — you don't turn it on or off, it's a service AWS manages that exists all the time for all its customers. You pay, per token, every time you send it text and every time it sends text back — and the size of that bill depends entirely on how much text goes in and comes out, a number that doesn't live in any Terraform file, exactly the same way "how many megabytes you're going to use this trip" doesn't live in your phone plan's contract.
Why this breaks the intuition the previous seven guides installed
Take a moment to review what every piece of Andes Cargo's infrastructure has taught you about cost so far:
THE COST-MODEL PROGRESSION ANDES CARGO ALREADY KNOWS
EC2 (named, not built in this ecosystem)
│ You pay per HOUR the instance exists.
│ 0 requests processed costs the same as 1 million.
▼
Lambda (process-shipment-manifest)
│ You pay per INVOCATION + DURATION.
│ 0 invocations = $0. Cost per invocation is predictable
│ (fixed memory × typical duration), even though the TOTAL
│ depends on how many invocations occur.
▼
DynamoDB PAY_PER_REQUEST (Shipments)
│ You pay per READ/WRITE UNIT.
│ Same pattern as Lambda: predictable cost per unit,
│ total depends on real volume.
▼
Bedrock (extract-shipment-manifest-fields, starting this module)
│ You pay per TOKEN, input and output, separately.
│ The cost of a SINGLE invocation is no longer fixed -- it
│ depends on how much text the arriving manifest has and how
│ much text the model generates in response. Not even the
│ "per unit" cost is a constant known in advance.
finops-and-cost-guardrails-guide already prepared you for half of this leap: Lambda and DynamoDB in on-demand mode are already usage-based — cost depends on how much real traffic occurs, not on how long the resource exists. That module, in its lesson 6, built infracost-usage.yml precisely to declare that volume and turn a rate into a number. Bedrock takes that same logic one step further, and this is the step that breaks something new: not even a single invocation's per-unit cost is a fixed constant. A Lambda call always bills the same formula (memory × typical duration); a Bedrock call bills according to that specific call's real content — a three-line manifest costs a fraction of what a three-paragraph one costs, even though both are, technically, "one invocation." This module's lesson 6 comes back to this exact point, with the precise vocabulary for why that leaves Infracost with no Terraform resource to point at.
What this module does NOT do yet
This lesson, and the two that follow, are deliberately conceptual — a pricing landscape, a quota landscape. No command runs yet against andes-cargo-infra/. That starts in lesson 4, with inherited Infracost, and goes deeper in lesson 5, with the real attempt of infracost scan against a freshly declared bedrock.tf — the first one in this entire guide, because, as Module 1's close confirmed, bedrock.tf didn't exist yet at the end of the previous lesson. This guide doesn't build the AI workload's full infrastructure in this module — that's Module 3 — but it does need a minimal, deliberately small version, to be able to ask Infracost the honest question this entire module exists to answer.
Common mistakes
Assuming "usage-based" already means the same thing you learned with Lambda and DynamoDB, with no new nuance (premature generalization mistake). What happens: someone, familiar with DynamoDB's PAY_PER_REQUEST, assumes Bedrock is "the same thing, under another name" and jumps straight to building without reading lessons 2 and 3. How to spot it: if your expectation is that this module's lesson 7 is going to look, structurally, like finops-and-cost-guardrails-guide's infracost-usage.yml. How to fix it: there's a real, non-cosmetic difference — Lambda and DynamoDB have a fixed per-unit cost (even though the total depends on volume); Bedrock doesn't. A single Bedrock invocation's cost varies with that specific invocation's content. This module's lesson 6 formalizes exactly that difference.
Thinking "Bedrock charges per token" means there's a single price per token for the whole catalog (oversimplification mistake). What happens: someone reads "charges per token" and assumes that price is a universal constant, as if it were a single rate applying equally regardless of which model you invoke. How to spot it: if your question is "how much does a token cost in Bedrock?", without specifying which model. How to fix it: every family and size of model in Module 1, lesson 6's catalog (Nova Micro, Nova Lite, Nova Pro, Claude, Llama, Mistral) has its own price per million tokens, input and output separately — this module's lesson 2 cites the exact, verified figures, not memorized ones.
Confusing "no server to manage" with "nothing to cost" (misapplied serverless intuition mistake). What happens: someone, used to thinking of Lambda as "cheap because it's serverless," assumes Bedrock automatically inherits that same economy of scale. How to spot it: if your starting assumption is "since I don't manage a server, the cost is going to be marginal, just like with Lambda at low volume." How to fix it: the absence of a managed server (true for Bedrock, just as it is for Lambda) says nothing about the price per unit of work. A single token from a large model can cost orders of magnitude more than an entire Lambda invocation — Module 2, lesson 2 puts the exact figures side by side so this comparison stops being an intuition and becomes an informed decision.
Exercises
Exercise 1 — Explain, without using the word "on," the difference between EC2's cost model and Bedrock's. A colleague, familiar with EC2 but never with Bedrock, asks how a language model gets billed. Answer them in two sentences, without using the word "on" or "off."
See solution
A complete answer sounds, roughly, like this: "EC2 charges you for however long the instance exists, regardless of how much real work it did during that time. Bedrock has no concept of 'time it exists' — you don't provision it or release it — and it charges you instead for the amount of text you send it and it returns to you on each individual call, so the cost depends entirely on the content of what you're processing, not on how much time passes."
Exercise 2 — Locate where, in Andes Cargo's infrastructure progression, a cost that varies with the CONTENT of a single operation — not just its volume — first appears. Review this lesson's diagram (EC2 → Lambda → DynamoDB → Bedrock) and explain what sets the last step apart from the three before it.
See solution
Lambda and DynamoDB, even though they're usage-based (the total depends on how many invocations or requests occur), have a fixed per-unit cost: every invocation of process-shipment-manifest costs the same under Lambda's formula (configured memory × typical duration), and every PutItem in Shipments costs the same per write unit, regardless of what specific data that item contains. Bedrock breaks that: two invocations of extract-shipment-manifest-fields, both "a single call," can cost completely different amounts from each other if one manifest is longer than the other — the individual per-unit cost is no longer a constant, it depends on that specific call's content.
Exercise 3 — Predict what Andes Cargo is going to need to declare, beyond monthly volume, to estimate extract-shipment-manifest-fields's cost accurately. Based on this lesson's analogy (roaming, not a fixed plan), and without having read lesson 7 yet, what other piece of data — beyond "how many manifests per month" — do you think will need to be declared?
See solution
Beyond monthly volume (how many times the model gets invoked), you need the average size of each invocation — specifically, how many input tokens a typical manifest has and how many output tokens the model produces when responding with the extracted fields. It's exactly the roaming analogy taken to its logical conclusion: it's not enough to know "how many days you'll be traveling" (the monthly-volume equivalent), you also need to know "how many megabytes you consume per day" (the tokens-per-invocation equivalent) to be able to project a total. This module's lesson 7 builds the calculator with exactly those two axes — tokens per invocation and declared volume — as its explicit inputs.
Summary and next step
This lesson installed this module's central thesis: Bedrock's cost isn't "on = costs money," it isn't even exactly the same kind of usage-based you already knew from Lambda and DynamoDB — it's a cost that varies with each individual invocation's content, not just with how many invocations there are. You saw the full map of the eight lessons that follow, and the analogy that's going to run through them: international roaming, not a fixed monthly plan — you pay for what actually crosses the border, and nobody tells you the total until you do the math yourself.
Before moving on you should be able to: explain in one sentence why Bedrock breaks the "on = costs money" intuition even more than Lambda or DynamoDB; name this module's eight topics in order; and anticipate that you're going to need, at minimum, two different kinds of data (size per invocation, volume of invocations) to estimate a real cost.
Lesson 2 does the concrete work this lesson left at the intuition level: Bedrock's five real pricing models, with figures cited directly from AWS, verified at this very moment of writing — not memorized from an earlier version of that page.
Resources
- AWS — Amazon Bedrock Pricing — the source lesson 2 develops in detail.
finops-and-cost-guardrails-guide, Module 1 and Module 2 — the usage-based vocabulary foundation (infracost-usage.yml) this module extends one level further.ADR-001-llm-as-escalation-path.md(Module 1, lesson 8, this same guide) — the document that assigns this module the responsibility of fixing the escalation path's cost.