How to Set Up AWS Bedrock with Claude: A Complete Guide with Code Examples

What Is AWS Bedrock?

AWS Bedrock is Amazon’s managed AI platform that provides API access to a curated selection of foundation models from multiple providers — Anthropic’s Claude, Meta’s Llama, Mistral AI, Cohere, Amazon’s own Titan models, and others — through a unified AWS API. Rather than integrating with each model provider separately, Bedrock gives you access to all of them through a single SDK with consistent authentication, logging, and network controls.

The key advantages of Bedrock over going directly to model providers are tight AWS ecosystem integration (CloudWatch logging, IAM authentication, VPC endpoints, AWS Cost Explorer billing), consistency across providers (same SDK, same auth flow, same monitoring regardless of which model you use), and access to AWS-specific features like Bedrock Agents for no-code agent building, Bedrock Knowledge Bases for managed RAG, and Bedrock Guardrails for content filtering.

Setting Up Bedrock Access

Bedrock requires two setup steps: enabling model access in your AWS account (models are disabled by default) and configuring IAM permissions.

# Install the AWS SDK
pip install boto3 anthropic-bedrock
# In the AWS Console: go to Amazon Bedrock -> Model access
# Request access to Anthropic Claude models (takes ~1-5 minutes to activate)

# Configure AWS credentials
aws configure
# or set environment variables:
# AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION

Your IAM user or role needs the bedrock:InvokeModel permission. A minimal IAM policy:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"],
    "Resource": "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-*"
  }]
}

Calling Claude via Bedrock

Use the Anthropic SDK’s Bedrock client — it handles the Bedrock API format automatically:

import anthropic

# AnthropicBedrock client — uses AWS credentials automatically
client = anthropic.AnthropicBedrock(
    aws_region="us-east-1"  # Must match the region where you enabled model access
)

message = client.messages.create(
    model="anthropic.claude-sonnet-4-5",  # Bedrock uses different model IDs
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain AWS Bedrock in two paragraphs."}]
)
print(message.content[0].text)

Bedrock model IDs differ from Anthropic’s direct API IDs — they follow the format anthropic.claude-{version}. Check the Bedrock console for the exact current model IDs as they update with new releases. The rest of the API — messages format, tool use, streaming, system prompts — is identical to the standard Anthropic API.

Using boto3 Directly

Alternatively, use boto3 with the Bedrock runtime client for more control over the raw API:

import boto3, json

bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")

body = json.dumps({
    "anthropic_version": "bedrock-2023-05-31",
    "max_tokens": 1024,
    "messages": [{"role":"user","content":"Explain serverless computing."}]
})

response = bedrock.invoke_model(
    modelId="anthropic.claude-sonnet-4-5",
    body=body
)

result = json.loads(response["body"].read())
print(result["content"][0]["text"])

The boto3 approach gives you direct access to the raw HTTP response, which is useful when building custom middleware or when you need to handle the response at a lower level than the Anthropic SDK provides.

Streaming Responses

