Deploy an AWS Architecture Advisor

Build and deploy a grounded Strands agent that recommends AWS hosting options.

Introduction

30 Second Summary

A confident recommendation is only useful when you can see where it came from. That matters when the choice shapes how a workload runs.

In this project, you will build an AWS Architecture Advisor using Strands Agents on Amazon Bedrock. You will ground its hosting recommendations in a controlled service catalog before deploying it to Amazon Bedrock AgentCore Runtime.

What You'll Build

Ask your deployed advisor where to host a stateful AI agent to watch it consult a controlled catalog before returning a concise recommendation with source URLs.

By the end of this project, you'll have:

  • A before-and-after test where the first recommendation lacks catalog evidence while the grounded version shows its sources.
  • A visible tool trace showing the advisor retrieve controlled guidance for AWS Lambda and AgentCore Runtime before it answers.
  • A deployed advisor you can invoke remotely to receive the same catalog-backed behavior you tested locally.
  • Secret Mission: a deterministic comparison tool that returns guidance for two catalog services in one call.

Are there any prerequisites?

You should be comfortable with Python and AWS fundamentals. You also need Windows plus an AWS account that can access Amazon Bedrock and assume the CDK bootstrap roles used for AgentCore deployment.

Before We Start

This first checkpoint helps you commit to building an AWS architecture advisor before any hands-on work begins. Your advisor will recommend AWS Lambda or Amazon Bedrock AgentCore Runtime using only a controlled service catalog.

Prepare Your Toolchain and Scaffold

Your advisor will eventually recommend AWS Lambda or Amazon Bedrock AgentCore Runtime. Exact tool versions keep its local and cloud workflows compatible.

You will confirm Python and AWS access first. You will then install the remaining command-line tools before AgentCore creates the project structure.

In this step, get ready to:
  • Confirm Python 3.13.15 and your authenticated AWS CLI identity.
  • Install the required Node.js, uv, and AgentCore CLI versions.
  • Create the CodeZip project scaffold on your Desktop.
Verify Python and AWS access

The advisor runs on Python 3.13.15. PowerShell gives you one place to verify Python and the AWS identity that AgentCore uses later.

  • Press the Windows key to open Windows search.
  • Type PowerShell into the search field.
  • Press Enter to open PowerShell.

You should see a PowerShell prompt where you can enter commands.

  • Check your installed Python version by running this command:
python --version

What Does This Check Do?

The command asks the active Python installation for its version. This reveals whether PowerShell can find the exact interpreter required by the project.

✔️ I see Python 3.13.15

Python is ready. Your advisor can use the project’s pinned Python 3.13.15 runtime.

ⓧ I see an older Python version

The older interpreter can cause dependency or deployment failures. Install the pinned version before continuing.

  • Download Python 3.13.15 using the official 64-bit Windows installer.
  • Run the downloaded installer.
  • Complete the installer using its recommended options.
  • Close PowerShell after the installation finishes.
  • Press the Windows key to reopen Windows search.
  • Type PowerShell into the search field.
  • Press Enter to reopen PowerShell.
  • Repeat the Python version check shown above. You should now see Python 3.13.15.

ⓧ Python is not found

PowerShell cannot reach a Python installation yet. The official installer adds the required interpreter to your Windows environment.

  • Download Python 3.13.15 using the official 64-bit Windows installer.
  • Run the downloaded installer.
  • Complete the installer using its recommended options.
  • Close PowerShell after the installation finishes.
  • Press the Windows key to reopen Windows search.
  • Type PowerShell into the search field.
  • Press Enter to reopen PowerShell.
  • Repeat the Python version check shown above. You should now see Python 3.13.15.

Still Seeing the Wrong Python Version?

Close every PowerShell window after installing Python. A new terminal reloads the Windows command path.

If the older version still appears, restart Windows before checking again.

Help me diagnose my Python version.

The next check reads the identity already configured in AWS CLI. It does not display secret access keys.

  • Verify the AWS identity available to AgentCore by running this command:
aws sts get-caller-identity

What Does This Check Do?

The command asks AWS Security Token Service which identity your configured credentials represent. A successful response proves that AWS CLI can authenticate to your account.

You should see identity details returned in PowerShell. That response confirms your AWS credentials are active.

AWS Identity Check Failing?

Confirm that AWS CLI has credentials configured for the account you plan to use. Expired credentials must be refreshed through your normal AWS sign-in method.

Help me fix my AWS identity check.

Install Node.js, uv, and AgentCore CLI

Node.js provides the package manager used to install AgentCore CLI. uv manages the Python environment and dependencies used by the generated agent.

Each tool is pinned to a known version. This keeps your scaffold aligned with the commands used throughout the project.

  • Visit the official Node.js download page.
  • Download the official Windows Installer for Node.js v24.21.0 LTS.
  • Run the downloaded installer.
  • Complete the installer using its recommended options.
  • Close PowerShell after the installation finishes.
  • Press the Windows key to reopen Windows search.
  • Type PowerShell into the search field.
  • Press Enter to reopen PowerShell.
  • Check the installed Node.js version by running this command:
node --version

What Does This Check Do?

The command reports the Node.js version available in your current PowerShell session. AgentCore CLI requires Node.js 20 or later.

✔️ I see v24.21.0

