AI EngineeringZero to ProductionHome·About·Contact
AWS AI Automation · Chapter W1

AWS AI foundations

AWS bundles AI into three layers — pre-built services, Bedrock, and SageMaker. This chapter gets you authenticated, in the right region, and oriented, so every later chapter is build, not setup.

⏱️ ~1 hour🧪 2 labs🎯 Beginner→Expert
🌱 Start here — from zero AWS AI, from scratch — you don't need to know AWS yet — this section builds it up from the first command.

AWS (Amazon Web Services) is a giant menu of computing services you rent by the hour or by usage. For AI, three items on that menu matter: Bedrock (call ready-made AI models like Claude), SageMaker (train/host your own models), and a set of pre-built AI APIs (read documents, images, speech). You talk to all of them from Python using a library called boto3. That's the whole picture — everything else is detail.

The words you'll hear (in plain terms):

TermWhat it actually means
BedrockAWS's way to call foundation models (incl. Claude) over an API — like the Anthropic API, but on AWS.
boto3the official Python library for talking to AWS. pip install boto3.
IAM role / credentialsAWS's way of proving who you are and what you're allowed to do — instead of a password in your code.
regionwhich AWS data-center location your service runs in (e.g. us-east-1).
Terraform / CDKtools that create cloud resources from a file, so setup is repeatable — introduced gently later.

What you need before starting:

  • Comfort with Python basics (the Python track covers this).
  • Having called Claude via the Anthropic API helps — Bedrock is the same idea.
  • An AWS account to actually run the labs (reading works without one).

New to the topic? Read this box, then take the chapters in order — each section is tagged essentialexpert so you always know the depth you're at.

⚙️ To run this for realThe code here is complete and correct as written. To actually execute it you'll need:
  • AWS credentials (aws configure) + Bedrock model access enabled in your region + pip install boto3
  • AWS credentials (aws configure) + pip install boto3
Reading and learning works without any of this — run when you're ready. IDs/ARNs in examples are placeholders; swap in your own.

Learning objectives

  • Explain how AWS packages AI: Bedrock (GenAI), SageMaker (ML platform), and the pre-built AI services.
  • Authenticate boto3 to AWS with the credential chain, profiles, and IAM roles — no keys in code.
  • Choose a region that has the models/services you need, and reason about the cost model.
  • Find where Claude fits: the same model you used via the Anthropic SDK, now behind Bedrock.
▶ Runnable companionEvery code block in this lesson is also a standalone file under code/aws1-foundations/ in the course, with a README on how to run it. Read here, run there — no need to copy-paste.

The AWS AI landscape in one map essential

AWS AI splits into three layers. From highest-level to lowest: pre-built AI services (call an API, no ML knowledge — Textract, Comprehend, Rekognition, Transcribe), Amazon Bedrock (managed access to foundation models incl. Claude, plus managed RAG, agents, and guardrails), and Amazon SageMaker (the full ML platform — train, tune, host your own models). This track covers all three, but leads with Bedrock because that is where the generative-AI automation lives.

Where this connectsYou already called Claude through the Anthropic SDK in Claude · the API. Bedrock is a second front door to the same Claude models, with AWS handling auth, billing, logging, and data residency. Everything you learned about prompts, tokens, and tool use carries over directly.

Authentication: the boto3 credential chain essential

boto3 (the AWS SDK for Python) never wants credentials hard-coded. It searches a chain: environment variables → shared config file (~/.aws/credentials profiles) → IAM role (on EC2/Lambda/ECS). In automation you almost always use an IAM role so there are no long-lived keys at all.

Example code for learning — review, test, and adapt it before running against real or production systems. Commands can create, change, or delete resources. See the Terms & Disclaimer.
Lab W1.1
check_auth.pyimport boto3

# The credential chain resolves automatically. On your laptop this uses a
# named profile; in Lambda/EC2 it uses the attached IAM role — same code.
session = boto3.Session(region_name="us-east-1")   # region where Bedrock has Claude

# Prove who we are (STS = Security Token Service) without needing any AI service.
sts = session.client("sts")
ident = sts.get_caller_identity()
print("account:", ident["Account"])
print("arn:    ", ident["Arn"])
▶ How this works

This tiny script answers one question before you touch any AI service: "Who does AWS think I am, and am I logged in?" It uses boto3 (the official AWS library for Python) to open a connection and ask AWS to identify you. If it prints an account number, your credentials work and every later lab will too.

  1. import boto3 pulls in the AWS SDK. You installed it with pip install boto3. It knows how to talk to every AWS service.
  2. boto3.Session(region_name="us-east-1") creates a session — a bundle of "who I am" plus "which data-center region I'm working in". You did not type any password or key here: boto3 finds your credentials automatically by walking the credential chain (environment variables → your ~/.aws/credentials profile → an IAM role if running on AWS). The same code works on your laptop and inside Lambda.
  3. session.client("sts") builds a client for STS (Security Token Service) — AWS's "identity desk". We pick STS on purpose because it needs no special permissions and touches no AI service, so it's the cleanest possible login test.
  4. sts.get_caller_identity() is the actual call over the network. It returns a small dictionary describing you; we read two fields from it and print them.

