AWS AI Services for Developers: Bedrock, SageMaker, and Beyond
AWS has the widest catalog of AI services of any cloud provider. The challenge isn't finding services — it's knowing which ones to use for which problem. This post focuses on the services that matter most for application developers: Bedrock for LLM access, SageMaker for model deployment, and a few specialized services worth knowing.
The AWS AI Service Map
| Service | What It Does |
|---|---|
| Amazon Bedrock | Access to Claude, Llama, Mistral, Titan via API |
| SageMaker | Train, fine-tune, and deploy ML models |
| Amazon Textract | OCR, table extraction, form parsing from documents |
| Amazon Comprehend | NLP: sentiment, entities, language detection |
| Amazon Rekognition | Image and video analysis |
| Amazon Transcribe | Speech-to-text |
| Amazon Polly | Text-to-speech |
| Amazon Kendra | Enterprise search with ML ranking |
| Amazon Q | Enterprise AI assistant, connected to your data sources |
Amazon Bedrock
Bedrock is AWS's managed LLM service — it gives you API access to foundation models from Anthropic (Claude), Meta (Llama), Mistral, AI21, and Amazon's own Titan models. No model management, no GPU infrastructure.
Setup
pip install boto3
aws configure # or use IAM roleCalling Claude via Bedrock
import boto3
import json
client = boto3.client("bedrock-runtime", region_name="us-east-1")
response = client.invoke_model(
modelId="anthropic.claude-sonnet-4-6-20251001-v1:0",
body=json.dumps({
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "What's the capital of France?"}
]
})
)
result = json.loads(response["body"].read())
print(result["content"][0]["text"])Calling Llama 3
response = client.invoke_model(
modelId="meta.llama3-70b-instruct-v1:0",
body=json.dumps({
"prompt": "<|begin_of_text|><|start_header_id|>user<|end_header_id|>\nExplain RAG in one paragraph<|eot_id|><|start_header_id|>assistant<|end_header_id|>",
"max_gen_len": 512,
"temperature": 0.5
})
)
result = json.loads(response["body"].read())
print(result["generation"])Streaming with Bedrock
response = client.invoke_model_with_response_stream(
modelId="anthropic.claude-sonnet-4-6-20251001-v1:0",
body=json.dumps({
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 2048,
"messages": [{"role": "user", "content": prompt}]
})
)
stream = response.get("body")
for event in stream:
chunk = event.get("chunk")
if chunk:
data = json.loads(chunk.get("bytes").decode())
if data.get("type") == "content_block_delta":
print(data["delta"].get("text", ""), end="", flush=True)Bedrock Knowledge Bases
Bedrock Knowledge Bases is AWS's managed RAG service. You point it at an S3 bucket, it handles chunking, embedding, and indexing. At query time, it retrieves relevant chunks and passes them to the model.
import boto3
bedrock_agent = boto3.client("bedrock-agent-runtime", region_name="us-east-1")
response = bedrock_agent.retrieve_and_generate(
input={"text": "What is our return policy?"},
retrieveAndGenerateConfiguration={
"type": "KNOWLEDGE_BASE",
"knowledgeBaseConfiguration": {
"knowledgeBaseId": "YOUR_KB_ID",
"modelArn": "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-sonnet-4-6-20251001-v1:0",
"retrievalConfiguration": {
"vectorSearchConfiguration": {
"numberOfResults": 5
}
}
}
}
)
print(response["output"]["text"])
# Citations
for citation in response.get("citations", []):
for ref in citation.get("retrievedReferences", []):
print("Source:", ref["location"]["s3Location"]["uri"])Just Retrieval (no generation)
response = bedrock_agent.retrieve(
knowledgeBaseId="YOUR_KB_ID",
retrievalQuery={"text": "refund policy"},
retrievalConfiguration={
"vectorSearchConfiguration": {"numberOfResults": 5}
}
)
for result in response["retrievalResults"]:
print(f"[{result['score']:.3f}] {result['content']['text'][:200]}")Bedrock Agents
Bedrock Agents lets you build agentic systems where Claude can call your Lambda functions, query your knowledge bases, and execute multi-step tasks.
import boto3
bedrock_agent_runtime = boto3.client("bedrock-agent-runtime", region_name="us-east-1")
response = bedrock_agent_runtime.invoke_agent(
agentId="YOUR_AGENT_ID",
agentAliasId="YOUR_ALIAS_ID",
sessionId="session-123",
inputText="Look up order #4521 and tell me its current status"
)
# Collect streamed response
output = ""
for event in response["completion"]:
if "chunk" in event:
chunk = event["chunk"]
output += chunk["bytes"].decode()
print(output)The Lambda functions you attach as action groups handle the actual tool execution. AWS manages the orchestration loop.
Amazon SageMaker
SageMaker is AWS's full ML platform. For application developers, the most relevant parts are:
- SageMaker Endpoints — deploy any model as a REST API
- SageMaker Batch Transform — run inference on large datasets at scale
- SageMaker Jumpstart — pre-built notebooks and deployable models
Deploy a Hugging Face Model
from sagemaker.huggingface import HuggingFaceModel
import sagemaker
role = sagemaker.get_execution_role()
hub = {
"HF_MODEL_ID": "sentence-transformers/all-MiniLM-L6-v2",
"HF_TASK": "feature-extraction"
}
model = HuggingFaceModel(
env=hub,
role=role,
transformers_version="4.37",
pytorch_version="2.1",
py_version="py310"
)
predictor = model.deploy(
initial_instance_count=1,
instance_type="ml.m5.large"
)
# Call the endpoint
embeddings = predictor.predict({
"inputs": ["Hello world", "Goodbye world"]
})Batch Transform for Large Datasets
from sagemaker.huggingface import HuggingFaceModel
model = HuggingFaceModel(
model_data="s3://my-bucket/model.tar.gz",
role=role,
transformers_version="4.37",
pytorch_version="2.1",
py_version="py310"
)
transformer = model.transformer(
instance_count=2,
instance_type="ml.g4dn.xlarge",
output_path="s3://my-bucket/results/"
)
transformer.transform(
data="s3://my-bucket/inputs/",
content_type="application/json",
split_type="Line"
)
transformer.wait()Amazon Textract
Textract extracts text, tables, and forms from PDFs and images — including scanned documents that aren't machine-readable.
import boto3
textract = boto3.client("textract", region_name="us-east-1")
# From S3
response = textract.analyze_document(
Document={"S3Object": {"Bucket": "my-bucket", "Name": "contract.pdf"}},
FeatureTypes=["TABLES", "FORMS"]
)
# Extract plain text
for block in response["Blocks"]:
if block["BlockType"] == "LINE":
print(block["Text"])
# Extract tables
tables = [b for b in response["Blocks"] if b["BlockType"] == "TABLE"]
print(f"Found {len(tables)} tables")
# Extract key-value pairs (forms)
key_map, value_map, block_map = {}, {}, {}
for block in response["Blocks"]:
block_map[block["Id"]] = block
if block["BlockType"] == "KEY_VALUE_SET":
if "KEY" in block.get("EntityTypes", []):
key_map[block["Id"]] = block
else:
value_map[block["Id"]] = block
for key_id, key_block in key_map.items():
key_text = " ".join(
block_map[rel["Ids"][0]]["Text"]
for rel in key_block.get("Relationships", [])
if rel["Type"] == "CHILD"
)
# Get corresponding value...
print(f"Key: {key_text}")Async for Large Documents
# Start async job
response = textract.start_document_analysis(
DocumentLocation={"S3Object": {"Bucket": "my-bucket", "Name": "large-doc.pdf"}},
FeatureTypes=["TABLES", "FORMS"]
)
job_id = response["JobId"]
# Poll until done
import time
while True:
result = textract.get_document_analysis(JobId=job_id)
status = result["JobStatus"]
if status in ("SUCCEEDED", "FAILED"):
break
time.sleep(5)
if status == "SUCCEEDED":
# Handle paginated results
pages = [result]
next_token = result.get("NextToken")
while next_token:
result = textract.get_document_analysis(JobId=job_id, NextToken=next_token)
pages.append(result)
next_token = result.get("NextToken")Production Architecture on AWS
A typical production AI app on AWS looks like this:
User request
↓
API Gateway → Lambda (or ECS)
↓
Amazon Bedrock (Claude / Llama)
↑
Bedrock Knowledge Base ← S3 (your documents)
↑
OpenSearch Serverless (vector store)
Key decisions:
- Lambda for request/response under 15 minutes; ECS Fargate for long-running agents
- Bedrock Knowledge Bases if you want zero-infrastructure RAG; custom RAG if you need fine-grained control
- S3 + Lambda for async document processing pipelines
- SQS between Lambda functions to decouple and handle retries
When to Use AWS AI vs. Azure vs. Direct Providers
| Factor | AWS | Azure | Direct Provider |
|---|---|---|---|
| Existing cloud infra | AWS is the winner | Azure if already on EA | Doesn't matter |
| Claude / Anthropic access | Bedrock | Not available | Direct API |
| Open-source model deployment | SageMaker / Bedrock | Azure AI Foundry | Own infrastructure |
| Compliance (HIPAA, FedRAMP) | Strong coverage | Strong coverage | Provider-dependent |
| Billing consolidation | Through AWS credits | Through Azure credits | Separate billing |
| Lowest latency to model | Direct API wins | Direct API wins | ✓ |
AWS Bedrock is the best choice when you're already on AWS and want Claude or open-source models without managing model infrastructure. For greenfield projects, direct provider APIs are simpler to start with.