← Blog

AWS AI Services for Developers: Bedrock, SageMaker, and Beyond

·6 min read·AWSAIBedrockSageMakerCloudPythonLLM

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

ServiceWhat It Does
Amazon BedrockAccess to Claude, Llama, Mistral, Titan via API
SageMakerTrain, fine-tune, and deploy ML models
Amazon TextractOCR, table extraction, form parsing from documents
Amazon ComprehendNLP: sentiment, entities, language detection
Amazon RekognitionImage and video analysis
Amazon TranscribeSpeech-to-text
Amazon PollyText-to-speech
Amazon KendraEnterprise search with ML ranking
Amazon QEnterprise 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 role

Calling 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

FactorAWSAzureDirect Provider
Existing cloud infraAWS is the winnerAzure if already on EADoesn't matter
Claude / Anthropic accessBedrockNot availableDirect API
Open-source model deploymentSageMaker / BedrockAzure AI FoundryOwn infrastructure
Compliance (HIPAA, FedRAMP)Strong coverageStrong coverageProvider-dependent
Billing consolidationThrough AWS creditsThrough Azure creditsSeparate billing
Lowest latency to modelDirect API winsDirect 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.