The GenAI Developer on AWS: Bedrock, Models, and Your First Converse Call (AWS GenAI Developer Pro, Module 1)

Module 1 of 16 14 min read D1 · 31% Lab code ↗

This is Module 1 of AWS GenAI Pro Mastery, a free 16-module course that takes you from your first Amazon Bedrock call to AWS-certified.

A developer on the CloudCart team gets a Jira ticket: “Add AI to the support workflow.” That’s the whole spec. She opens the AWS console, navigates to Bedrock, and the ground tilts. There’s Amazon Bedrock, but also SageMaker AI, and Amazon Q Business, and roughly eighty-five models in a catalog that scrolls forever. She finds a 2024 tutorial, follows it, and step two tells her to click a “Request model access” button that no longer exists. Step four pastes a JSON payload that returns an error she’s never seen.

This is the real starting line for most cloud developers in 2026. Everyone is “doing GenAI.” Almost nobody starts cleanly on AWS — with a secured account, the right call path, and a model chosen on purpose. This course fixes that by building one real thing, end to end: Relay, a production-grade GenAI support agent. This module lays the first stone — a healthy account and a first Converse call that works.

In this module

  • You’ll learn to delimit the GenAI developer role (integrate models, don’t train them), map Amazon Bedrock and its call path, assess a model family without the marketing, and prove feasibility with a minimal lab before committing to any architecture.
  • You’ll build a secured, budget-alarmed AWS account and hello_bedrock.py — your first Converse call to Amazon Nova, with token and cost reporting.
  • Exam domains covered: D1 — Foundation Model Integration, Data Management, and Compliance — 31% of the exam. Modules 1–6 share D1; this module covers Task 1.1 and skill 1.2.1.
  • Prerequisites: solid Python, the basics of any LLM API, an AWS account, and basic IAM/CLI. This course does not teach AWS from scratch — see the “AWS in 30 minutes” box in the lab if you’re missing the account.

The series: from your first Bedrock call to certified

You are at the start of a 16-module course. The destination is the AWS Certified Generative AI Developer - Professional (AIP-C01) exam, and the vehicle is Relay. Here is the promise in one line, the same one CloudCart’s developer needed: Relay is a production-grade GenAI support agent: a customer ticket comes in, Relay triages it, answers from your docs with citations, takes safe actions in your business systems, and escalates to a human when needed — guarded, evaluated, monitored, and cost-optimized on AWS.

CloudCart is the fictional SaaS e-commerce company you’ll work for. It sells a hosted online-store platform to small merchants and gets a steady stream of support tickets — email, chat, sometimes a screenshot of a broken checkout. Relay handles them. You build it brick by brick, and each brick maps to a chunk of the exam blueprint:

Exam domainWeightModules
D1 — Foundation Model Integration, Data Management, and Compliance31%M1–M6
D2 — Implementation and Integration26%M7, M8, M11 (+ routing/streaming in M3)
D3 — AI Safety, Security, and Governance20%M9, M10
D4 — Operational Efficiency and Optimization for GenAI Applications12%M12, M14
D5 — Testing, Validation, and Troubleshooting11%M13, M14
SynthesisM15 capstone, M16 mock exam

Here is the target architecture — the map you’ll fill in. Each block is annotated with the module that builds it. Today you build none of it; you build the account and the first call that everything below depends on.

flowchart TD
    T["Customer ticket<br/>email / chat &plusmn; screenshot"] --> API["API Gateway + Lambda<br/>(M11)"]
    API -->|SQS async| INTAKE["Intake pipeline (M6)<br/>validate &rarr; normalize &rarr;<br/>PII redaction (M10) &rarr; vision read"]
    INTAKE --> AGENT["Relay agent &mdash; Strands (M7)<br/>on AgentCore Runtime (M8)<br/>triage (M2) &middot; model router (M3)"]
    AGENT --> KB["Bedrock Knowledge Base (M5)<br/>S3 docs + S3 Vectors (M4)"]
    AGENT --> SYS["CloudCart systems &mdash; DynamoDB<br/>relay-orders &middot; relay-tickets (M7)"]
    AGENT -->|refund &rarr; HITL approval (M8)| HUMAN["Human reviewer<br/>routed via EventBridge relay-events (M11)"]
    GUARD["Guardrails (M9) &middot; Security/IAM (M10)<br/>Cost (M12) &middot; Evals (M13) &middot; Observability (M14)"] -.cross-cutting.- AGENT