What the output means: Two lines: your 12-digit AWS account number, and your ARN (Amazon Resource Name — the unique string naming exactly which user or role you are). Seeing them means you're authenticated. An error like Unable to locate credentials instead means the chain found nothing — run aws configure first.

Try this: Change region_name to "us-west-2" and re-run — the account and ARN stay the same, because who you are is global; only where you work changed. Identity is not tied to a region.

Use a profile locallyRun aws configure --profile llm-course once, then boto3.Session(profile_name="llm-course", region_name="us-east-1"). Keep production on roles, never on keys.

Regions & model access intermediate

Not every model is in every region. Claude on Bedrock is broadest in us-east-1 and us-west-2. Before a model works you must enable model access once in the Bedrock console (Model access → request). This is a one-time, per-account, per-region step.

Lab W1.2
list_models.pyimport boto3

# List the foundation models your account can see in this region.
bedrock = boto3.client("bedrock", region_name="us-east-1")   # control-plane client
models = bedrock.list_foundation_models(byProvider="Anthropic")

for m in models["modelSummaries"]:
    print(m["modelId"], "-", m["modelName"])
anthropic.claude-3-5-sonnet-20241022-v2:0 - Claude 3.5 Sonnet
anthropic.claude-3-5-haiku-20241022-v1:0 - Claude 3.5 Haiku
anthropic.claude-3-opus-20240229-v1:0 - Claude 3 Opus
▶ How this works

Before you can call an AI model on Bedrock, you need to know which models your account is actually allowed to see in a region. This script asks Bedrock for that list, filtered to Anthropic's Claude models. Think of it as reading the menu before ordering.

  1. boto3.client("bedrock", region_name="us-east-1") creates a client for the bedrock service. Note this is the control plane — the part that manages and lists models. (A different client, bedrock-runtime, is what you'll use later to actually run a model. Don't mix them up.) This is also a shortcut for the session+client you saw in W1.1 rolled into one line.
  2. bedrock.list_foundation_models(byProvider="Anthropic") calls AWS and returns every foundation model from Anthropic that's visible in this region. byProvider is a filter so you don't get every vendor's models back.
  3. The result is a dictionary; the models live under the key "modelSummaries", which is a list. The for loop walks that list, and for each model m we print its modelId (the exact string you pass when calling it) next to its human-friendly modelName.

What the output means: One line per available Claude model — its machine ID and its name, e.g. anthropic.claude-3-5-sonnet-20241022-v2:0 - Claude 3.5 Sonnet. An empty list is the common gotcha: it usually means you haven't enabled model access yet in the Bedrock console for that region — a one-time step.

Try this: Copy one of the printed modelId strings — that exact value is what W2 passes to the bedrock-runtime client to send a real prompt. Also try removing byProvider="Anthropic" to see how many models other providers add to the menu.

Two different clientsbedrock is the control plane (manage models, guardrails, KBs). bedrock-runtime is the data plane (actually call a model). You will use bedrock-runtime for every inference call — that is W2.

The cost model advanced

Bedrock bills per token, like the Anthropic API, but on the AWS bill. Pre-built AI services bill per unit (per page for Textract, per minute for Transcribe). SageMaker endpoints bill per hour the instance is running — a real trap: an idle endpoint still costs money. The rule for automation: Bedrock and AI services are pay-per-use (scale to zero); SageMaker real-time endpoints are pay-per-hour (remember to delete them).

LayerBills byScales to zero?
Bedrock (models)input+output tokens✅ yes
AI services (Textract…)per page / minute / image✅ yes
SageMaker endpointinstance-hour❌ no — delete it

Exercise W1.1 — Prove your setup

Context: Nothing in the rest of this track works until your credentials resolve and Bedrock model access is enabled in the regions you'll use. Proving both up front saves you from debugging a permissions ghost three lessons later.

Your task: Write a script that prints your caller identity and the list of available Anthropic models in both us-east-1 and us-west-2; if a region's list is empty, enable model access in the console and re-run.

Requirements:

  • Print caller identity via sts.get_caller_identity()
  • For each region, list Anthropic foundation models with a bedrock control-plane client
  • Treat an empty model list as the signal to enable model access in that region's console
  • You're ready for W2 only when both regions return at least one Claude model

💡 Hint: Model access is per-region, so run the same listing code twice with different region names — a passing us-east-1 tells you nothing about us-west-2.

🪜 Practice ladder beginner → industry

Six graded exercises, easy to real-world. Try each before opening its solution.

