Bedrock mechanics: the model plane

Part 1 built an agent whose model was a stand-in. Part 2 takes the model's chair seriously. In the reference architecture this is the model plane: the layer where tokens are actually bought, and the layer whose physics (latency, cost, quotas, failure modes) every other plane inherits. This chapter covers the mechanics of talking to Bedrock at all: how requests authenticate, which of the three request styles to use, and how to read the model-id strings, which carry more architecture in them than they appear to.

A scope note before diving in: the decoder ring already covered what Bedrock is (vendor weights hosted on AWS silicon behind one API). This chapter is about using it well; nothing here requires re-reading that, but the "inference profile is routing, not a model" idea returns with force.

Getting in the door: there is no API key

The first difference from calling a model provider directly: Bedrock has no API-key header. Requests are signed with SigV4, AWS's request-signing scheme, using whatever AWS credentials the calling code already has: an EC2 or Lambda role, an SSO session, environment variables. The AWS SDKs and the Anthropic Bedrock client both do the signing invisibly, so in practice "auth" means "the code runs under an IAM identity that is allowed to invoke the model."

That sentence should trigger the concepts chapter's identity section, because it is the first concrete payoff of the principal-and-role vocabulary. Model access is an IAM permission (bedrock:InvokeModel on specific model or profile ARNs), which means which agents may use which models is policy, not code, and gate 1 of the production bar extends naturally over the model plane: a worker role can be allowed Haiku-class models and denied Opus-class ones, and no prompt can argue with that.

Three doors into the same models

Bedrock has accumulated three request styles, and knowing why each exists beats memorizing them:

DoorWhat it isUse it when
InvokeModelThe original: you POST each vendor's native JSON body, verbatimLegacy code, or a vendor feature the uniform APIs have not wrapped yet
ConverseOne uniform request shape (messages, tools, streaming) across every hosted vendorMulti-vendor systems; you want to swap models without rewriting request code
The Anthropic-native endpoint (Mantle)Bedrock serving Anthropic's own Messages API shape directly, for Claude Opus 4.7 and laterClaude-first systems; you want the Anthropic SDK's ergonomics with AWS auth and billing

The third door deserves the extra sentence, because it is the newest and the one this book defaults to. For recent Claude models, AWS serves the same Messages API that Anthropic serves first-party, reached through Anthropic's own SDK with a Bedrock-flavored client class. Same request shape, same response objects, different transport and billing. The practical consequence is pleasant: everything Part 1 built against the model interface, and every Anthropic-documented pattern, carries over with a changed constructor.

Reading the id strings

Model ids on Bedrock are dense little architecture documents, and there are two dialects, one per era:

The classic dialect (InvokeModel and Converse) looks like this:

global.anthropic.claude-opus-4-5-20251101-v1:0
\____/ \_______/ \____________/ \______/ \__/
routing  vendor      model        date   rev

The trailing date pins an exact model snapshot. The leading segment is the important one: it names an inference profile, the routing indirection from the decoder ring. us. spreads your traffic across US regions, eu. across European ones (a data-residency statement as much as a capacity one), and global. across everything, which is the largest capacity pool and the strongest answer to a single region having a bad day. A bare id with no prefix targets one region only, and for the newest models often is not offered at all: AWS increasingly publishes new Claude models behind profiles only, because pooled capacity is the only way to serve launch demand.

The Mantle dialect (Claude Opus 4.7 and later) is shorter: anthropic.claude-opus-4-8. Undated, unprefixed: the vendor prefix plus Anthropic's own model alias, with routing handled behind the endpoint rather than in the string. The book's examples use this dialect for Claude and the classic one only where required.

Don't be confused: model id vs inference profile id. A model id names weights ("Claude Opus 4.5, the 2025-11-01 snapshot"). An inference profile id names a routing arrangement over capacity that serves those weights. The classic dialect gluing them into one string blurs a real distinction: when you call global.anthropic..., "which model" is fixed but "which region answers" is decided per request. Capacity planning, quota accounting, and residency all attach to the profile, not the snapshot.

The other door entirely: Claude Platform on AWS

One more distinction, because it costs teams real confusion. Besides Bedrock, Anthropic operates its own full API on AWS infrastructure, called Claude Platform on AWS: bare first-party model ids (claude-opus-4-8, no anthropic. prefix), SigV4 auth, AWS Marketplace billing, and same-day feature parity with Anthropic's first-party API because Anthropic runs the service.

Amazon BedrockClaude Platform on AWS
Operated byAWSAnthropic
ModelsMany vendorsClaude only
Model idsanthropic.-prefixedBare (claude-opus-4-8)
Feature surfaceAWS's release schedule; some first-party features absentFull first-party API, same-day
Fits whenMulti-vendor strategy, deep AWS-service integration (Guardrails, AgentCore)Claude-first, want every newest API feature with AWS-native auth and billing

Both are legitimate for this book's architectures; the capstones use Bedrock because the surrounding chapters lean on its ecosystem, and each time a first-party-only feature matters, the text says so.

Lab 2.3, part one: first calls

This lab touches real AWS, so it is tier T1 follow-along: the code is exact, the outputs below are illustrative (typical shapes, not captured runs), and it costs cents. Prerequisites: an AWS account with Bedrock model access granted in the console, credentials in the environment, and pip install boto3 anthropic.

Through the Converse door, with the AWS SDK:

import boto3

bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")

response = bedrock.converse(
    modelId="global.anthropic.claude-opus-4-5-20251101-v1:0",
    messages=[{"role": "user",
               "content": [{"text": "One sentence: what is a microVM?"}]}],
    inferenceConfig={"maxTokens": 200},
)
print(response["output"]["message"]["content"][0]["text"])
print(response["usage"])
(illustrative)
A microVM is a lightweight virtual machine that provides
hardware-level isolation while booting in milliseconds with minimal
memory overhead.
{'inputTokens': 17, 'outputTokens': 33, 'totalTokens': 50}

Through the Mantle door, with the Anthropic SDK's Bedrock client:

from anthropic import AnthropicBedrockMantle

client = AnthropicBedrockMantle(aws_region="us-east-1")

response = client.messages.create(
    model="anthropic.claude-opus-4-8",
    max_tokens=200,
    messages=[{"role": "user",
               "content": "One sentence: what is a microVM?"}],
)
print(response.content[0].text)
print(response.usage)
(illustrative)
A microVM is a stripped-down virtual machine that keeps a VM's strong
isolation boundary while starting in about a tenth of a second.
Usage(input_tokens=17, output_tokens=36, ...)

Two details worth noticing even without running anything. First, the usage block: every response reports exactly what you were billed for, and those fields become load-bearing next chapter, when they are how cache behavior is verified. Second, how little separates this from Part 1: swap the ScriptedModel for either client, adapt the message shapes, and the loop investigates for real. The model plane slots in under everything already built, which was the point of building the interface first.

👉 Next: prompt caching, where the model plane's biggest cost lever gets mechanics, prices, and a lab that re-bills one agent session four different ways.