Cheap, not free — the honest cost

Amazon Bedrock has no unlimited free tier, so this course is up front about money: cheap, not free. The whole 15-lab build costs roughly $20–25 total at June 2026 prices, and every module prints its own measured spend. Today’s lab cost me $0.00003 — the total of two hello_bedrock.py runs plus one live test call.

Three rules keep it cheap. First, every lab ships a teardown.py that removes anything billing while idle — Module 1 leaves nothing idle-billed. Second, no lab provisions the expensive traps (OpenSearch Serverless at ~$174/month, provisioned throughput, idle SageMaker endpoints); those are taught as exam theory, never run. Third, you set a budget alarm today, before the first token — a $5 monthly AWS Budget that emails you at 80%. That alarm is the one thing this module leaves behind on purpose; it guards every later module’s spend.

What the AIP-C01 actually validates

Before you write any code, get the role right, because the exam is built around it. Per the official AIP-C01 exam guide, the certification “validates a candidate’s ability to effectively integrate foundation models (FMs) into applications and business workflows.” A foundation model (FM) is a large pre-trained model — text, multimodal, or embeddings — that you consume through an API rather than build. You are an integrator, not a model builder.

That distinction is not decoration; the exam guide lists what is explicitly out of scope for the target candidate: model development and training, advanced ML techniques, and data engineering and feature engineering. If a question hinges on training a model, tuning a loss function, or building a feature store, it’s testing whether you know that’s not your job. The correct answer integrates an existing FM.

This also sets the cleanest mental model in AWS GenAI: Amazon Bedrock vs SageMaker AI. Bedrock is how you integrate FMs through a managed API — no servers, no model lifecycle. SageMaker AI is how you build and host ML — training, endpoints, the full pipeline. As a GenAI developer you live in Bedrock. SageMaker AI appears in the exam only at the edges (fine-tuning, custom deployment), and even then it’s the heavy path you reach for last.

Logistics so you can plan. From the exam guide: 75 questions (65 scored, 10 unscored), a scaled score of 100–1000 with a passing score of 750, and compensatory scoring — there’s no per-section minimum, you just need to pass overall. From the AWS certification page: 180 minutes, $300 USD, delivered via Pearson VUE. Two question types are new versus classic AWS certs — ordering (place 3–5 steps in sequence) and matching (pair 3–7 items) — and you’ll drill them explicitly in Module 16.

Amazon Bedrock in one map

Amazon Bedrock is a fully managed service that serves foundation models behind one API — serving, scaling, and security on its side; the request and the bill on yours. The catalog is large — roughly eighty-five models as of June 2026, spanning Amazon Nova, Anthropic Claude, Meta Llama, and Mistral. You don’t memorize the catalog; you learn the call path, because it’s identical across all of them.

That uniform call path is the Converse API — the single, model-agnostic interface for text generation on Bedrock. One message shape (system, messages with role and content blocks, inferenceConfig) works for Nova, Claude, Llama, every chat-capable model. Switch models by changing one ID; the request body does not change. (Its streaming sibling, ConverseStream, arrives in Module 3.)

InvokeModel comparison (read-only — the only time this course shows it). Before Converse existed, you called each model with bedrock_runtime.invoke_model() and a model-specific JSON body: Nova, Claude, and Llama each had a different payload and a different response shape, so swapping models meant rewriting your integration. Converse replaced all of that with one unified shape. The only place this entire course uses invoke_model is Titan embeddings in Module 4 — Converse cannot embed, and embeddings return a vector, not text. For text generation: always Converse.

Now the single most important operational fact in this module, and the one old tutorials get wrong. On-demand is the pay-per-token invocation mode you use by default (the alternative, provisioned throughput, reserves capacity for a flat hourly fee). And recent models cannot be invoked on-demand with a bare regional model ID. You must use an inference profile — an ID prefixed us., eu., or global. (for example us.amazon.nova-lite-v1:0) that routes your request across a Region group for capacity. Pass the bare ID amazon.nova-lite-v1:0 and the call fails with “Invocation of model ID … with on-demand throughput isn’t supported. Retry with an inference profile.” Inference profiles are also how cross-Region inference works, which you’ll lean on in Module 3. For now, the rule is absolute: every model ID is an inference profile (us./global.), never a bare regional ID.