Exercise 1 · Confirm your identity with STSBeginner

Context: Before you invoke a single model you need to know which identity AWS thinks you are — the same credential chain governs every Bedrock call, and a misresolved role is the most common reason a script that 'worked yesterday' suddenly gets AccessDenied.

Your task: Use a boto3 Session to resolve your credentials via STS and print the account id and ARN the chain landed on.

Requirements:

  • Create a boto3.Session with an explicit region
  • Call get_caller_identity() on an sts client
  • Print both the Account and the Arn fields from the response
  • Understand the resolution order: environment vars, then ~/.aws/credentials, then an attached IAM role

💡 Hint: STS doesn't grant anything — it just echoes whoever the credential chain already resolved, so this is a pure read-only identity check.

Show solution

The credential chain resolves env vars, then ~/.aws/credentials, then an IAM role. STS just echoes who you are.

import boto3

session = boto3.Session(region_name="us-east-1")
ident = session.client("sts").get_caller_identity()
print(ident["Account"], ident["Arn"])
Exercise 2 · List the available Anthropic modelsIntermediate

Context: Bedrock model access is opt-in per region: a fresh account can authenticate perfectly and still see zero Claude models until access is enabled. Listing what Anthropic models are actually available is the first thing to verify in any new region.

Your task: Use the Bedrock control plane to list foundation models from Anthropic and print each modelId.

Requirements:

  • Use the bedrock client (the control plane), not bedrock-runtime
  • Call list_foundation_models filtering to the Anthropic provider
  • Iterate modelSummaries and print each modelId
  • Recognize that an empty list means model access hasn't been enabled for that region yet

💡 Hint: There are two Bedrock clients for a reason — the one that lists models is not the one that runs them.

Show solution

bedrock (not bedrock-runtime) is the control plane. Model access must be enabled once per region.

import boto3

bedrock = boto3.client("bedrock", region_name="us-east-1")
resp = bedrock.list_foundation_models(byProvider="Anthropic")
for m in resp["modelSummaries"]:
    print(m["modelId"], "-", m["modelName"])
Exercise 3 · Control plane vs data planeAdvanced

Context: Bedrock splits cleanly into a control plane that manages models and a data plane that runs them, and confusing the two is a rite of passage: the call you want simply isn't a method on the client you reached for.

Your task: Explain, with a short boto3 sketch, which client manages models versus runs them, and why calling inference on the control-plane client fails.

Requirements:

  • Use bedrock for management operations like list_foundation_models
  • Use bedrock-runtime for inference such as converse / invoke_model
  • Show that calling converse on the bedrock client raises AttributeError because the method doesn't exist there
  • State the mental model plainly: control plane administers, data plane performs inference

💡 Hint: If the method you want throws AttributeError rather than a permissions error, you've almost certainly grabbed the wrong plane's client.

Show solution

bedrock administers (list/enable); bedrock-runtime performs inference. Calling converse on the control-plane client raises AttributeError.

import boto3

control = boto3.client("bedrock", region_name="us-east-1")          # manage
runtime = boto3.client("bedrock-runtime", region_name="us-east-1")  # run

control.list_foundation_models()          # OK on control plane
# control.converse(...)                    # AttributeError -- wrong client
runtime.converse(                          # inference lives here
    modelId="anthropic.claude-3-5-sonnet-20241022-v2:0",
    messages=[{"role":"user","content":[{"text":"hi"}]}],
)
Exercise 4 · An offline Bedrock cost estimatorExpert

Context: Bedrock bills per token, so cost is a simple linear function of two counts you already have from every response. A tiny local estimator lets you reason about spend without waiting for a bill or calling the API at all.

Your task: Given input/output token counts and per-1K prices, compute the dollar cost of one call, and demonstrate it for 1,200 input and 400 output tokens at $0.003 / $0.015 per 1K.

Requirements:

  • Cost = in_tok/1000 * in_per_k + out_tok/1000 * out_per_k
  • Input and output are priced separately — don't collapse them into one rate
  • The sample inputs total roughly $0.0096 ($0.0036 in + $0.0060 out)
  • Run entirely offline — no AWS credentials or network needed

💡 Hint: Prices are quoted per 1,000 tokens, so divide each count by 1000 before multiplying — the two products just add.

Show solution

Bedrock bills per token; cost is a linear function of the two token counts.

def call_cost(in_tok, out_tok, in_per_k, out_per_k):
    return in_tok/1000*in_per_k + out_tok/1000*out_per_k

c = call_cost(1200, 400, 0.003, 0.015)
print(round(c, 6))   # 0.0096  (0.0036 in + 0.0060 out)
Exercise 5 · Pick the layer for a taskProfessional

Context: AWS gives you three tiers of AI — pre-built services, managed foundation models on Bedrock, and self-hosted SageMaker — and picking wrong is usually a cost decision, not a capability one. Encoding the rule makes the trade-off explicit and reviewable.

