Skip to content

Deploying Strands Agents to Amazon Bedrock AgentCore Runtime

What is Amazon Bedrock AgentCore Runtime

Amazon Bedrock AgentCore Runtime is a secure, serverless runtime purpose-built for deploying and scaling dynamic AI agents and tools using any open-source framework including Strands Agents, LangChain, LangGraph and CrewAI. It supports any protocol such as MCP and A2A, and any model from any provider including Amazon Bedrock, OpenAI, Gemini, etc. Developers can securely and reliably run any type of agent including multi-modal, real-time, or long-running agents. AgentCore Runtime helps protect sensitive data with complete session isolation, providing dedicated microVMs for each user session - critical for AI agents that maintain complex state and perform privileged operations on users' behalf. It is highly reliable with session persistence and it can scale up to thousands of agent sessions in seconds so developers don't have to worry about managing infrastructure and only pay for actual usage. AgentCore Runtime, using AgentCore Identity, also seamlessly integrates with the leading identity providers such as Amazon Cognito, Microsoft Entra ID, and Okta, as well as popular OAuth providers such as Google and GitHub. It supports all authentication methods, from OAuth tokens and API keys to IAM roles, so developers don't have to build custom security infrastructure.

⚠️ Important: Amazon Bedrock AgentCore is in preview release and is subject to change.

Prerequisites

Before you start, you need:

  • An AWS account with appropriate permissions
  • Python 3.10+
  • Familiarity with Docker containers (for advanced deployment)

🚨 Don't forget observability

📈 AgentCore runtime observability - Distributed tracing, metrics, and debugging

This section is at the bottom of this document - don't skip it


Choose Your Deployment Approach

⚠️ Important: Choose the approach that best fits your use case. You only need to follow ONE of the two approaches below.

🚀 SDK Integration

Option A: SDK Integration - Use when: You want to quickly deploy existing agent functions - Best for: Simple agents, prototyping, minimal setup - Benefits: Automatic HTTP server setup, built-in deployment tools - Trade-offs: Less control over server configuration

🔧 Custom Implementation

Option B: Custom Agent - Use when: You need full control over your agent's HTTP interface - Best for: Complex agents, custom middleware, production systems - Benefits: Complete FastAPI control, custom routing, advanced features - Trade-offs: More setup required, manual server configuration


Option A: SDK Integration

The AgentCore Runtime Python SDK provides a lightweight wrapper that helps you deploy your agent functions as HTTP services.

Step 1: Install the SDK

pip install bedrock-agentcore

Step 2: Prepare Your Agent Code

Basic Setup (3 simple steps)

Import the runtime

from bedrock_agentcore.runtime import BedrockAgentCoreApp

Initialize the app

app = BedrockAgentCoreApp()

Decorate your function

@app.entrypoint
def invoke(payload):
    # Your existing code remains unchanged
    return payload

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

Complete Examples

Basic Example

from bedrock_agentcore.runtime import BedrockAgentCoreApp
from strands import Agent

app = BedrockAgentCoreApp()
agent = Agent()

@app.entrypoint
def invoke(payload):
    """Process user input and return a response"""
    user_message = payload.get("prompt", "Hello")
    result = agent(user_message)
    return {"result": result.message}

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

Streaming Example

from strands import Agent
from bedrock_agentcore import BedrockAgentCoreApp

app = BedrockAgentCoreApp()
agent = Agent()

@app.entrypoint
async def agent_invocation(payload):
    """Handler for agent invocation"""
    user_message = payload.get(
        "prompt", "No prompt found in input, please guide customer to create a json payload with prompt key"
    )
    stream = agent.stream_async(user_message)
    async for event in stream:
        print(event)
        yield (event)

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

Step 3: Test Locally

python my_agent.py

# Test with curl:
curl -X POST http://localhost:8080/invocations \
-H "Content-Type: application/json" \
-d '{"prompt": "Hello world!"}'

Step 4: Choose Your Deployment Method

Choose ONE of the following deployment methods:

Method A: Starter Toolkit (For quick prototyping)

For quick prototyping with automated deployment:

pip install bedrock-agentcore-starter-toolkit

Project Structure

your_project_directory/
├── agent_example.py # Your main agent code
├── requirements.txt # Dependencies for your agent
└── __init__.py # Makes the directory a Python package

agent_example.py

from strands import Agent
from bedrock_agentcore.runtime import BedrockAgentCoreApp