One bridge for readers coming from OpenAI or from this catalog’s first course: Bedrock added OpenAI-compatible “chat completions” endpoints (informally bedrock-mantle) in late 2025. They’re a handy conceptual on-ramp, but they are not the AWS path the exam tests. We use Converse throughout.

Here’s the call path you build today, region pinned to us-east-1:

flowchart LR
    APP["Your code<br/>hello_bedrock.py"] --> B["boto3 client<br/>bedrock-runtime"]
    B --> C["converse()<br/>system + messages + inferenceConfig"]
    C --> P["Inference profile<br/>us.amazon.nova-lite-v1:0"]
    P --> FM["Foundation model<br/>Amazon Nova Lite"]
    FM -->|reply + usage tokens| APP
    P -.->|cross-Region routing<br/>detailed in M3| P2["Region group<br/>(us-east-1 + siblings)"]

Choosing a model without the marketing

The leaderboard is not a selection method. Per skill 1.2.1, you choose an FM against your use case using concrete criteria: capability for the task, latency, price in and out, context window, modalities (text, vision, embeddings), and regional availability. A support-ticket triage classifier and a legal-summary generator have completely different right answers.

Here are the models this course uses, with on-demand us-east-1 prices as of June 2026 (re-verify on the Bedrock pricing page — published GenAI prices move):

Model (inference profile)$/M in$/M outContextStrengthRelay role
Nova Micro (us.amazon.nova-micro-v1:0)0.0350.14128KCheapest text, fastTriage, router, tests (M2–M3)
Nova Lite (us.amazon.nova-lite-v1:0)0.060.24300KCheap + visionThis lab; screenshots (M6)
Nova 2 Lite (us.amazon.nova-2-lite-v1:0)~0.30~2.501MTunable reasoningComplex answers, agent (M5–M7)
Claude Haiku 4.5 (us.anthropic.claude-haiku-4-5-20251001-v1:0)15200KStrong, balancedLLM-as-a-judge (M13)
Claude Sonnet 4.5 (us.anthropic.claude-sonnet-4-5-20250929-v1:0)315200KFrontier reasoningFrontier option (table / Try-it only)

Notice the spread: output tokens on Sonnet cost over a hundred times more than on Nova Micro. That’s why model choice is an engineering decision, not a taste. Here’s an opinion I’ll defend with the numbers: Relay’s triage will run on Nova Micro. At $0.035 per million input tokens, classifying a ticket’s intent is so close to free that being occasionally wrong costs nothing. Save the frontier models for the work that needs them.

(Two traps in that table. Nova Lite ≠ Nova 2 Lite — different models, different price tiers, different jobs. And Anthropic’s published Claude prices have shown ambiguity between older and current generations, so the figures above are the verified current-generation numbers — confirm on the pricing page the day you choose.)

⚠️ Common misconception: “you must request model access in the console first”

Old tutorials open with a “Model access” console screen where you tick boxes and click Request model access before any model will respond. That step is gone — removed in October 2025. Serverless foundation models now auto-activate: the Nova Lite call in today’s lab works the moment your credentials and IAM allow it, with no console pre-step. The one survivor is a single one-time use-case form for Anthropic Claude (submitted in the console under Model access, or via the PutUseCaseForModelAccess API). Submit it today so Claude is ready for later modules — the Module 13 judge especially. If a tutorial tells you to hunt for “Request model access,” it predates this course and is wrong.

Prove it works first: the PoC discipline

When CloudCart’s developer got “add AI to the support workflow,” the wrong first move was an architecture diagram. The right first move is a proof of concept (PoC) — a minimal, throwaway implementation that proves the chain is feasible before anyone commits to design. The exam guide names this directly in skill 1.1.2: develop technical proof-of-concept implementations to validate feasibility, performance characteristics, and business value before proceeding to full-scale deployment. It even names the tool: Amazon Bedrock.

hello_bedrock.py is that PoC pattern. It answers the only three questions that matter before you build anything: can my credentials reach Bedrock, does a model respond usefully to a CloudCart question, and what does a call cost? About forty lines of real call logic validate the entire chain — credentials → bedrock-runtime client → Converse → an FM → real tokens and a real (tiny) bill. If it works, you’ve de-risked every later module. If it doesn’t, you found out for a fraction of a cent instead of after a sprint of architecture.

