AWS AI Services
AWS SageMaker vs Amazon Bedrock: Choosing the Right AI Service
Comprehensive comparison of AWS SageMaker and Amazon Bedrock for Australian businesses, covering use cases, cost analysis, and decision framework for selecting the right AI platform.
CloudPoint Team
Choosing between AWS SageMaker and Amazon Bedrock is one of the most important decisions when building AI applications on AWS. Both services enable machine learning and AI, but they serve different purposes, require different expertise levels, and suit different use cases. For Australian businesses, understanding these differences is crucial for successful AI implementation.
Service Overview
Amazon Bedrock
Amazon Bedrock provides serverless access to pre-trained foundation models from leading AI providers. It’s designed for rapid deployment of generative AI applications without requiring machine learning expertise.
Key Characteristics:
- Fully managed foundation models
- No ML expertise required
- Pay-per-use pricing
- Immediate availability
- Focus on generative AI
- API-first interaction
AWS SageMaker
AWS SageMaker is a comprehensive machine learning platform for building, training, and deploying custom ML models. It provides complete control over the ML lifecycle and supports any ML use case.
Key Characteristics:
- Full ML platform
- Requires ML expertise
- Custom model development
- Complete lifecycle management
- Traditional and generative AI
- Infrastructure management required
Core Differences
1. Model Source
Bedrock:
- Pre-trained foundation models
- Models from Anthropic, AI21, Cohere, Meta, Stability AI, Amazon
- Ready to use immediately
- Cannot modify model architecture
- Can customise through fine-tuning
SageMaker:
- Build models from scratch
- Use pre-trained models from anywhere
- Access to SageMaker JumpStart models
- Full control over architecture
- Complete customisation capability
2. Use Cases
Bedrock Excels At:
- Text generation and analysis
- Chatbots and conversational AI
- Content creation
- Document summarisation
- Code generation
- Sentiment analysis
- Quick AI integration
SageMaker Excels At:
- Custom prediction models
- Computer vision (object detection, classification)
- Time series forecasting
- Anomaly detection
- Recommendation systems
- Fraud detection
- Any supervised/unsupervised learning task
3. Expertise Required
Bedrock:
# Minimal ML knowledge needed
import boto3
import json
bedrock = boto3.client('bedrock-runtime', region_name='ap-southeast-2')
response = bedrock.invoke_model(
modelId='anthropic.claude-v2',
body=json.dumps({
"prompt": "\n\nHuman: Summarise this document\n\nAssistant:",
"max_tokens_to_sample": 500
})
)
# Use response immediately
SageMaker:
# Requires ML expertise
import sagemaker
from sagemaker.estimator import Estimator
from sagemaker.inputs import TrainingInput
# Data preparation
train_data = preprocess_data(raw_data)
validation_data = split_validation(train_data)
# Model training
estimator = Estimator(
image_uri=training_image,
role=sagemaker_role,
instance_count=1,
instance_type='ml.p3.2xlarge',
hyperparameters={
'epochs': 50,
'learning_rate': 0.001,
'batch_size': 32
}
)
estimator.fit({
'train': TrainingInput(train_data_s3),
'validation': TrainingInput(val_data_s3)
})
# Deploy endpoint
predictor = estimator.deploy(
initial_instance_count=1,
instance_type='ml.m5.xlarge'
)
When to Use Bedrock
Ideal Scenarios
1. Generative AI Applications:
- Customer service chatbots
- Content generation platforms
- Document analysis tools
- Code generation assistants
- Marketing copy creation
2. Rapid Prototyping:
- Proof of concepts
- MVP development
- Quick experimentation
- Startup validation
3. Limited ML Resources:
- Small development teams
- No data science team
- Budget constraints for ML expertise
- Focus on application development
4. Standard AI Tasks:
- Text summarisation
- Sentiment analysis
- Entity extraction
- Question answering
- Translation
Bedrock Example Use Case
Australian Legal Document Analysis:
import boto3
import json
class LegalDocumentAnalyser:
def __init__(self):
self.bedrock = boto3.client(
'bedrock-runtime',
region_name='ap-southeast-2'
)
self.model_id = 'anthropic.claude-v2'
def extract_key_terms(self, document: str) -> dict:
"""Extract key terms and obligations from legal document."""
prompt = f"""Analyse this Australian legal document and extract:
1. Key parties involved
2. Primary obligations
3. Important dates and deadlines
4. Financial terms
5. Compliance requirements
Document:
{document}
Provide structured JSON output."""
response = self.bedrock.invoke_model(
modelId=self.model_id,
body=json.dumps({
"prompt": f"\n\nHuman: {prompt}\n\nAssistant:",
"max_tokens_to_sample": 2000,
"temperature": 0.3
})
)
result = json.loads(response['body'].read())
return self._parse_structured_output(result['completion'])
def assess_compliance(self, document: str, regulations: list) -> dict:
"""Check document against Australian regulations."""
regulations_text = "\n".join(regulations)
prompt = f"""Review this document for compliance with Australian regulations:
Regulations to check:
{regulations_text}
Document:
{document}
Identify:
1. Compliance issues
2. Missing clauses
3. Recommendations"""
response = self.bedrock.invoke_model(
modelId=self.model_id,
body=json.dumps({
"prompt": f"\n\nHuman: {prompt}\n\nAssistant:",
"max_tokens_to_sample": 3000,
"temperature": 0.2
})
)
result = json.loads(response['body'].read())
return {
'assessment': result['completion'],
'timestamp': datetime.utcnow().isoformat()
}
# Usage
analyser = LegalDocumentAnalyser()
contract = load_document('employment_contract.pdf')
# Extract key information
terms = analyser.extract_key_terms(contract)
# Check compliance
compliance = analyser.assess_compliance(contract, [
'Fair Work Act 2009',
'Privacy Act 1988',
'Work Health and Safety Act 2011'
])
Benefits of Using Bedrock:
- No ML model training required
- Immediate deployment
- Handles complex language understanding
- Scales automatically
- Cost-effective for variable workloads
When to Use SageMaker
Ideal Scenarios
1. Custom ML Models:
- Unique business problems
- Proprietary data patterns
- Competitive differentiation
- Specific performance requirements
2. Prediction Tasks:
- Sales forecasting
- Inventory optimisation
- Risk assessment
- Customer churn prediction
- Price optimisation
3. Computer Vision:
- Product quality inspection
- Defect detection
- Image classification
- Object detection
- Facial recognition
4. Specialised Domains:
- Healthcare diagnostics
- Financial fraud detection
- Manufacturing optimisation
- Supply chain prediction
- Energy consumption forecasting
SageMaker Example Use Case
Australian Retail Demand Forecasting:
import sagemaker
from sagemaker import get_execution_role
from sagemaker.deserializers import JSONDeserializer
from sagemaker.serializers import CSVSerializer
import pandas as pd
import numpy as np
class DemandForecastingModel:
def __init__(self):
self.role = get_execution_role()
self.session = sagemaker.Session()
self.bucket = self.session.default_bucket()
self.region = 'ap-southeast-2'
def prepare_data(self, sales_data: pd.DataFrame) -> str:
"""Prepare historical sales data for training."""
# Feature engineering
sales_data['date'] = pd.to_datetime(sales_data['date'])
sales_data['day_of_week'] = sales_data['date'].dt.dayofweek
sales_data['month'] = sales_data['date'].dt.month
sales_data['is_weekend'] = sales_data['day_of_week'].isin([5, 6]).astype(int)
sales_data['is_holiday'] = sales_data['date'].isin(
self._get_australian_holidays()
).astype(int)
# Add lagged features
for lag in [7, 14, 30]:
sales_data[f'sales_lag_{lag}'] = sales_data.groupby('product_id')['sales'].shift(lag)
# Rolling averages
sales_data['sales_rolling_7'] = sales_data.groupby('product_id')['sales'].rolling(7).mean().reset_index(0, drop=True)
sales_data['sales_rolling_30'] = sales_data.groupby('product_id')['sales'].rolling(30).mean().reset_index(0, drop=True)
# Handle missing values
sales_data = sales_data.fillna(0)
# Split train/validation
train_data = sales_data[sales_data['date'] < '2025-10-01']
validation_data = sales_data[sales_data['date'] >= '2025-10-01']
# Upload to S3
train_s3 = self._upload_to_s3(train_data, 'train.csv')
val_s3 = self._upload_to_s3(validation_data, 'validation.csv')
return train_s3, val_s3
def train_model(self, train_s3: str, val_s3: str) -> str:
"""Train XGBoost model for demand forecasting."""
from sagemaker.estimator import Estimator
from sagemaker.inputs import TrainingInput
# Configure XGBoost
container = sagemaker.image_uris.retrieve(
'xgboost',
self.region,
version='1.5-1'
)
xgb = Estimator(
container,
self.role,
instance_count=1,
instance_type='ml.m5.xlarge',
output_path=f's3://{self.bucket}/output',
sagemaker_session=self.session,
base_job_name='retail-demand-forecast'
)
# Set hyperparameters
xgb.set_hyperparameters(
objective='reg:squarederror',
num_round=100,
max_depth=6,
eta=0.1,
subsample=0.8,
colsample_bytree=0.8,
eval_metric='rmse'
)
# Train
xgb.fit({
'train': TrainingInput(train_s3, content_type='text/csv'),
'validation': TrainingInput(val_s3, content_type='text/csv')
})
return xgb
def deploy_model(self, estimator) -> str:
"""Deploy model to endpoint."""
predictor = estimator.deploy(
initial_instance_count=1,
instance_type='ml.t2.medium',
endpoint_name='demand-forecast-endpoint',
serializer=CSVSerializer(),
deserializer=JSONDeserializer()
)
return predictor.endpoint_name
def predict_demand(
self,
endpoint_name: str,
product_id: str,
forecast_date: str
) -> dict:
"""Generate demand forecast for product."""
from sagemaker.predictor import Predictor
predictor = Predictor(
endpoint_name=endpoint_name,
serializer=CSVSerializer(),
deserializer=JSONDeserializer()
)
# Prepare features
features = self._prepare_forecast_features(product_id, forecast_date)
# Get prediction
prediction = predictor.predict(features)
return {
'product_id': product_id,
'forecast_date': forecast_date,
'predicted_sales': prediction['predictions'][0]['score'],
'confidence_interval': self._calculate_confidence_interval(prediction)
}
def _get_australian_holidays(self) -> list:
"""Return Australian public holidays."""
return [
'2025-01-01', # New Year's Day
'2025-01-27', # Australia Day
'2025-04-18', # Good Friday
'2025-04-21', # Easter Monday
'2025-04-25', # ANZAC Day
'2025-06-09', # Queen's Birthday
'2025-12-25', # Christmas Day
'2025-12-26', # Boxing Day
]
# Usage
forecaster = DemandForecastingModel()
# Load historical sales data
sales_data = pd.read_csv('sales_history.csv')
# Prepare and train
train_s3, val_s3 = forecaster.prepare_data(sales_data)
model = forecaster.train_model(train_s3, val_s3)
# Deploy
endpoint = forecaster.deploy_model(model)
# Generate forecasts
forecast = forecaster.predict_demand(
endpoint_name=endpoint,
product_id='PROD-12345',
forecast_date='2025-12-15'
)
print(f"Predicted sales: {forecast['predicted_sales']:.0f} units")
Benefits of Using SageMaker:
- Custom model for specific business patterns
- Incorporates domain knowledge
- Optimised for prediction accuracy
- Handles complex feature engineering
- Full control over model behaviour
Cost Comparison
Bedrock Pricing
Pay-per-token model:
# Example cost calculation for Bedrock
def calculate_bedrock_cost(
input_tokens: int,
output_tokens: int,
model: str = 'claude-v2'
) -> float:
"""Calculate Bedrock usage cost in AUD."""
pricing = {
'claude-v2': {
'input': 0.01102, # $0.01102 per 1K tokens (converted to AUD)
'output': 0.03306 # $0.03306 per 1K tokens
},
'titan-text': {
'input': 0.0004,
'output': 0.0006
}
}
rates = pricing[model]
input_cost = (input_tokens / 1000) * rates['input']
output_cost = (output_tokens / 1000) * rates['output']
return input_cost + output_cost
# Example: 1 million requests with 500 input, 200 output tokens
monthly_requests = 1_000_000
cost = calculate_bedrock_cost(500, 200) * monthly_requests
print(f"Monthly cost: ${cost:,.2f} AUD")
# Output: Monthly cost: $12,120.00 AUD
Bedrock cost characteristics:
- No infrastructure costs
- No minimum commitment
- Scales to zero when not used
- Predictable per-request pricing
- Higher per-request cost than SageMaker at scale
SageMaker Pricing
Infrastructure-based model:
# Example cost calculation for SageMaker
def calculate_sagemaker_cost(
instance_type: str,
instance_count: int,
hours_per_month: int = 730 # Average month
) -> dict:
"""Calculate SageMaker endpoint cost in AUD."""
# Prices in AUD per hour (ap-southeast-2)
pricing = {
'ml.t2.medium': 0.065,
'ml.m5.large': 0.134,
'ml.m5.xlarge': 0.268,
'ml.c5.xlarge': 0.238,
'ml.p3.2xlarge': 4.862, # GPU instance for training
}
hourly_rate = pricing[instance_type] * instance_count
monthly_cost = hourly_rate * hours_per_month
return {
'hourly_rate': hourly_rate,
'monthly_cost': monthly_cost,
'annual_cost': monthly_cost * 12
}
# Example: Production endpoint
endpoint_cost = calculate_sagemaker_cost('ml.m5.large', 2)
print(f"Monthly endpoint cost: ${endpoint_cost['monthly_cost']:,.2f} AUD")
# Output: Monthly endpoint cost: $195.64 AUD
# Example: Training job (one-time)
training_cost = calculate_sagemaker_cost('ml.p3.2xlarge', 1, hours_per_month=10)
print(f"Training job cost: ${training_cost['monthly_cost']:,.2f} AUD")
# Output: Training job cost: $48.62 AUD
SageMaker cost characteristics:
- Fixed infrastructure costs
- Runs continuously (unless using serverless)
- Lower per-request cost at scale
- Training costs separate from inference
- Requires capacity planning
Cost Comparison Scenarios
Low Volume (10,000 requests/month):
# Bedrock
bedrock_cost = calculate_bedrock_cost(500, 200) * 10_000
# $121.20 AUD/month
# SageMaker (ml.t2.medium)
sagemaker_cost = calculate_sagemaker_cost('ml.t2.medium', 1)
# $47.45 AUD/month
# Winner: SageMaker (but may be over-provisioned)
Medium Volume (500,000 requests/month):
# Bedrock
bedrock_cost = calculate_bedrock_cost(500, 200) * 500_000
# $6,060 AUD/month
# SageMaker (ml.m5.large with auto-scaling)
sagemaker_cost = calculate_sagemaker_cost('ml.m5.large', 2)
# $195.64 AUD/month
# Winner: SageMaker (significant savings)
High Volume (5,000,000 requests/month):
# Bedrock
bedrock_cost = calculate_bedrock_cost(500, 200) * 5_000_000
# $60,600 AUD/month
# SageMaker (ml.m5.xlarge with auto-scaling)
sagemaker_cost = calculate_sagemaker_cost('ml.m5.xlarge', 3)
# $586.92 AUD/month
# Winner: SageMaker (massive savings at scale)
Decision Framework
Choose Bedrock When
✅ Building generative AI applications ✅ Need rapid deployment (days, not months) ✅ Limited ML expertise on team ✅ Variable or unpredictable workload ✅ Standard NLP/text generation tasks ✅ Low to medium request volumes ✅ Prototype or MVP stage ✅ Cannot maintain ML infrastructure
Choose SageMaker When
✅ Building custom prediction models ✅ High request volumes (>100K/month) ✅ Specific accuracy requirements ✅ Computer vision applications ✅ Complex feature engineering needed ✅ Have ML expertise on team ✅ Need full model control ✅ Long-term production deployment
Decision Tree
Start
│
├─ Generative AI (text, chat, content)?
│ ├─ Yes → Bedrock
│ └─ No → Continue
│
├─ Need custom model for predictions?
│ ├─ Yes → SageMaker
│ └─ No → Continue
│
├─ Computer vision or image processing?
│ ├─ Yes → SageMaker
│ └─ No → Continue
│
├─ Have ML team or expertise?
│ ├─ Yes → SageMaker (likely)
│ ├─ No → Bedrock (likely)
│ └─ Uncertain → Continue
│
├─ Request volume >100K/month?
│ ├─ Yes → SageMaker (cost-effective)
│ └─ No → Bedrock (simpler)
│
└─ Need rapid deployment (<1 week)?
├─ Yes → Bedrock
└─ No → Evaluate both
Using Both Together
Many applications benefit from using both services:
Hybrid Architecture Example
E-commerce Platform:
class HybridAIEcommercePlatform:
def __init__(self):
# Bedrock for generative AI
self.bedrock = boto3.client('bedrock-runtime', region_name='ap-southeast-2')
# SageMaker for predictions
self.sagemaker_runtime = boto3.client('sagemaker-runtime', region_name='ap-southeast-2')
self.product_recommender_endpoint = 'product-recommendations-endpoint'
self.chatbot_model = 'anthropic.claude-v2'
def generate_product_description(self, product_data: dict) -> str:
"""Use Bedrock to generate engaging product descriptions."""
prompt = f"""Create an engaging product description for Australian customers:
Product: {product_data['name']}
Category: {product_data['category']}
Features: {', '.join(product_data['features'])}
Price: ${product_data['price']} AUD
Write a compelling 2-3 paragraph description highlighting benefits."""
response = self.bedrock.invoke_model(
modelId=self.chatbot_model,
body=json.dumps({
"prompt": f"\n\nHuman: {prompt}\n\nAssistant:",
"max_tokens_to_sample": 500
})
)
result = json.loads(response['body'].read())
return result['completion']
def get_product_recommendations(self, user_id: str, context: dict) -> list:
"""Use SageMaker to predict personalised product recommendations."""
# Prepare features
features = self._prepare_recommendation_features(user_id, context)
# Get predictions from SageMaker model
response = self.sagemaker_runtime.invoke_endpoint(
EndpointName=self.product_recommender_endpoint,
ContentType='text/csv',
Body=features
)
predictions = json.loads(response['Body'].read())
return predictions['recommendations']
def handle_customer_query(self, query: str, customer_context: dict) -> dict:
"""Use Bedrock for conversational AI, SageMaker for personalisation."""
# Get personalised recommendations from SageMaker
recommendations = self.get_product_recommendations(
customer_context['user_id'],
customer_context
)
# Generate conversational response with Bedrock
prompt = f"""You are a helpful Australian e-commerce assistant.
Customer query: {query}
Recommended products:
{self._format_recommendations(recommendations)}
Provide a helpful response incorporating these recommendations naturally."""
response = self.bedrock.invoke_model(
modelId=self.chatbot_model,
body=json.dumps({
"prompt": f"\n\nHuman: {prompt}\n\nAssistant:",
"max_tokens_to_sample": 800
})
)
result = json.loads(response['Body'].read())
return {
'response': result['completion'],
'recommendations': recommendations,
'source': 'hybrid_ai'
}
# Usage
platform = HybridAIEcommercePlatform()
# Generate content with Bedrock
description = platform.generate_product_description({
'name': 'Wireless Noise-Cancelling Headphones',
'category': 'Electronics',
'features': ['40-hour battery', 'Bluetooth 5.0', 'Active noise cancellation'],
'price': 349.99
})
# Get recommendations with SageMaker
recommendations = platform.get_product_recommendations(
user_id='user123',
context={'current_category': 'electronics', 'price_range': 'premium'}
)
# Combined conversational AI
response = platform.handle_customer_query(
query="I'm looking for headphones for my daily commute",
customer_context={'user_id': 'user123', 'location': 'Sydney'}
)
Benefits of hybrid approach:
- Use Bedrock for generative AI (content, chat)
- Use SageMaker for predictions (recommendations, forecasting)
- Optimise cost for each use case
- Best tool for each job
Migration Scenarios
From Bedrock to SageMaker
When to migrate:
- Request volume exceeds cost-effectiveness threshold
- Need custom model for better accuracy
- Require specific performance characteristics
- Want full control over model behaviour
Migration path:
# Phase 1: Bedrock baseline
class Phase1BedrockImplementation:
def classify_text(self, text: str) -> dict:
bedrock = boto3.client('bedrock-runtime', region_name='ap-southeast-2')
response = bedrock.invoke_model(
modelId='anthropic.claude-v2',
body=json.dumps({
"prompt": f"\n\nHuman: Classify this text into categories: {text}\n\nAssistant:",
"max_tokens_to_sample": 100
})
)
return json.loads(response['body'].read())
# Phase 2: Collect training data from Bedrock usage
class Phase2DataCollection:
def collect_training_data(self, text: str, bedrock_result: dict) -> None:
"""Store Bedrock inputs and outputs for model training."""
training_sample = {
'input': text,
'output': bedrock_result,
'timestamp': datetime.utcnow().isoformat()
}
# Store in S3 for SageMaker training
self._store_training_sample(training_sample)
# Phase 3: Train custom SageMaker model
class Phase3SageMakerModel:
def train_custom_classifier(self, training_data_s3: str) -> str:
"""Train custom model using collected data."""
# Use collected Bedrock data to train custom model
estimator = self._create_estimator()
estimator.fit(training_data_s3)
return estimator.deploy(
initial_instance_count=1,
instance_type='ml.m5.large'
)
# Phase 4: A/B test and gradual migration
class Phase4Migration:
def __init__(self):
self.bedrock_client = Phase1BedrockImplementation()
self.sagemaker_endpoint = 'custom-classifier-endpoint'
self.sagemaker_runtime = boto3.client('sagemaker-runtime')
def classify_with_routing(self, text: str, user_segment: str) -> dict:
"""Route traffic between Bedrock and SageMaker."""
# Gradual migration: 80% SageMaker, 20% Bedrock
if hash(text) % 100 < 80:
return self._classify_with_sagemaker(text)
else:
return self.bedrock_client.classify_text(text)
From SageMaker to Bedrock
When to migrate:
- Generative AI capabilities needed
- Want to reduce infrastructure management
- Lower request volumes make Bedrock cost-effective
- Standard NLP tasks don’t need custom model
Migration considerations:
- Assess if foundation models meet accuracy requirements
- Test with representative workload
- Compare costs at expected scale
- Plan for model customisation if needed
Australian Compliance Considerations
Data Sovereignty
Both services:
# Always specify Sydney region
bedrock = boto3.client('bedrock-runtime', region_name='ap-southeast-2')
sagemaker = boto3.client('sagemaker', region_name='ap-southeast-2')
# Verify data stays in Australia
# Configure VPC endpoints for private connectivity
industry regulations
Security requirements:
- Both services support encryption at rest and in transit
- Both integrate with CloudWatch for monitoring
- Both support VPC endpoints for private access
- SageMaker requires more security configuration
Risk management:
- Bedrock: Lower operational risk (fully managed)
- SageMaker: Higher operational risk (more components to secure)
Privacy Act Compliance
Data handling:
- Bedrock: Data not used for model training, no retention
- SageMaker: Full control over data storage and usage
- Both: Document data flows in privacy assessments
Conclusion
Choosing between Bedrock and SageMaker depends on your use case, team capabilities, scale, and requirements:
Choose Bedrock for generative AI applications, rapid deployment, and when ML expertise is limited. It’s ideal for chatbots, content generation, and document analysis.
Choose SageMaker for custom prediction models, computer vision, high-volume applications, and when you have ML expertise. It’s ideal for forecasting, recommendations, and specialised ML tasks.
Use both when building comprehensive AI applications that need generative AI capabilities and custom prediction models.
CloudPoint helps Australian businesses select and implement the right AI services for their needs. We provide architecture consulting, cost analysis, proof of concept development, and production implementation for both Bedrock and SageMaker.
Contact us for an AI strategy consultation and build the right AI solution for your business.
Need Help Choosing Between SageMaker and Bedrock?
CloudPoint helps Australian businesses select and implement the right AI approach for their needs. Get in touch to discuss your requirements.