Node.js v24.21.0 LTS is ready. PowerShell can now use its package manager to install AgentCore CLI.

ⓧ I see an older Node.js version

Your current Node.js installation is below the project pin. Upgrade it with the official Windows Installer.

  • Return to the official Node.js download page.
  • Download the Windows Installer for Node.js v24.21.0 LTS.
  • Run the installer to upgrade Node.js.
  • Close PowerShell after the upgrade finishes.
  • Reopen PowerShell through Windows search.
  • Repeat the Node.js version check shown above. You should now see v24.21.0.

ⓧ Node.js is not found

PowerShell cannot reach Node.js yet. Install the pinned LTS release before continuing.

  • Return to the official Node.js download page.
  • Download the Windows Installer for Node.js v24.21.0 LTS.
  • Run the downloaded installer.
  • Close PowerShell after the installation finishes.
  • Reopen PowerShell through Windows search.
  • Repeat the Node.js version check shown above. You should now see v24.21.0.

Node.js Version Still Missing?

A PowerShell window opened before the installation may still hold the old command path. Close every terminal window before checking again.

Help me fix my Node.js installation.

  • Install uv 0.12.13 by running this pinned installer command:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/0.12.13/install.ps1 | iex"

What Does This Command Do?

The command downloads the official Windows installation script for uv 0.12.13. PowerShell executes that script to install the pinned release.

  • Close PowerShell after the uv installer finishes.
  • Press the Windows key to reopen Windows search.
  • Type PowerShell into the search field.
  • Press Enter to reopen PowerShell.
  • Confirm that PowerShell can use uv by running this command:
uv help

What Does This Check Do?

The command opens the uv command reference. Seeing that reference confirms that the newly installed executable is available in PowerShell.

✔️ uv help opens

The pinned uv installer completed successfully. The uv command is ready to manage the agent’s Python environment.

ⓧ An older uv installation remains

An older uv installation may still be first on the Windows command path. Reapply the pinned installer before continuing.

  • Rerun the pinned uv installer command shown above.
  • Close every PowerShell window after the installer finishes.
  • Reopen PowerShell through Windows search.
  • Repeat the uv help check shown above.

ⓧ PowerShell cannot find uv

The installer may have updated the Windows command path after this terminal started. Reload that path before reinstalling.

  • Close every PowerShell window.
  • Reopen PowerShell through Windows search.
  • Repeat the uv help check shown above.
  • Rerun the pinned installer command if the uv command remains unavailable.

uv Still Unavailable?

Check whether the installer completed without a download or permission failure. A restricted network can prevent the installation script from loading.

Help me fix my uv installation.

  • Install AgentCore CLI 0.29.0 by running this command:
npm install -g @aws/agentcore@0.29.0

What Does This Command Do?

The Node.js package manager installs AgentCore CLI 0.29.0 globally. A global installation makes the AgentCore command available from your project directory.

  • Check the installed AgentCore CLI version by running this command:
agentcore --version

What Does This Check Do?

The command reports which AgentCore CLI PowerShell resolves. This catches missing installations and older commands that could interfere with the scaffold.

✔️ I see version 0.29.0

AgentCore CLI 0.29.0 is ready. You now have every command-line tool needed to create the project.

ⓧ I see an older version

PowerShell is resolving an older AgentCore CLI. Reinstall the pinned npm package to update the global command.

  • Rerun the pinned AgentCore CLI installation command shown above.
  • Close every PowerShell window after the installation finishes.
  • Reopen PowerShell through Windows search.
  • Repeat the AgentCore CLI version check shown above. You should see version 0.29.0.

ⓧ AgentCore is not found

PowerShell cannot reach the global npm installation yet. Reload the command path before reinstalling.

  • Close every PowerShell window.
  • Reopen PowerShell through Windows search.
  • Repeat the AgentCore CLI version check shown above.
  • Rerun the pinned npm installation command if AgentCore remains unavailable.

Seeing the Wrong AgentCore CLI?

An older Python-installed AgentCore command can shadow the npm CLI on Windows. Remove that legacy installation before reinstalling the pinned npm package.

Help me resolve an AgentCore CLI conflict.

Create the CodeZip scaffold

The scaffold gives AgentCore the directory structure and configuration needed for local development. It also creates the starter app/ArchitectureAdvisor/main.py entrypoint.

Why CodeZip?

CodeZip packages the application as a zip for Amazon S3 during deployment. It avoids a Docker requirement in this Windows setup.

  • Move to your Desktop before creating the project by running this command:
cd ~/Desktop

What Does This Command Do?

The command changes PowerShell’s current location to your Desktop. The generated ArchitectureAdvisorProject folder stays easy to find there.

  • Create the AgentCore project scaffold by running this command:
agentcore create --project-name ArchitectureAdvisorProject --name ArchitectureAdvisor --language Python --framework Strands --model-provider Bedrock --memory none --build CodeZip

What Does This Command Create?

  • The project name creates the ArchitectureAdvisorProject directory.
  • The agent name creates the app/ArchitectureAdvisor directory.
  • The framework option selects Strands Agents with Amazon Bedrock as the model provider.
  • The remaining options disable memory and choose the CodeZip build type.

You should see AgentCore create the project files and application directories. No cloud runtime is deployed by this command.

  • Move into the generated project directory by running this command:
cd ArchitectureAdvisorProject

What Does This Command Do?

The command makes ArchitectureAdvisorProject your current PowerShell location. Later AgentCore commands use the configuration stored in this directory.

Before you run the final checks, which command do you expect to confirm that the scaffold itself exists?

  • Verify the complete toolchain and scaffold by running these checks:
python --version
node --version
uv help
agentcore --version
aws sts get-caller-identity
Test-Path -Path "app/ArchitectureAdvisor/main.py"

What Do These Checks Prove?

The version commands confirm that PowerShell can reach Python, Node.js, uv, and AgentCore CLI. The AWS command confirms that authenticated credentials remain available.

The final path check confirms that AgentCore generated the advisor’s main.py entrypoint. Together, these checks cover every prerequisite for the next step.

💡 What Should You See?

The Python check shows Python 3.13.15. The Node.js check shows v24.21.0.

The uv check prints its command reference. The AgentCore check shows version 0.29.0.

The AWS check returns your configured identity details. The path check returns a positive result for app/ArchitectureAdvisor/main.py.

🙋‍♀️ One of the Final Checks Failing?

  • Reopen PowerShell if an installed command is missing.
  • Confirm that the prompt shows the ArchitectureAdvisorProject directory if the path check fails.
  • Refresh your configured AWS credentials if the identity check fails.

Help me diagnose my final setup checks.

Your Windows toolchain is ready, and ArchitectureAdvisorProject now contains the generated advisor entrypoint. Next, you will replace the scaffold with the first model-only advisor and expose its grounding gap.

Build the Ungrounded Advisor

The Windows toolchain you verified is ready for the first runnable version of your architecture advisor. That setup work now pays off inside the scaffold.

A model-only advisor can produce a plausible recommendation without approved evidence. That gap makes the answer unsuitable as an approved decision source.

In this step, Strands Agents sends a local advisor prompt to Amazon Bedrock. You will inspect the result for a catalog tool trace plus a controlled source.

In this step, get ready to:
  • Pin the project's Python runtime dependencies.
  • Build the model-only advisor with input validation.
  • Run the local inspector to test one architecture question.
Pin the project dependencies

The pyproject.toml file is the dependency contract for this app. Exact pins keep every local run on the same SDK behavior.

  • Open the current ArchitectureAdvisorProject directory in Visual Studio Code by running this command in the PowerShell session from Step 1:
code .

What does this command do?

The command opens the current PowerShell directory as a Visual Studio Code workspace. Your project files become available in the editor without changing your terminal location.

  • Confirm Visual Studio Code opens with ArchitectureAdvisorProject visible in the workspace.

Project Not Opening?

Check that PowerShell is still inside the ArchitectureAdvisorProject directory. A different terminal location opens the wrong folder.

Use Windows Search to start Visual Studio Code if the terminal cannot launch it. Load the existing ArchitectureAdvisorProject directory as your workspace.

Help me open the project in Visual Studio Code.

  • Select app/ArchitectureAdvisor/pyproject.toml in the Explorer sidebar.
  • Select all existing text in pyproject.toml.
  • Replace the selected text with this manifest:
[project]
name = "architecture-advisor"
version = "0.1.0"
requires-python = ">=3.13,<3.14"
dependencies = [
    "bedrock-agentcore==1.23.0",
    "strands-agents==1.55.1",
]

What Does This Manifest Control?

  • The requires-python value keeps the app within the Python 3.13 release series.
  • The bedrock-agentcore==1.23.0 dependency provides the Amazon Bedrock AgentCore application lifecycle.
  • The strands-agents==1.55.1 dependency provides the agent implementation.
  • Save app/ArchitectureAdvisor/pyproject.toml.
  • Confirm the editor shows both pinned dependencies inside the dependencies list.

Manifest Showing a Syntax Problem?

Check that each dependency remains inside double quotes. Keep the final comma after each dependency.

Confirm the opening plus closing square brackets surround the dependency list. A missing bracket makes the manifest invalid.

Help me check my dependency manifest.

✔️ Awesome, I've got everything!

Great. Double check that app/ArchitectureAdvisor/pyproject.toml is saved with both dependency pins.

ⓧ I'd like to double check the full code

Compare your app/ArchitectureAdvisor/pyproject.toml file with this complete version.

[project]
name = "architecture-advisor"
version = "0.1.0"
requires-python = ">=3.13,<3.14"
dependencies = [
    "bedrock-agentcore==1.23.0",
    "strands-agents==1.55.1",
]
Build the model-only agent

The Agent forms the model-only agent loop for this first version. Its system prompt defines the advisor role plus the expected answer shape.

  • Select app/ArchitectureAdvisor/main.py in the Explorer sidebar.
  • Select all existing scaffold code in the editor.
  • Replace the selection with this first section:
from __future__ import annotations

from bedrock_agentcore import BedrockAgentCoreApp
from strands import Agent

MODEL_ID = "global.anthropic.claude-sonnet-4-6"

SYSTEM_PROMPT = """
You are an AWS architecture advisor.
Provide a concise hosting recommendation and label the recommendation and trade-off.
"""