One more thread the exam pulls, parked here for later: skill 1.1.3 expects you to standardize components for consistent deployments, and points at the AWS Well-Architected Framework and its Generative AI Lens — the official set of GenAI-specific best-practice questions across reliability, cost, security, and operations. You’ll run a full Generative AI Lens review at the capstone in Module 15; for now, just know the name, because it’s the lens through which AWS grades a “good” GenAI architecture.

Build it: secure the account, make the first call

Goal: prepare a secured, budget-alarmed AWS account for the whole course, then validate the full chain with a first Converse call to Amazon Nova Lite. At the end, running one command prints a model reply and a tokens: ... | est. cost: $0.000NN line. Region is us-east-1 throughout. Full code lives in module-01/; excerpts below.

AWS in 30 minutes (only if you’re starting from zero)

This course does not re-teach AWS basics. If you don’t yet have an account, an IAM user, and a working CLI, spend 30 minutes here first:

  • Create an AWS accountaws.amazon.com/free (then put MFA on the root user and never use it again).
  • Create a course IAM user/roleIAM user guide.
  • Install and configure the AWS CLI (aws configure --profile aws-genai-pro) — CLI setup guide.

Everyone else: continue.

Step 1 — A least-privilege identity, no keys in code

Use a course-only IAM user or role, never the root user, and never a hardcoded key. The lab ships a least-privilege policy in iam/course-policy.json that grants only what Module 1 needs — bedrock:Converse, ConverseStream, InvokeModel, and InvokeModelWithResponseStream scoped to Nova and Claude profiles, plus the Bedrock catalog reads, AWS Budgets, SNS, and sts:GetCallerIdentity (each statement’s rationale is in iam/course-policy.md). The JSON carries no comments on purpose: IAM’s grammar is strict and aws iam create-policy rejects any unrecognized key. The code reads no key from a file: boto3 uses the default session, which respects AWS_PROFILE if set, otherwise your default credentials. There is no .env for AWS anywhere in this course.

Step 2 — Budget alarm before the first token

setup.py is idempotent and verbose — safe to run twice, and it tells you exactly what it creates and what it costs ($0; AWS Budgets gives two budgets free). The core of it:

budget_def = {
    "BudgetName": "aws-genai-pro-monthly",
    "BudgetLimit": {"Amount": "5.0", "Unit": "USD"},
    "TimeUnit": "MONTHLY",
    "BudgetType": "COST",
}
notification = {
    "NotificationType": "ACTUAL",
    "ComparisonOperator": "GREATER_THAN",
    "Threshold": 80.0,          # email me at 80% of $5
    "ThresholdType": "PERCENTAGE",
}
try:
    budgets.create_budget(
        AccountId=account_id, Budget=budget_def,
        NotificationsWithSubscribers=[
            {"Notification": notification, "Subscribers": [subscriber]}
        ],
    )
except ClientError as err:
    if err.response["Error"]["Code"] != "DuplicateRecordException":
        raise
    budgets.update_budget(AccountId=account_id, NewBudget=budget_def)  # idempotent

Run it with your email:

export RELAY_BUDGET_EMAIL="you@example.com"
uv sync
uv run python setup.py

The same script reports model access: it confirms the Nova family auto-activates (no console step) and reminds you to submit the one-time Anthropic use-case form now.

Step 3 — The Converse call

Here is the heart of the lab. The model ID is a single top-of-file constant — provisional, because from Module 3 onward relay/config.py becomes the sole home of every model ID in the course. Note the us. prefix: that’s the inference profile, not a bare regional ID.

MODEL_ID = "us.amazon.nova-lite-v1:0"   # inference profile, NOT a bare regional ID

# One-line system prompt. Real prompt engineering is Module 2.
SYSTEM_PROMPT = (
    "You are a concise support assistant for CloudCart, a hosted e-commerce "
    "platform that lets small merchants run online stores. Answer in 2-3 sentences."
)

# boto3 default session: respects AWS_PROFILE if set, else default creds.
client = boto3.client("bedrock-runtime", region_name="us-east-1")

response = client.converse(
    modelId=MODEL_ID,
    system=[{"text": SYSTEM_PROMPT}],
    messages=[{"role": "user", "content": [{"text": question}]}],
    inferenceConfig={"maxTokens": 300, "temperature": 0.2},
)