agent = Agent()
app = BedrockAgentCoreApp()

@app.entrypoint
def invoke(payload):
    """Process user input and return a response"""
    user_message = payload.get("prompt", "Hello")
    response = agent(user_message)
    return str(response) # response should be json serializable

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

requirements.txt

strands-agents
bedrock-agentcore

Deploy with Starter Toolkit

Ensure Docker is running before proceeding:

# Configure your agent
agentcore configure --entrypoint agent_example.py -er <YOUR_IAM_ROLE_ARN>

# Local testing
agentcore launch -l

# Deploy to AWS
agentcore launch

# Test your agent with CLI
agentcore invoke '{"prompt": "Hello"}'

Method B: Manual Deployment with boto3

For more control over the deployment process:

  1. Package your code as a container image and push it to ECR
  2. Create your agent using CreateAgentRuntime:
import boto3

# Create the client
client = boto3.client('bedrock-agentcore-control', region_name="us-east-1")

# Call the CreateAgentRuntime operation
response = client.create_agent_runtime(
    agentRuntimeName='hello-strands',
    agentRuntimeArtifact={
        'containerConfiguration': {
            # Your ECR image Uri
            'containerUri': '123456789012.dkr.ecr.us-east-1.amazonaws.com/my-agent:latest'
        }
    },
    networkConfiguration={"networkMode":"PUBLIC"},
    # Your AgentCore Runtime role arn
    roleArn='arn:aws:iam::123456789012:role/AgentRuntimeRole'
)
  1. Invoke Your Agent
import boto3
import json

# Initialize the AgentCore Runtime client
agent_core_client = boto3.client('bedrock-agentcore')

# Prepare the payload
payload = json.dumps({"prompt": prompt}).encode()

# Invoke the agent
response = agent_core_client.invoke_agent_runtime(
    agentRuntimeArn=agent_arn, # you will get this from deployment
    runtimeSessionId=session_id, # you will get this from deployment
    payload=payload
)

📊 Next Steps: Set Up Observability (Optional)

⚠️ IMPORTANT: Your agent is deployed, you could also set up Observability


Option B: Custom Agent

This section is complete - follow all steps below if you chose the custom agent approach.

This approach demonstrates how to deploy a custom agent using FastAPI and Docker, following AgentCore Runtime requirements.

Requirements

  • FastAPI Server: Web server framework for handling requests
  • /invocations Endpoint: POST endpoint for agent interactions (REQUIRED)
  • /ping Endpoint: GET endpoint for health checks (REQUIRED)
  • Docker Container: ARM64 containerized deployment package

Quick Start Setup

Install uv

curl -LsSf https://astral.sh/uv/install.sh | sh

Create Project

mkdir my-custom-agent && cd my-custom-agent
uv init --python 3.11
uv add fastapi uvicorn[standard] pydantic httpx strands-agents

Project Structure

my-custom-agent/
├── agent.py                 # FastAPI application
├── Dockerfile               # ARM64 container configuration
├── pyproject.toml          # Created by uv init
└── uv.lock                 # Created automatically by uv

Complete Strands Agent Example

agent.py

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Dict, Any
from datetime import datetime,timezone
from strands import Agent

app = FastAPI(title="Strands Agent Server", version="1.0.0")

# Initialize Strands agent
strands_agent = Agent()

class InvocationRequest(BaseModel):
    input: Dict[str, Any]

class InvocationResponse(BaseModel):
    output: Dict[str, Any]

@app.post("/invocations", response_model=InvocationResponse)
async def invoke_agent(request: InvocationRequest):
    try:
        user_message = request.input.get("prompt", "")
        if not user_message:
            raise HTTPException(
                status_code=400,
                detail="No prompt found in input. Please provide a 'prompt' key in the input."
            )

        result = strands_agent(user_message)
        response = {
            "message": result.message,
            "timestamp": datetime.now(timezone.utc).isoformat(),
            "model": "strands-agent",
        }

        return InvocationResponse(output=response)

    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Agent processing failed: {str(e)}")

@app.get("/ping")
async def ping():
    return {"status": "healthy"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8080)

Test Locally

# Run the application
uv run uvicorn agent:app --host 0.0.0.0 --port 8080

# Test /ping endpoint
curl http://localhost:8080/ping

# Test /invocations endpoint
curl -X POST http://localhost:8080/invocations \
  -H "Content-Type: application/json" \
  -d '{
    "input": {"prompt": "What is artificial intelligence?"}
  }'