What Does This Configuration Do?

  • The imports provide the managed application wrapper plus the Strands agent class.
  • The MODEL_ID value selects global.anthropic.claude-sonnet-4-6 for inference.
  • The SYSTEM_PROMPT value gives the advisor a focused role. It also requests a concise recommendation with a labeled trade-off.
  • Save app/ArchitectureAdvisor/main.py.
  • Confirm the editor shows a closed triple-quoted SYSTEM_PROMPT below MODEL_ID.

Prompt String Highlighting the Whole File?

Check the three double quotes above the first prompt line. Confirm another three double quotes appear after the second prompt line.

Help me fix the system prompt string.

  • Paste this next section directly below the closing quotes of SYSTEM_PROMPT.

app = BedrockAgentCoreApp()
agent = Agent(
    model=MODEL_ID,
    system_prompt=SYSTEM_PROMPT,
    callback_handler=None,
)


@app.entrypoint
def invoke(payload):
    """Validate a prompt and return the advisor response."""
    prompt = payload.get("prompt")
    if not isinstance(prompt, str) or not prompt.strip():
        return {"error": "prompt must be a non-empty string"}

    result = agent(prompt.strip())
    return {"response": str(result)}


if __name__ == "__main__":
    app.run()

How Does the Advisor Respond?

  • The BedrockAgentCoreApp instance exposes the local application entrypoint.
  • The Agent receives the selected model plus the system prompt.
  • The invoke(payload) function rejects missing prompts. It also rejects blank prompts.
  • The final call sends the cleaned prompt through the agent. The result returns as a response string.
  • Save app/ArchitectureAdvisor/main.py.
  • Confirm the file ends with the app.run() call inside the main guard.

Seeing Python Diagnostics?

Check that the code under invoke(payload) uses four spaces of indentation. Keep the final app.run() line indented beneath the main guard.

Help me compare my advisor code.

✔️ Awesome, I've got everything!

Your model-only advisor is ready. Double check that app/ArchitectureAdvisor/main.py is saved before starting the local server.

ⓧ I'd like to double check the full code

Compare your app/ArchitectureAdvisor/main.py file with this complete version.

from __future__ import annotations

from bedrock_agentcore import BedrockAgentCoreApp
from strands import Agent

MODEL_ID = "global.anthropic.claude-sonnet-4-6"

SYSTEM_PROMPT = """
You are an AWS architecture advisor.
Provide a concise hosting recommendation and label the recommendation and trade-off.
"""

app = BedrockAgentCoreApp()
agent = Agent(
    model=MODEL_ID,
    system_prompt=SYSTEM_PROMPT,
    callback_handler=None,
)


@app.entrypoint
def invoke(payload):
    """Validate a prompt and return the advisor response."""
    prompt = payload.get("prompt")
    if not isinstance(prompt, str) or not prompt.strip():
        return {"error": "prompt must be a non-empty string"}

    result = agent(prompt.strip())
    return {"response": str(result)}


if __name__ == "__main__":
    app.run()
Test the ungrounded response

The local development workflow starts a hot-reloading server for your AgentCore CLI project. Its browser inspector lets you submit a prompt while watching how the advisor handles it.

  • Start the local development server from the ArchitectureAdvisorProject directory by running:
agentcore dev

What Does This Command Do?

  • The command creates a Python virtual environment for the project.
  • It installs the dependencies from pyproject.toml.
  • It starts a hot-reloading local server.
  • It opens the browser agent inspector.

The first launch can take a few minutes while the dependencies install. Let the setup finish before testing the advisor.

  • Keep PowerShell running so the local server stays available.
  • Wait for the browser inspector to open.

You'll see the browser inspector connected to the local advisor.

Inspector Not Opening?

Check the PowerShell output for a dependency installation problem. Compare both files with the full-code tabs before retrying.

An AWS permission problem can also stop the model request. Confirm that the authenticated session from Step 1 is still active.

Help me troubleshoot the local AgentCore server.

Before you submit the question, do you think a confident recommendation alone proves that the answer came from an approved source?

  • Enter Which AWS service should host a stateful, long-running AI agent, and why? as the prompt in the browser inspector.
  • Submit the prompt to the local advisor.

You'll see a concise hosting recommendation in the inspector. The wording can vary because the response comes from the model.

No catalog tool event appears. The answer includes no controlled catalog source from this project.

Why This Result Falls Short

The advisor can use model knowledge to produce a plausible answer. Its response provides no deterministic evidence from an approved service catalog.

This visible gap is the intended result. You have now proved why the model-only version cannot support a controlled architecture recommendation.

You found the exact limitation this first advisor was designed to reveal. Next, you'll ground its recommendations with controlled catalog evidence.

Ground Recommendations with a Tool

Your model-only advisor can make a plausible recommendation. It cannot prove where the advice came from.

You will now add a read-only custom tool to Strands Agents. The tool supplies controlled service facts with source links before the agent answers.

In this step, get ready to:
  • Add a controlled service catalog with name resolution.
  • Expose the catalog through a typed Strands tool.
  • Register the tool and verify a sourced recommendation.
Add the controlled catalog

A controlled catalog gives the agent a fixed set of facts for AWS Lambda and Amazon Bedrock AgentCore Runtime. Each entry records a service fit.

The catalog also records a trade-off plus a source URL. This evidence gives every recommendation a traceable foundation.

  • In Visual Studio Code's file sidebar, select app/ArchitectureAdvisor/main.py.
  • Replace the import section at the top of main.py with this version:
from __future__ import annotations

import json

from bedrock_agentcore import BedrockAgentCoreApp
from strands import Agent, tool

What do these imports enable?

  • The json module converts catalog entries into structured text for the model.
  • The tool decorator exposes a Python function to the agent.
  • Save app/ArchitectureAdvisor/main.py.
  • Return to the terminal panel from earlier that is running agentcore dev.

The development server should complete its hot reload with the new imports available.

Import changes stopping the reload?

Compare the import names with the snippet above. Check the comma between Agent and tool.

Ask for help with the exact terminal output if the reload still fails. Help me debug the new imports in main.py.

  • Below the MODEL_ID line in main.py, add the controlled service entries:
SERVICE_CATALOG = {
    "aws lambda": {
        "service": "AWS Lambda",
        "fit": "Event-driven functions and short request-response work without managing servers.",
        "tradeoff": "This catalog does not prefer Lambda for stateful or long-running agent sessions.",
        "source": "https://strandsagents.com/docs/user-guide/deploy/deploy_to_aws_lambda/",
    },
    "amazon bedrock agentcore runtime": {
        "service": "Amazon Bedrock AgentCore Runtime",
        "fit": "A serverless runtime purpose-built for deploying and scaling dynamic AI agents and tools.",
        "tradeoff": "It is usage-priced and introduces managed runtime resources that should be cleaned up after testing.",
        "source": "https://strandsagents.com/docs/user-guide/deploy/deploy_to_bedrock_agentcore/",
    },
}

What does the catalog control?

  • The SERVICE_CATALOG dictionary limits guidance to two supported hosting services.
  • The fit and tradeoff fields supply the decision evidence.
  • The source field supplies the URL that the final answer can cite.
  • Save app/ArchitectureAdvisor/main.py.
  • Return to the existing agentcore dev terminal panel.

The server should reload successfully with both catalog entries in memory.

Catalog causing a syntax problem?

Check that every catalog key uses matching quotation marks. Confirm that each nested dictionary closes with a brace.

Use the terminal output to locate the affected line. Help me find the syntax problem in SERVICE_CATALOG.

  • Below SERVICE_CATALOG, add the accepted service-name aliases:
ALIASES = {
    "lambda": "aws lambda",
    "aws lambda": "aws lambda",
    "agentcore": "amazon bedrock agentcore runtime",
    "agentcore runtime": "amazon bedrock agentcore runtime",
    "amazon bedrock agentcore runtime": "amazon bedrock agentcore runtime",
}

Why use aliases?

The ALIASES dictionary maps several user-friendly names to the catalog's two canonical keys. The resolver can therefore accept common service names without duplicating catalog entries.

  • Save app/ArchitectureAdvisor/main.py.
  • Check the existing development terminal.

The hot reload should complete with the alias map available.

Alias map preventing a reload?

Confirm that ALIASES starts after the closing brace of SERVICE_CATALOG. Check that every alias entry ends with a comma.

Share the affected lines for focused help. Help me fix my ALIASES dictionary.

  • Below ALIASES, add the service resolver:
def _resolve_service(service_name: str) -> dict[str, str]:
    normalized = ALIASES.get(service_name.strip().lower())
    if normalized is None:
        return {
            "error": "Service is outside the controlled catalog.",
            "supported_services": ", ".join(
                entry["service"] for entry in SERVICE_CATALOG.values()
            ),
        }
    return SERVICE_CATALOG[normalized]

How does resolution stay controlled?

  • The strip() and lower() calls normalize the requested service name.
  • An accepted alias returns one existing catalog entry.
  • An unsupported name returns an explicit error plus the supported services.
  • Save app/ArchitectureAdvisor/main.py.
  • Check the existing development terminal.

The server should reload with _resolve_service() ready to validate service names.

Resolver failing during reload?

Check the indentation inside the if normalized is None: block. Confirm that the final return aligns with the if statement.

Use the line number from the terminal to narrow the problem. Help me debug _resolve_service().

  • Below _resolve_service(), add the typed lookup tool:
@tool
def lookup_service_guidance(service_name: str) -> str:
    """Look up controlled hosting guidance for one supported AWS service.

    Args:
        service_name: The AWS service name to look up.

    Returns:
        A JSON string containing the service fit, trade-off, and source URL.
    """
    return json.dumps(_resolve_service(service_name), indent=2)

What does this tool return?

  • The @tool decorator makes lookup_service_guidance() available for agent registration.
  • The typed parameter tells the agent that the function expects a service name.
  • The function returns deterministic JSON generated from the controlled catalog.
  • Save app/ArchitectureAdvisor/main.py.
  • Check the existing development terminal.

The hot reload should complete with the tool function defined.

Tool definition stopping the reload?

Confirm that @tool sits directly above the function definition. Check that the final return remains indented inside the function.

Include the terminal output when asking for help. Help me debug lookup_service_guidance().

Register the tool with the agent

The catalog remains ordinary Python until the agent receives a policy for using it. The system prompt sets that policy.

The agent configuration then makes the function callable during its reasoning loop.

  • Replace the existing SYSTEM_PROMPT block with this grounded policy:
SYSTEM_PROMPT = """
You are an AWS architecture advisor.
Before making any hosting recommendation, call lookup_service_guidance for both
AWS Lambda and Amazon Bedrock AgentCore Runtime.
Base the recommendation only on tool output and cite each returned source URL.
If the request falls outside the controlled catalog, say that the catalog does
not cover it. Keep the answer concise and label the recommendation and trade-off.
"""

How does the policy ground answers?

  • The prompt requires a lookup for both supported hosting services before a recommendation.
  • The recommendation must use the returned tool output as its evidence.
  • The final answer must cite each returned source URL.
  • Save app/ArchitectureAdvisor/main.py.
  • Return to the existing development terminal.

The server should reload with the grounded decision policy.

System prompt breaking the file?

Confirm that the prompt starts and ends with three quotation marks. Keep the closing quotation marks above the app definition.

Ask for help with the surrounding prompt lines if the file still fails. Help me repair SYSTEM_PROMPT.

  • Replace the existing agent = Agent(...) block with this registered-tool configuration:
agent = Agent(
    model=MODEL_ID,
    system_prompt=SYSTEM_PROMPT,
    tools=[lookup_service_guidance],
    callback_handler=None,
)

What changes in the agent loop?

The tools list registers lookup_service_guidance with the agent. The system prompt can now trigger a real function call during a hosting recommendation.

  • Save app/ArchitectureAdvisor/main.py.
  • Check the existing development terminal.

The server should reload with one registered tool.

Agent registration failing?

Confirm that tools=[lookup_service_guidance] sits inside the Agent(...) call. Check the comma after the tools list.

Share the agent block plus the terminal output for targeted help. Help me fix the tool registration.

  • Inside invoke(payload), replace the function docstring with this grounded description:
    """Validate a prompt and return the grounded advisor response."""

Why update the docstring?

The docstring now describes the function's completed behavior. Incoming prompts still pass through the same validation before reaching the grounded agent.

  • Save app/ArchitectureAdvisor/main.py.
  • Check the existing development terminal.

The hot reload should finish with the complete grounded advisor loaded.

✔️ Awesome, I've got everything!

Your imports, catalog, resolver, tool, prompt, registration, and grounded response description are now in place.

ⓧ I'd like to double check the full code

  • Compare app/ArchitectureAdvisor/main.py against this complete version:
from __future__ import annotations

import json

from bedrock_agentcore import BedrockAgentCoreApp
from strands import Agent, tool

MODEL_ID = "global.anthropic.claude-sonnet-4-6"

SERVICE_CATALOG = {
    "aws lambda": {
        "service": "AWS Lambda",
        "fit": "Event-driven functions and short request-response work without managing servers.",
        "tradeoff": "This catalog does not prefer Lambda for stateful or long-running agent sessions.",
        "source": "https://strandsagents.com/docs/user-guide/deploy/deploy_to_aws_lambda/",
    },
    "amazon bedrock agentcore runtime": {
        "service": "Amazon Bedrock AgentCore Runtime",
        "fit": "A serverless runtime purpose-built for deploying and scaling dynamic AI agents and tools.",
        "tradeoff": "It is usage-priced and introduces managed runtime resources that should be cleaned up after testing.",
        "source": "https://strandsagents.com/docs/user-guide/deploy/deploy_to_bedrock_agentcore/",
    },
}

ALIASES = {
    "lambda": "aws lambda",
    "aws lambda": "aws lambda",
    "agentcore": "amazon bedrock agentcore runtime",
    "agentcore runtime": "amazon bedrock agentcore runtime",
    "amazon bedrock agentcore runtime": "amazon bedrock agentcore runtime",
}


def _resolve_service(service_name: str) -> dict[str, str]:
    normalized = ALIASES.get(service_name.strip().lower())
    if normalized is None:
        return {
            "error": "Service is outside the controlled catalog.",
            "supported_services": ", ".join(
                entry["service"] for entry in SERVICE_CATALOG.values()
            ),
        }
    return SERVICE_CATALOG[normalized]


@tool
def lookup_service_guidance(service_name: str) -> str:
    """Look up controlled hosting guidance for one supported AWS service.

    Args:
        service_name: The AWS service name to look up.

    Returns:
        A JSON string containing the service fit, trade-off, and source URL.
    """
    return json.dumps(_resolve_service(service_name), indent=2)


SYSTEM_PROMPT = """
You are an AWS architecture advisor.
Before making any hosting recommendation, call lookup_service_guidance for both
AWS Lambda and Amazon Bedrock AgentCore Runtime.
Base the recommendation only on tool output and cite each returned source URL.
If the request falls outside the controlled catalog, say that the catalog does
not cover it. Keep the answer concise and label the recommendation and trade-off.
"""

app = BedrockAgentCoreApp()
agent = Agent(
    model=MODEL_ID,
    system_prompt=SYSTEM_PROMPT,
    tools=[lookup_service_guidance],
    callback_handler=None,
)


@app.entrypoint
def invoke(payload):
    """Validate a prompt and return the grounded advisor response."""
    prompt = payload.get("prompt")
    if not isinstance(prompt, str) or not prompt.strip():
        return {"error": "prompt must be a non-empty string"}

    result = agent(prompt.strip())
    return {"response": str(result)}


if __name__ == "__main__":
    app.run()

What should match?