The cost line is computed from the API’s own usage block times a documented per-token price — never guessed:

PRICE_PER_1K_INPUT = 0.00006    # $0.06 per million input tokens (Nova Lite)
PRICE_PER_1K_OUTPUT = 0.00024   # $0.24 per million output tokens

reply = response["output"]["message"]["content"][0]["text"]
usage = response["usage"]
cost = (usage["inputTokens"] / 1000 * PRICE_PER_1K_INPUT
        + usage["outputTokens"] / 1000 * PRICE_PER_1K_OUTPUT)
print(reply.strip())
print(f"\ntokens: in={usage['inputTokens']} out={usage['outputTokens']} "
      f"| est. cost: ${cost:.5f}")

There is no silent try/except. The one failure mode worth teaching in Module 1 is the inference-profile trap, so the real script catches ValidationException and prints the exact fix (use the us. profile) rather than swallowing it. Run it:

uv run python hello_bedrock.py "What does CloudCart sell?"

Real output from my run (yours will differ in wording and counts):

CloudCart is a hosted e-commerce platform that enables small merchants to create
and manage their online stores. It doesn't sell products directly but provides
tools and services for merchants to sell their own products online.

tokens: in=38 out=43 | est. cost: $0.00001

That $0.00001 is the whole point of the cost discipline: the call is real, the bill is real, and it’s a hundredth of a cent.

Step 4 — Feel the parameters, then prove the unified shape

Re-run with RELAY_TEMPERATURE=0.0 uv run python hello_bedrock.py (deterministic, near-identical answers) versus RELAY_TEMPERATURE=0.9 (more varied phrasing), and watch the token counts and the cost line move with the answer length. (Temperature is read from the environment so you can experiment without editing the file — the offline test pins the default 0.2.) Then the payoff: once the Anthropic form is approved, change one line — MODEL_ID = "us.anthropic.claude-haiku-4-5-20251001-v1:0" — and re-run. The request body doesn’t change at all. That is the Converse promise made concrete: one shape, every model.

Step 5 — Tests and teardown

The lab’s tests are offline by default — a botocore Stubber fakes the Converse response, so uv run pytest runs with no credentials and no network call. One test is marked live and makes a single real sub-cent call only when you opt in with RELAY_LIVE_TESTS=1. Then confirm the account is clean:

uv run python teardown.py

It asserts there is no idle-billed resource (there isn’t — Module 1 made only pay-per-token calls and a free budget) and keeps the budget on purpose. At the very end of the whole course you’ll run teardown.py --delete-budget.

Try it yourself. (1) Point MODEL_ID at Nova Micro and compare the cost line for the same question — that’s your triage model. (2) Lower NOTIFY_THRESHOLD_PCT in setup.py to 50.0 to get alerted at $2.50 instead of $4.00.

In production

A real production account looks nothing like this lab, and the gaps are exam-relevant. You don’t budget with a single $5 alarm — you use Cost Anomaly Detection to catch a runaway agent automatically, plus per-environment budgets. You don’t grant one IAM user broad Bedrock access — you use Service Control Policies at the org level and a least-privilege role per service, so the ticket-intake Lambda can’t touch the orders table. Identity is federated, not a long-lived key.

On-demand throughput is not infinite, either. Bedrock enforces per-model request and token quotas, and at scale you manage them through Service Quotas — requesting increases ahead of a launch, or moving hot paths to provisioned throughput for guaranteed capacity. Model selection stops being one-time, too: the catalog ships new models constantly, so you re-benchmark your tier choices on a cadence and keep a model card recording why each tier runs what it runs.

And the single hardcoded MODEL_ID at the top of hello_bedrock.py? In production that’s a liability — a model ID buried in application code means a swap is a code change and a redeploy. In Module 3, Relay gets a routing layer (relay/config.py + relay/llm.py) so that swapping models, or failing over across Regions, never touches application code.

Exam corner

What the exam tests here. This module sits in D1 (31% of the exam) and covers Task 1.1 and skill 1.2.1: knowing the GenAI developer role is integration, not training; choosing Bedrock over SageMaker AI for FM integration; validating with a PoC before committing to architecture; and selecting a model on concrete criteria — including the inference-profile requirement for recent models.

Five scenario questions in the style of the exam. Answers and explanations follow all five.