# With AnthropicBedrock client (recommended)
with client.messages.stream(
    model="anthropic.claude-sonnet-4-5",
    max_tokens=1024,
    messages=[{"role":"user","content":"Write a Python function for binary search."}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

# With boto3 invoke_model_with_response_stream
response = bedrock.invoke_model_with_response_stream(
    modelId="anthropic.claude-sonnet-4-5",
    body=json.dumps({"anthropic_version":"bedrock-2023-05-31","max_tokens":1024,
                     "messages":[{"role":"user","content":"Explain RLHF."}]})
)
for event in response["body"]:
    chunk = json.loads(event["chunk"]["bytes"])
    if chunk["type"] == "content_block_delta":
        print(chunk["delta"].get("text",""), end="", flush=True)

IAM Roles and Authentication in Production

For production deployments on AWS infrastructure (EC2, Lambda, ECS, EKS), use IAM roles rather than access keys. Attach a role with Bedrock permissions to your compute resource — the AWS SDK automatically picks up the role credentials without any explicit configuration:

# On EC2/ECS/Lambda — no credential configuration needed
# The SDK reads credentials from the instance metadata service

import boto3
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
# That's it — credentials come from the IAM role attached to the instance

This is significantly more secure than embedding access keys in environment variables or code. Keys can be accidentally exposed in logs or version control; IAM role credentials are temporary and automatically rotated.

VPC Endpoints for Private Access

For workloads where prompts must not traverse the public internet, configure a VPC endpoint for Bedrock:

aws ec2 create-vpc-endpoint   --vpc-id vpc-xxxxxxxxxx   --service-name com.amazonaws.us-east-1.bedrock-runtime   --vpc-endpoint-type Interface   --subnet-ids subnet-xxxxxxxxxx   --security-group-ids sg-xxxxxxxxxx

With a VPC endpoint in place, all traffic between your application and Bedrock stays within the AWS network. Combined with an IAM role-based auth and CloudWatch logging, this architecture satisfies the data handling requirements of most regulated enterprise workloads.

Bedrock Knowledge Bases: Managed RAG

Bedrock Knowledge Bases is Amazon’s managed RAG service. You point it at an S3 bucket of documents, it chunks and embeds them automatically using Amazon Titan embeddings, stores them in a managed vector store (OpenSearch Serverless or Aurora PostgreSQL), and provides a retrieve-and-generate API that handles the full RAG pipeline:

bedrock_agent = boto3.client("bedrock-agent-runtime", region_name="us-east-1")

response = bedrock_agent.retrieve_and_generate(
    input={"text": "What is our employee parental leave policy?"},
    retrieveAndGenerateConfiguration={
        "type": "KNOWLEDGE_BASE",
        "knowledgeBaseConfiguration": {
            "knowledgeBaseId": "your-kb-id",
            "modelArn": "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-sonnet-4-5",
            "retrievalConfiguration": {
                "vectorSearchConfiguration": {"numberOfResults": 5}
            }
        }
    }
)

print(response["output"]["text"])
for citation in response["citations"]:
    print(f"Source: {citation['retrievedReferences'][0]['location']['s3Location']['uri']}")

For teams that want RAG without building the embedding pipeline, chunking strategy, and vector store infrastructure themselves, Bedrock Knowledge Bases provides a fully managed path. The trade-off is less control over chunking, embedding model choice, and retrieval strategy — for advanced RAG applications, building your own pipeline with pgvector or a dedicated vector database gives more flexibility.

Bedrock Guardrails

Bedrock Guardrails provides managed content filtering, PII detection and redaction, and topic-based restrictions that apply across any model on the platform. Configure a guardrail in the console and reference it in API calls:

response = bedrock.invoke_model(
    modelId="anthropic.claude-sonnet-4-5",
    guardrailIdentifier="your-guardrail-id",
    guardrailVersion="DRAFT",
    body=json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 1024,
        "messages": [{"role":"user","content":user_input}]
    })
)

result = json.loads(response["body"].read())
if result.get("amazon-bedrock-guardrailAction") == "GUARDRAIL_INTERVENED":
    print("Content filtered by guardrail")

CloudWatch Logging and Cost Monitoring

Enable model invocation logging in the Bedrock console to send all requests and responses to CloudWatch Logs or S3. This provides a complete audit trail and enables cost attribution by application, user, or team. Set CloudWatch billing alerts for Bedrock usage in AWS Cost Explorer — Bedrock charges the same per-token rates as the direct provider APIs, so the same cost monitoring practices apply.

Bedrock vs. Direct Anthropic API

For teams already invested in AWS, Bedrock offers compelling operational advantages: unified IAM auth, CloudWatch monitoring, VPC endpoint access, and a single bill for all AI usage alongside other AWS services. The model capability and pricing are identical to the direct Anthropic API. Choose Bedrock if your team’s compliance and security requirements are already addressed by AWS’s certifications, if you want to avoid managing credentials for multiple AI providers, or if you want managed RAG and agent features without building your own infrastructure. Choose the direct Anthropic API if you need access to the latest Claude features immediately at release (Bedrock sometimes lags by weeks on new model versions), or if you are not primarily an AWS shop and the integration benefits do not justify the additional AWS dependency.

Calling Other Models on Bedrock

Bedrock’s multi-model access is one of its strongest practical advantages. Switching between Anthropic Claude, Meta Llama, Mistral, and Amazon Titan requires only a model ID change — the same SDK, same authentication, same VPC endpoint. This makes it straightforward to route different tasks to the most cost-effective model or to A/B test models against each other:

import boto3, json

bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")

def call_model(model_id: str, prompt: str, max_tokens: int = 1024) -> str:
    if model_id.startswith("anthropic"):
        body = {"anthropic_version":"bedrock-2023-05-31",
                "max_tokens":max_tokens,"messages":[{"role":"user","content":prompt}]}
    elif model_id.startswith("meta"):
        body = {"prompt":f"<s>[INST]{prompt}[/INST]","max_gen_len":max_tokens,"temperature":0}
    elif model_id.startswith("mistral"):
        body = {"prompt":f"<s>[INST]{prompt}[/INST]","max_tokens":max_tokens}
    else:
        body = {"inputText":prompt,"textGenerationConfig":{"maxTokenCount":max_tokens}}

    response = bedrock.invoke_model(modelId=model_id, body=json.dumps(body))
    result = json.loads(response["body"].read())

    if model_id.startswith("anthropic"):
        return result["content"][0]["text"]
    elif model_id.startswith("meta"):
        return result["generation"]
    elif model_id.startswith("mistral"):
        return result["outputs"][0]["text"]
    return result["results"][0]["outputText"]