Use this file as a comparison reference. The catalog entries, resolver, tool function, system prompt, and agent registration should match exactly.

Verify grounded tool use

Hot reload applies your saved edits to the existing local server. The browser inspector can now reveal whether the agent calls its registered tool.

Before you ask, do you expect the inspector to show model text alone or visible catalog lookups?

  • Return to the browser inspector from earlier.
  • Place the verification question in the prompt field by copying this text:
Which AWS service should host a stateful, long-running AI agent, and why?

What does this question test?

The workload description gives the advisor a concrete hosting decision. The system prompt requires evidence for both supported services before the agent recommends one.

  • Submit the prompt in the inspector.
  • Inspect the visible lookup_service_guidance tool events.

You should see lookup_service_guidance invoked for AWS Lambda plus Amazon Bedrock AgentCore Runtime. The final recommendation should cite the controlled catalog source URLs.

That is the key shift completed. Your advisor now shows where its recommendation came from.

No tool events or source links?

  • Confirm that app/ArchitectureAdvisor/main.py is saved.
  • Check that tools=[lookup_service_guidance] sits inside the Agent(...) call.
  • Confirm that SYSTEM_PROMPT requires both service lookups plus source citations.

Share the inspector result for a focused diagnosis. Help me diagnose why the catalog tool was not called.

Your local advisor now grounds its decisions in controlled evidence. Next, you will package the same behavior for a managed runtime deployment.

Deploy and Invoke the Advisor

Your advisor already uses a controlled catalog in the local inspector. Its recommendations now carry service facts plus source links.

The final proof comes from running the same agent on Amazon Bedrock AgentCore Runtime. A remote invocation confirms that CodeZip packaging plus IAM access preserve the grounded behavior.

In this step, get ready to:
  • Review a validated deployment preview.
  • Deploy the CodeZip application to a ready AgentCore Runtime endpoint.
  • Invoke the endpoint to verify catalog-backed reasoning remotely.
Validate and preview the deployment

A deployment preview catches project configuration problems before AWS resources exist. It also shows what the deployment plans to change.

  • Switch back to the integrated terminal where the local development server is running.
  • Press Ctrl+C to stop the local development server.
  • Confirm that the PowerShell prompt returns.
  • Validate the AgentCore project by running this command:
agentcore validate

What Does This Command Do?

The validation command checks the project configuration before packaging begins. A successful result confirms that the scaffold is ready for deployment.

You should see the validation finish successfully.

Validation Not Completing?

Confirm that the terminal is inside ArchitectureAdvisorProject. Check that both application files are saved.

If the local server still owns the terminal session, press Ctrl+C again before retrying.

Help me diagnose the AgentCore validation result.

  • Preview the CodeZip package plus planned AWS changes by running this command:
agentcore deploy --dry-run

What Does the Preview Show?

The dry run prepares a deployment preview without provisioning the runtime. It lets you review the planned package plus AWS changes before creating resources.

You should see a deployment preview. No runtime resources are provisioned by this command.

Dry Run Failing?

Confirm that validation succeeded first. Check that your authenticated AWS CLI session remains available.

Help me troubleshoot the AgentCore dry run.

✔️ Awesome, I've got everything!

Your application files remain unchanged. The validated preview is ready for deployment.

ⓧ I'd like to double check the full code

These are the exact application files used by the deployment preview.

from __future__ import annotations

import json

from bedrock_agentcore import BedrockAgentCoreApp
from strands import Agent, tool

MODEL_ID = "global.anthropic.claude-sonnet-4-6"

SERVICE_CATALOG = {
    "aws lambda": {
        "service": "AWS Lambda",
        "fit": "Event-driven functions and short request-response work without managing servers.",
        "tradeoff": "This catalog does not prefer Lambda for stateful or long-running agent sessions.",
        "source": "https://strandsagents.com/docs/user-guide/deploy/deploy_to_aws_lambda/",
    },
    "amazon bedrock agentcore runtime": {
        "service": "Amazon Bedrock AgentCore Runtime",
        "fit": "A serverless runtime purpose-built for deploying and scaling dynamic AI agents and tools.",
        "tradeoff": "It is usage-priced and introduces managed runtime resources that should be cleaned up after testing.",
        "source": "https://strandsagents.com/docs/user-guide/deploy/deploy_to_bedrock_agentcore/",
    },
}

ALIASES = {
    "lambda": "aws lambda",
    "aws lambda": "aws lambda",
    "agentcore": "amazon bedrock agentcore runtime",
    "agentcore runtime": "amazon bedrock agentcore runtime",
    "amazon bedrock agentcore runtime": "amazon bedrock agentcore runtime",
}


def _resolve_service(service_name: str) -> dict[str, str]:
    normalized = ALIASES.get(service_name.strip().lower())
    if normalized is None:
        return {
            "error": "Service is outside the controlled catalog.",
            "supported_services": ", ".join(
                entry["service"] for entry in SERVICE_CATALOG.values()
            ),
        }
    return SERVICE_CATALOG[normalized]


@tool
def lookup_service_guidance(service_name: str) -> str:
    """Look up controlled hosting guidance for one supported AWS service.

    Args:
        service_name: The AWS service name to look up.

    Returns:
        A JSON string containing the service fit, trade-off, and source URL.
    """
    return json.dumps(_resolve_service(service_name), indent=2)