Create Dockerfile

# Use uv's ARM64 Python base image
FROM --platform=linux/arm64 ghcr.io/astral-sh/uv:python3.11-bookworm-slim

WORKDIR /app

# Copy uv files
COPY pyproject.toml uv.lock ./

# Install dependencies (including strands-agents)
RUN uv sync --frozen --no-cache

# Copy agent file
COPY agent.py ./

# Expose port
EXPOSE 8080

# Run application
CMD ["uv", "run", "uvicorn", "agent:app", "--host", "0.0.0.0", "--port", "8080"]

Build and Deploy ARM64 Image

Setup Docker buildx

docker buildx create --use

Build and Test Locally

# Build the image
docker buildx build --platform linux/arm64 -t my-agent:arm64 --load .

# Test locally with credentials
docker run --platform linux/arm64 -p 8080:8080 \
  -e AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" \
  -e AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" \
  -e AWS_SESSION_TOKEN="$AWS_SESSION_TOKEN" \
  -e AWS_REGION="$AWS_REGION" \
  my-agent:arm64

Deploy to ECR

# Create ECR repository
aws ecr create-repository --repository-name my-strands-agent --region us-west-2

# Login to ECR
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin <account-id>.dkr.ecr.us-west-2.amazonaws.com

# Build and push to ECR
docker buildx build --platform linux/arm64 -t <account-id>.dkr.ecr.us-west-2.amazonaws.com/my-strands-agent:latest --push .

# Verify the image
aws ecr describe-images --repository-name my-strands-agent --region us-west-2

Deploy Agent Runtime

deploy_agent.py

import boto3

client = boto3.client('bedrock-agentcore-control')

response = client.create_agent_runtime(
    agentRuntimeName='strands_agent',
    agentRuntimeArtifact={
        'containerConfiguration': {
            'containerUri': '<account-id>.dkr.ecr.us-west-2.amazonaws.com/my-strands-agent:latest'
        }
    },
    networkConfiguration={"networkMode": "PUBLIC"},
    roleArn='arn:aws:iam::<account-id>:role/AgentRuntimeRole'
)

print(f"Agent Runtime created successfully!")
print(f"Agent Runtime ARN: {response['agentRuntimeArn']}")
print(f"Status: {response['status']}")
uv run deploy_agent.py

Invoke Your Agent

invoke_agent.py

import boto3
import json

agent_core_client = boto3.client('bedrock-agentcore', region_name='us-west-2')
payload = json.dumps({
    "input": {"prompt": "Explain machine learning in simple terms"}
})

response = agent_core_client.invoke_agent_runtime(
    agentRuntimeArn='arn:aws:bedrock-agentcore:us-west-2:<account-id>:runtime/myStrandsAgent-suffix',
    runtimeSessionId='dfmeoagmreaklgmrkleafremoigrmtesogmtrskhmtkrlshmt',  # Must be 33+ chars
    payload=payload,
    qualifier="DEFAULT"
)

response_body = response['response'].read()
response_data = json.loads(response_body)
print("Agent Response:", response_data)
uv run invoke_agent.py

Expected Response Format

{
  "output": {
    "message": {
      "role": "assistant",
      "content": [
        {
          "text": "# Artificial Intelligence in Simple Terms\n\nArtificial Intelligence (AI) is technology that allows computers to do tasks that normally need human intelligence. Think of it as teaching machines to:\n\n- Learn from information (like how you learn from experience)\n- Make decisions based on what they've learned\n- Recognize patterns (like identifying faces in photos)\n- Understand language (like when I respond to your questions)\n\nInstead of following specific step-by-step instructions for every situation, AI systems can adapt to new information and improve over time.\n\nExamples you might use every day include voice assistants like Siri, recommendation systems on streaming services, and email spam filters that learn which messages are unwanted."
        }
      ]
    },
    "timestamp": "2025-07-13T01:48:06.740668",
    "model": "strands-agent"
  }
}

Shared Information (Both Options)

This section applies to both deployment approaches - reference as needed regardless of which option you chose.

AgentCore Runtime Requirements Summary

  • Platform: Must be linux/arm64
  • Endpoints: /invocations POST and /ping GET are mandatory
  • ECR: Images must be deployed to ECR
  • Port: Application runs on port 8080
  • Strands Integration: Uses Strands Agent for AI processing
  • Credentials: Require AWS credentials for operation

