Python Deployment to Amazon Bedrock AgentCore Runtime
Section titled âPython Deployment to Amazon Bedrock AgentCore RuntimeâThis guide covers deploying Python-based Strands agents to Amazon Bedrock AgentCore Runtime.
Prerequisites
Section titled âPrerequisitesâ- Python 3.10+
- AWS account with appropriate permissions
- Optional: A container engine (Docker, Finch, or Podman) - only required for local testing and advanced deployment scenarios
Choose Your Deployment Approach
Section titled â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
Section titled âđ 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
Section titled âđ§ Custom Implementationâ- 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
Section titled â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
Section titled âStep 1: Install the SDKâpip install bedrock-agentcoreStep 2: Prepare Your Agent Code
Section titled âStep 2: Prepare Your Agent CodeâBasic Setup (3 simple steps)
Import the runtime
from bedrock_agentcore.runtime import BedrockAgentCoreAppInitialize the app
app = BedrockAgentCoreApp()Decorate your function
@app.entrypointdef invoke(payload): # Your existing code remains unchanged return payload
if __name__ == "__main__": app.run()Complete Examples
- Basic Example
from bedrock_agentcore.runtime import BedrockAgentCoreAppfrom strands import Agent
app = BedrockAgentCoreApp()agent = Agent()
@app.entrypointdef 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 Agentfrom bedrock_agentcore import BedrockAgentCoreApp
app = BedrockAgentCoreApp()agent = Agent()
@app.entrypointasync 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
Section titled â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
Section titled âStep 4: Choose Your Deployment MethodâChoose ONE of the following deployment methods:
Method A: Starter Toolkit (For quick prototyping)
Section titled âMethod A: Starter Toolkit (For quick prototyping)âFor quick prototyping with automated deployment:
pip install bedrock-agentcore-starter-toolkitProject Structure
your_project_directory/âââ agent_example.py # Your main agent codeâââ requirements.txt # Dependencies for your agentâââ __init__.py # Makes the directory a Python packageExample: agent_example.py
from strands import Agentfrom bedrock_agentcore.runtime import BedrockAgentCoreApp
agent = Agent()app = BedrockAgentCoreApp()
@app.entrypointdef 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()Example: requirements.txt
strands-agentsbedrock-agentcoreDeploy with Starter Toolkit
# Configure your agentagentcore configure --entrypoint agent_example.py
# Optional: Local testing (requires Docker, Finch, or Podman)agentcore launch --local
# Deploy to AWSagentcore launch
# Test your agent with CLIagentcore invoke '{"prompt": "Hello"}'Note: The
agentcore launch --localcommand requires a container engine (Docker, Finch, or Podman) for local deployment testing. This step is optional - you can skip directly toagentcore launchfor AWS deployment if you donât need local testing.
Method B: Manual Deployment with boto3
Section titled âMethod B: Manual Deployment with boto3âFor more control over the deployment process:
- Package your code as a container image and push it to ECR
- Create your agent using CreateAgentRuntime:
import boto3
# Create the clientclient = boto3.client('bedrock-agentcore-control', region_name="us-east-1")
# Call the CreateAgentRuntime operationresponse = 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')Invoke Your Agent
import boto3import json
# Initialize the AgentCore Runtime clientagent_core_client = boto3.client('bedrock-agentcore')
# Prepare the payloadpayload = json.dumps({"prompt": prompt}).encode()
# Invoke the agentresponse = 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
Section titled âOption B: Custom AgentâThis section is complete - follow all steps below if you choose 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
/invocationsEndpoint: POST endpoint for agent interactions (REQUIRED)/pingEndpoint: GET endpoint for health checks (REQUIRED)- Container Engine: Docker, Finch, or Podman (required for this example)
- Docker Container: ARM64 containerized deployment package
Step 1: Quick Start Setup
Section titled âStep 1: Quick Start SetupâInstall uv
curl -LsSf https://astral.sh/uv/install.sh | shCreate Project
mkdir my-custom-agent && cd my-custom-agentuv init --python 3.11uv add fastapi 'uvicorn[standard]' pydantic httpx strands-agentsProject Structure example
my-custom-agent/âââ agent.py # FastAPI applicationâââ Dockerfile # ARM64 container configurationâââ pyproject.toml # Created by uv initâââ uv.lock # Created automatically by uvStep 2: Prepare your agent code
Section titled âStep 2: Prepare your agent codeâExample: agent.py
from fastapi import FastAPI, HTTPExceptionfrom pydantic import BaseModelfrom typing import Dict, Anyfrom datetime import datetime,timezonefrom strands import Agent
app = FastAPI(title="Strands Agent Server", version="1.0.0")
# Initialize Strands agentstrands_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)Step 3: Test Locally
Section titled âStep 3: Test Locallyâ# Run the applicationuv run uvicorn agent:app --host 0.0.0.0 --port 8080
# Test /ping endpointcurl http://localhost:8080/ping
# Test /invocations endpointcurl -X POST http://localhost:8080/invocations \ -H "Content-Type: application/json" \ -d '{ "input": {"prompt": "What is artificial intelligence?"} }'Step 4: Prepare your docker image
Section titled âStep 4: Prepare your docker imageâCreate docker file
# Use uv's ARM64 Python base imageFROM --platform=linux/arm64 ghcr.io/astral-sh/uv:python3.11-bookworm-slim
WORKDIR /app
# Copy uv filesCOPY pyproject.toml uv.lock ./
# Install dependencies (including strands-agents)RUN uv sync --frozen --no-cache
# Copy agent fileCOPY agent.py ./
# Expose portEXPOSE 8080
# Run applicationCMD ["uv", "run", "uvicorn", "agent:app", "--host", "0.0.0.0", "--port", "8080"]Setup Docker buildx
docker buildx create --useBuild and Test Locally
# Build the imagedocker buildx build --platform linux/arm64 -t my-agent:arm64 --load .
# Test locally with credentialsdocker 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:arm64Deploy to ECR
# Create ECR repositoryaws ecr create-repository --repository-name my-strands-agent --region us-west-2
# Login to ECRaws 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 ECRdocker buildx build --platform linux/arm64 -t <account-id>.dkr.ecr.us-west-2.amazonaws.com/my-strands-agent:latest --push .
# Verify the imageaws ecr describe-images --repository-name my-strands-agent --region us-west-2Step 5: Deploy Agent Runtime
Section titled âStep 5: Deploy Agent RuntimeâExample: 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']}")Execute python file
uv run deploy_agent.pyStep 6: Invoke Your Agent
Section titled âStep 6: Invoke Your AgentâExample: invoke_agent.py
import boto3import 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)Execute python file
uv run invoke_agent.pyExpected 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
Section titled âShared InformationâThis section applies to both deployment approaches - reference as needed regardless of which option you chose.
AgentCore Runtime Requirements Summary
Section titled âAgentCore Runtime Requirements Summaryâ- Platform: Must be linux/arm64
- Endpoints:
/invocationsPOST and/pingGET 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
Section titled âBest PracticesâDevelopment
- Test locally before deployment
- Use version control
- Keep dependencies updated
Configuration
- Use appropriate IAM roles
- Implement proper error handling
- Monitor agent performance
Security
- Follow the least privilege principle
- Secure sensitive information
- Regular security updates
Troubleshooting
Section titled âTroubleshootingâDeployment Failures
- Verify AWS credentials are configured correctly
- Check IAM role permissions
- Ensure container engine is running (for local testing with
agentcore launch --localor Option B custom deployments)
Runtime Errors
- Check CloudWatch logs
- Verify environment variables
- Test agent locally first
Container Issues
- Verify container engine installation (Docker, Finch, or Podman)
- Check port configurations
- Review Dockerfile if customized
Observability Enablement
Section titled â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.
Step 1: Enable CloudWatch Transaction Search
Section titled âStep 1: Enable CloudWatch Transaction Searchâ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
- Open the CloudWatch console
- Navigate to Application Signals (APM) > Transaction search
- Choose âEnable Transaction Searchâ
- Select the checkbox to ingest spans as structured logs
- Optionally adjust the X-Ray trace indexing percentage (default is 1%)
- Choose Save
Step 2: Add ADOT to Your Strands Agent
Section titled âStep 2: Add ADOT to Your Strands AgentâAdd to your requirements.txt:
aws-opentelemetry-distro>=0.10.1boto3Or install directly:
pip install aws-opentelemetry-distro>=0.10.1 boto3Run 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"]Step 3: Viewing Your Agentâs Observability Data
Section titled âStep 3: Viewing Your Agentâs Observability Dataâ- Open the CloudWatch console
- Navigate to the GenAI Observability page
- Find your agent service
- View traces, metrics, and logs
Session ID support
Section titled â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 baggagecontext.attach(ctx)Enhanced AgentCore observability with custom headers (Optional)
Section titled â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 responseCommon Tracing Headers Examples:
| 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
Best Practices
Section titled â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
- Keep your AgentCore Runtime and Strands packages updated for latest features and security fixes