SYSTEM_PROMPT = """
You are an AWS architecture advisor.
Before making any hosting recommendation, call lookup_service_guidance for both
AWS Lambda and Amazon Bedrock AgentCore Runtime.
Base the recommendation only on tool output and cite each returned source URL.
If the request falls outside the controlled catalog, say that the catalog does
not cover it. Keep the answer concise and label the recommendation and trade-off.
"""

app = BedrockAgentCoreApp()
agent = Agent(
    model=MODEL_ID,
    system_prompt=SYSTEM_PROMPT,
    tools=[lookup_service_guidance],
    callback_handler=None,
)


@app.entrypoint
def invoke(payload):
    """Validate a prompt and return the grounded advisor response."""
    prompt = payload.get("prompt")
    if not isinstance(prompt, str) or not prompt.strip():
        return {"error": "prompt must be a non-empty string"}

    result = agent(prompt.strip())
    return {"response": str(result)}


if __name__ == "__main__":
    app.run()

Why This File Matters

This file contains the controlled catalog plus its lookup tool. The system prompt requires catalog evidence before the agent recommends a hosting service.

[project]
name = "architecture-advisor"
version = "0.1.0"
requires-python = ">=3.13,<3.14"
dependencies = [
    "bedrock-agentcore==1.23.0",
    "strands-agents==1.55.1",
]

Why This File Matters

The dependency file keeps the validated Python range plus package versions fixed. This gives the deployment the same application environment you tested locally.

Deploy the advisor

The dry run proved that the project can be packaged. The real deployment now creates the managed endpoint that receives remote prompts.

Deployment Creates Billable Resources

This action creates usage-based AWS resources. Charges can come from runtime use plus storage plus logs plus model inference.

The CLI may ask to bootstrap AWS CDK for this AWS environment. Approve the bootstrap prompt so deployment can continue.

  • Deploy the CodeZip application by running this command:
agentcore deploy

What Happens During Deployment?

  • The AgentCore CLI packages the Python application as a CodeZip artifact.
  • The deployment uploads that artifact to Amazon S3.
  • AWS CDK provisions the managed runtime endpoint.
  • The deployment configures CloudWatch logging plus observability.

Deployment can take several minutes while AWS provisions the endpoint. A quiet stretch during this process is normal.

  • Check the deployed resource status by running this command:
agentcore status

What Does the Status Check Prove?

The status check reports the deployed resource details. A ready endpoint confirms that the managed runtime can accept remote invocations.

  • Repeat the status check until the AgentCore Runtime endpoint is reported as ready.

Your advisor now has a managed endpoint in AWS. The local agent has become a remotely invokable service.

Deployment or Status Check Failing?

Confirm that your AWS identity has permission to deploy AgentCore resources. It also needs permission to assume the CDK bootstrap roles used by the CLI.

If deployment completed but the endpoint is still preparing, wait briefly before repeating the status check.

Help me diagnose the AgentCore deployment.

Invoke the deployed advisor

A remote invocation is the final test of the deployment path. It sends a real architecture question through the managed endpoint.

Before you run the remote check, do you think the deployed advisor will preserve the catalog-backed behavior you saw locally?

  • Invoke the deployed advisor with the verification prompt by running this command:
agentcore invoke --prompt "Which service fits a stateful AI agent that may wait on tools?"

What Does This Invocation Test?

The invocation sends the prompt to the deployed endpoint. The response tests the packaged agent plus its model access plus its registered catalog tool.

You should see a hosting recommendation with catalog-backed reasoning plus source URLs. That closes the loop because your grounded advisor now works locally and remotely.

Remote Invocation Not Working?

Confirm that the latest status check reports a ready endpoint. Retry the invocation only after deployment has finished.

If the endpoint responds without a recommendation, inspect the deployment output for model invocation or runtime permission problems.

Help me troubleshoot the remote advisor invocation.

Secret mission

Add a Deterministic Comparison Tool

Give your advisor one structured result for side-by-side hosting questions. You will add a comparison tool that returns both controlled catalog entries before the agent responds.

Clean Up Your Resources

🗑 Before you go

Model inference through Amazon Bedrock is billed separately. AgentCore Runtime usage can also generate charges.

CodeZip artifacts stored in Amazon S3 can generate storage charges.

Retained CloudWatch data can generate logging charges. Network transfer can add usage charges.

Choose Pause or Delete if you do not need another remote demo.

Nice Work!

Nice Work!

You made it! Your AWS architecture advisor now returns catalog-backed recommendations from a deployed Amazon Bedrock AgentCore Runtime endpoint.

You've learned how to:

  • Build a Python architecture advisor with Strands Agents. It uses Amazon Bedrock to recommend AWS Lambda or Amazon Bedrock AgentCore Runtime for a workload.
  • Experience why a model-only recommendation lacks approved evidence. Add grounded responses backed by deterministic catalog facts and source URLs.
  • Inspect the agent loop through the local browser inspector. Deploy the same tool-using advisor for remote invocation through its managed runtime endpoint.
  • Complete the Secret Mission by adding a deterministic side-by-side comparison tool. It routes comparison questions through compare_service_guidance to return both controlled catalog entries in one call.

Ready to quiz yourself?