1. A team wants to “build our own model” to classify CloudCart support tickets into five standard intents. As the GenAI developer, what do you recommend, and why? A. Train a custom classifier in SageMaker AI from labeled tickets. B. Fine-tune a foundation model on the ticket history before doing anything else. C. Build a PoC that calls an existing FM on Amazon Bedrock to classify the intents, and measure it. D. Stand up a feature-engineering pipeline to extract ticket features first.

2. A requirement reads: “integrate a foundation model through an API, with no ML lifecycle to manage and no infrastructure to run.” Which service fits? A. Amazon SageMaker AI, with a real-time endpoint. B. Amazon Bedrock, via the Converse API. C. Amazon EC2 with a self-hosted model. D. Amazon Comprehend custom classification.

3. Leadership demands a full architecture and deployment plan for Relay before any code is written. What’s the most defensible first step? A. Deliver the complete production architecture diagram and a capacity plan. B. Build a minimal proof of concept that validates feasibility and business value at near-zero cost, then design from what you learned. C. Provision OpenSearch Serverless and a knowledge base so retrieval is ready. D. Request provisioned throughput so latency is guaranteed from day one.

4. Relay’s triage step must classify ticket intent under tight latency and a tight budget; the task is simple classification. Which model is the best default? A. A frontier reasoning model, for maximum accuracy. B. The smallest, cheapest fast-tier model (e.g., Nova Micro), accepting occasional errors. C. A vision model, in case a screenshot is attached. D. Whatever ranks highest on the public leaderboard this week.

5. A Converse call fails with: “Invocation of model ID amazon.nova-lite-v1

with on-demand throughput isn’t supported. Retry with an inference profile.” What’s the fix? A. Submit a “request model access” form in the console. B. Switch from Converse to InvokeModel with a model-specific payload. C. Change modelId to the inference profile us.amazon.nova-lite-v1:0. D. Request a quota increase via Service Quotas.

Answers. 1 → C. Training, fine-tuning, and feature engineering are all out of scope for the GenAI developer role; the right move is to integrate an existing FM and prove it with a PoC. 2 → B. Bedrock is FM integration via API with no infrastructure or ML lifecycle; SageMaker AI is for building/hosting ML. 3 → B. Skill 1.1.2: a PoC validates feasibility, performance, and business value before full-scale deployment — A commits too early, C and D spend money before feasibility is known. 4 → B. Simple classification under tight latency and budget is exactly the fast-tier case; at fractions of a cent, occasional errors are cheap, and the leaderboard is not a selection criterion. 5 → C. Recent models require an inference profile on-demand; the bare regional ID is the cause. A is the dead Oct-2025 step, B is the legacy call path, D doesn’t address a validation error.

Traps to avoid.

  • Hunting for a “Request model access” step. It disappeared in October 2025; only the one-time Anthropic use-case form remains.
  • Reaching for InvokeModel with a model-specific payload as the default path. Converse is the unified, model-agnostic call path.
  • Treating the GenAI developer role as an ML role. The exam tests neither model training nor feature engineering — integration is the job.

Key takeaways

  • The GenAI developer role is to integrate foundation models into applications and workflows — not train them, not do feature engineering. The exam guide says so explicitly.
  • Converse is the unified call path for text generation on Bedrock; InvokeModel is legacy by default (used only once in this course, for Titan embeddings).
  • A modern model ID is an inference profile (us./global.). A bare regional ID fails on-demand with “Retry with an inference profile.”
  • Choose a model on concrete criteria — capability, latency, price in/out, context, modalities — not the leaderboard. Triage runs on the cheapest fast model on purpose.
  • Set the budget alarm before the first token, and tear down anything idle-billed. The course is cheap (~$20–25 total), not free.
  • PoC first. A ~40-line Converse call de-risks the whole architecture for a fraction of a cent.
  • Bedrock integrates FMs; SageMaker AI builds and hosts ML. Keep that line crisp — the exam loves it.

What’s next

Relay’s first real job is triage — turning a messy customer ticket into clean, validated JSON. You’ll write a versioned prompt in Bedrock Prompt Management, parse the model’s output into a Pydantic schema, and add a validation retry. That’s Module 2.

Want the full AIP-C01 question bank and the next module in your inbox? Subscribe here — it’s free, like everything in this series.

Links: Module 1 lab · Course index · Module 2 → · Coming from the agents course? See NCP-AAI Mastery.

References