Best Practices

  1. Development
  2. Test locally before deployment
  3. Use version control
  4. Keep dependencies updated

  5. Configuration

  6. Use appropriate IAM roles
  7. Implement proper error handling
  8. Monitor agent performance

  9. Security

  10. Follow the least privilege principle
  11. Secure sensitive information
  12. Regular security updates

Troubleshooting

Common issues and solutions:

  1. Deployment Failures
  2. Verify AWS credentials are configured correctly
  3. Check IAM role permissions
  4. Ensure Docker is running

  5. Runtime Errors

  6. Check CloudWatch logs
  7. Verify environment variables
  8. Test agent locally first

  9. Container Issues

  10. Verify Docker installation
  11. Check port configurations
  12. Review Dockerfile if customized

Observability Enablement

Amazon Bedrock AgentCore provides built-in metrics to monitor your Strands agents. This section explains how to enable observability for your agents to view metrics, spans, and traces in CloudWatch.

With AgentCore, you can also view metrics for agents that aren't running in the AgentCore runtime. Additional setup steps are required to configure telemetry outputs for non-AgentCore agents. See the instructions in Configure Observability for agents hosted outside of the AgentCore runtime to learn more.

Before you can view metrics and traces, complete this one-time setup:

Via AgentCore Console - Look for the "Enable Observability" button when creating a memory resource

If you don't see this button while configuring your agent (for example, if you don't create a memory resource in the console), you must enable observability manually by using the CloudWatch console to enable Transaction Search as described in the following procedure.

Via CloudWatch Console 1. Open the CloudWatch console 2. Navigate to Application Signals (APM) > Transaction search 3. Choose "Enable Transaction Search" 4. Select the checkbox to ingest spans as structured logs 5. Optionally adjust the X-Ray trace indexing percentage (default is 1%) 6. Choose Save

Step 2: Add ADOT to Your Strands Agent

1. Add Dependencies

Add to your requirements.txt:

aws-opentelemetry-distro>=0.10.0
boto3

Or install directly:

pip install aws-opentelemetry-distro>=0.10.0 boto3

2. Run With Auto-Instrumentation

For SDK Integration (Option A):

opentelemetry-instrument python my_agent.py

For Docker Deployment:

CMD ["opentelemetry-instrument", "python", "main.py"]

For Custom Agent (Option B):

CMD ["opentelemetry-instrument", "uvicorn", "agent:app", "--host", "0.0.0.0", "--port", "8080"]

Session ID support

To propagate session ID, you need to invoke using session identifier in the OTEL baggage:

from opentelemetry import baggage,context

ctx = baggage.set_baggage("session.id", session_id) # Set the session.id in baggage
context.attach(ctx)

Enhanced AgentCore observability with custom headers (Optional)

You can invoke your agent with additional HTTP headers to provide enhanced observability options. The following example shows invocations including optional additional header requests for agents hosted in the AgentCore runtime.

import boto3

def invoke_agent(agent_id, payload, session_id=None):
    client = boto3.client("bedrock-agentcore", region_name="us-west-2")
    response = client.invoke_agent_runtime(
        agentRuntimeArn=f"arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/{agent_id}",
        runtimeSessionId="12345678-1234-5678-9abc-123456789012",
        payload=payload
    )
    return response

Common Tracing Headers

Header Description Sample Value
X-Amzn-Trace-Id X-Ray format trace ID Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1
traceparent W3C standard tracing header 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
X-Amzn-Bedrock-AgentCore-Runtime-Session-Id Session identifier aea8996f-dcf5-4227-b5ea-f9e9c1843729
baggage User-defined properties userId=alice,serverRegion=us-east-1

For more supported headers details, please check Bedrock AgentCore Runtime Observability Configuration

Viewing Your Agent's Observability Data

  1. Open the CloudWatch console
  2. Navigate to the GenAI Observability page
  3. Find your agent service
  4. View traces, metrics, and logs

Best Practices

  • Use consistent session IDs across related requests
  • Set appropriate sampling rates (1% is default)
  • Monitor key metrics like latency, error rates, and token usage
  • Set up CloudWatch alarms for critical thresholds

Notes

  • Amazon Bedrock AgentCore is in preview release and is subject to change.
  • Keep your AgentCore Runtime and Strands packages updated for latest features and security fixes

Additional Resources