Your task: Encode the layer choice as choose_layer(need_custom_model, task_is_narrow_prebuilt) returning 'prebuilt', 'bedrock', or 'sagemaker', and note each option's cost shape.

Requirements:

  • A narrow, pre-built task (Textract/Comprehend/Rekognition) short-circuits to 'prebuilt', pay-per-unit
  • Needing a custom trained/hosted model returns 'sagemaker', billed per instance-hour
  • Otherwise return 'bedrock' — managed FMs, pay-per-token
  • Capture the cost implication: pre-built and Bedrock scale to zero, a SageMaker real-time endpoint bills continuously and must be deleted
  • Run offline; verify all three branches with example inputs

💡 Hint: Order the checks so the cheapest, narrowest option wins first — only fall through to SageMaker when a custom model is genuinely required.

Show solution

Pre-built services and Bedrock scale to zero; a SageMaker real-time endpoint bills per instance-hour and must be deleted.

def choose_layer(need_custom_model, task_is_narrow_prebuilt):
    if task_is_narrow_prebuilt:
        return "prebuilt"     # Textract/Comprehend/Rekognition, pay-per-unit
    if need_custom_model:
        return "sagemaker"    # train/host your own; endpoint billed per hour
    return "bedrock"          # managed FMs, pay-per-token, scales to zero

print(choose_layer(False, True))   # prebuilt
print(choose_layer(True,  False))  # sagemaker
print(choose_layer(False, False))  # bedrock
Exercise 6 · A monthly Bedrock spend projector for capacity planningIndustry scenario

Context: Finance doesn't care about tokens — they care about the monthly bill and whether it blows the budget. Turning per-call token cost into a projected 30-day spend with a budget flag is exactly the artifact a capacity-planning review expects.

Your task: Given average tokens per request, requests per day, and the model's prices, project the 30-day Bedrock cost and flag whether it exceeds a supplied budget.

Requirements:

  • Compute a per-call cost from separate input/output per-1K prices (reuse the Expert-rung formula)
  • Scale it by requests-per-day and a configurable horizon (default 30 days)
  • Look prices up per model id (e.g. anthropic.claude-3-5-sonnet-20241022-v2:0) from a table
  • Return the per-call cost, the projected monthly total, and an over_budget boolean
  • Run offline — this is planning math, not a live API call

💡 Hint: Keep the horizon a parameter so the same function answers 'per week' or 'per quarter' — the budget comparison is just total > budget.

Show solution

Scale the per-call cost by daily volume and horizon; compare against the budget to drive an alert.

PRICES = {"anthropic.claude-3-5-sonnet-20241022-v2:0": (0.003, 0.015)}

def monthly_projection(model, in_tok, out_tok, reqs_per_day, budget, days=30):
    in_k, out_k = PRICES[model]
    per_call = in_tok/1000*in_k + out_tok/1000*out_k
    total = per_call * reqs_per_day * days
    return {"per_call": round(per_call, 6),
            "monthly": round(total, 2),
            "over_budget": total > budget}

print(monthly_projection("anthropic.claude-3-5-sonnet-20241022-v2:0",
                         in_tok=1500, out_tok=500, reqs_per_day=20000,
                         budget=5000))

✓ Checkpoint — you can move on when you can…

  • Name the three layers of AWS AI and give one service in each.
  • Explain the boto3 credential chain and why automation prefers IAM roles.
  • Describe the difference between the bedrock and bedrock-runtime clients.
  • State which AWS AI layer bills per hour and why that matters.

Knowledge check check yourself

✓ Knowledge check

What are the three layers of AWS AI, and where does calling Claude fit?

Show answer
The layers are pre-built services (Textract, Comprehend, Rekognition, Transcribe, no ML knowledge needed), Amazon Bedrock (managed access to foundation models including Claude, plus RAG/agents/guardrails), and Amazon SageMaker (a full platform to train/tune/host custom models). Calling Claude is a Bedrock task, using the bedrock-runtime data-plane client.
✓ Knowledge check

Why does the boto3 credential chain mean no keys in code, and what is the cost-model trap with SageMaker endpoints?

Show answer
boto3 resolves credentials automatically (env vars, then ~/.aws profile, then an attached IAM role), so the same code works on a laptop or in Lambda without embedding keys. The trap is that Bedrock and pre-built services scale to zero (pay per use), but a SageMaker real-time endpoint bills per instance-hour even when idle, so you must explicitly delete it or costs keep accruing.
© 2026 studybydoing.in · AI Engineering: Zero to Production · All rights reserved. · About · Privacy Policy · Terms · Contact
Educational content, provided as-is and without warranty. Code samples are examples — review, test, and adapt them before using in production. See the Terms of Use & Disclaimer. Use at your own risk.
© studybydoing.in