# Same function, different models
claude_answer = call_model("anthropic.claude-haiku-4-5", "Classify this as positive or negative: Great product!")
llama_answer = call_model("meta.llama3-8b-instruct-v1:0", "Classify this as positive or negative: Great product!")

This multi-model abstraction is particularly useful for cost optimisation — route simple classification tasks to Llama 8B or Titan at a lower price point while reserving Claude Sonnet for complex analysis tasks that need higher capability.

Bedrock Agents: No-Code Agentic Workflows

Bedrock Agents is Amazon’s managed agent service that lets you build tool-calling agents without writing the orchestration loop yourself. You define action groups (functions the agent can call), knowledge bases (document corpora for RAG), and a system prompt — Bedrock handles the LLM calls, tool execution management, and conversation memory. For teams that want agent functionality without the operational complexity of building and maintaining an agentic framework, Bedrock Agents provides a managed alternative. The trade-off is less control over the agent’s decision-making process and tool execution logic than a custom LangChain or LangGraph implementation provides.

Pricing on Bedrock

Bedrock pricing matches the direct provider API rates for on-demand usage. Claude Sonnet on Bedrock costs the same per token as calling the Anthropic API directly. The advantage is consolidated billing — all AI costs appear on a single AWS invoice alongside your other infrastructure, making budget management and cost attribution simpler for organisations already using AWS Cost Explorer and budget alerts. Bedrock also offers Provisioned Throughput — reserved capacity at a fixed hourly rate — for workloads requiring guaranteed throughput above on-demand limits. This is analogous to Anthropic’s enterprise tier and makes sense for applications with consistent high-volume traffic where unpredictable rate limits are unacceptable.

When to Choose Bedrock vs. Direct Provider APIs

Bedrock is the right choice when your team is primarily AWS-based and wants unified auth, billing, and compliance; when you need VPC endpoint access to keep prompts off the public internet within an existing AWS VPC; when you want to use multiple model providers through a single integration without managing separate API keys and SDKs; or when Bedrock’s managed features (Knowledge Bases, Agents, Guardrails) reduce engineering work that you would otherwise build yourself. The direct Anthropic API is better when you need immediate access to the newest Claude features at release (Bedrock sometimes lags by days or weeks), when you want the simplest possible integration with minimal AWS dependency, or when your compliance requirements are already satisfied by Anthropic’s data handling agreements. For most AWS-native teams building serious production LLM applications, Bedrock’s integration benefits justify choosing it over direct provider APIs — the model capabilities are identical and the operational advantages compound as usage scales.

Bedrock Batch Inference

Like the direct Anthropic API, Bedrock supports batch inference for asynchronous workloads at reduced cost. Submit a JSONL file of requests to S3, create a batch inference job, and retrieve results from S3 when processing completes. Batch inference on Bedrock is priced at 50% of on-demand rates — the same discount as the direct Anthropic batch API — making it the right choice for any offline processing pipeline: nightly document analysis, bulk classification, embedding generation for large corpora. The AWS-native workflow integrates naturally with S3 for input/output storage and CloudWatch Events for completion notifications, fitting cleanly into existing AWS data pipelines without custom polling logic.

Using Bedrock with LangChain

LangChain supports Bedrock models through the langchain-aws integration package, making it easy to use Bedrock-hosted models in LangChain chains, agents, and RAG pipelines:

pip install langchain-aws
from langchain_aws import ChatBedrock, BedrockEmbeddings

llm = ChatBedrock(
    model_id="anthropic.claude-sonnet-4-5",
    region_name="us-east-1",
    model_kwargs={"max_tokens": 1024, "temperature": 0}
)

embeddings = BedrockEmbeddings(
    model_id="amazon.titan-embed-text-v2:0",
    region_name="us-east-1"
)

response = llm.invoke("Explain AWS Bedrock in two paragraphs.")
print(response.content)

With LangChain’s Bedrock integration, all standard LangChain components — vector stores, retrieval chains, agents, evaluation tools — work against Bedrock-hosted models using IAM authentication automatically. This is the fastest path to a production LangChain application on AWS infrastructure without managing separate API credentials for each model provider.

Leave a Comment