Getting Started with Amazon Bedrock and Python

An introductory guide to Amazon Bedrock, showing you how to use Python and Boto3 to interact with powerful foundation models like Anthropic's Claude for text generation tasks.

Amazon Bedrock has emerged as a powerful service that provides a simple, serverless API for accessing a wide range of foundation models (FMs) from leading AI companies like Anthropic, Cohere, AI21 Labs, and Amazon itself. Instead of integrating with multiple different APIs, you get a single, unified AWS experience.

This guide will walk you through making your first call to a foundation model using Amazon Bedrock with Python and Boto3.

Why Use Bedrock?

  • Simplicity: A single API for many different models. You can swap out models with minimal code changes.
  • Security and Privacy: Your data is not used to train the underlying models. All data is encrypted and processed within your AWS environment.
  • Serverless: No infrastructure to manage. You pay per token, and it scales automatically.

Setting Up

First, you need to request access to the models you want to use. In the Amazon Bedrock console, navigate to "Model access" and enable access for the models you're interested in (e.g., Anthropic's Claude 3 Sonnet).

Next, make sure your Boto3 library is up-to-date and your AWS credentials are configured with permissions for Bedrock (bedrock:InvokeModel).

pip install boto3 --upgrade

Interacting with a Model

Bedrock has a different runtime client than other AWS services. You'll use boto3.client('bedrock-runtime').

The core function is invoke_model. It takes the modelId and a body containing the prompt and inference parameters, which are specific to each model.

Let's write a Python function to interact with Anthropic's Claude 3 Sonnet.

import boto3
import json

# It's a good practice to create the client outside of your function handler
bedrock_runtime = boto3.client('bedrock-runtime')

def generate_text(prompt):
    """Generates text using the Claude 3 Sonnet model in Bedrock."""

    # The modelId for Claude 3 Sonnet
    model_id = 'anthropic.claude-3-sonnet-20240229-v1:0'

    # The request body format is specific to the model provider (Anthropic in this case)
    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 1000,
        "messages": [
            {
                "role": "user",
                "content": [{ "type": "text", "text": prompt}]
            }
        ]
    })

    try:
        response = bedrock_runtime.invoke_model(
            body=body,
            modelId=model_id,
            accept='application/json',
            contentType='application/json'
        )

        # The response body is also a stream, so we need to read and parse it
        response_body = json.loads(response.get('body').read())

        # The actual generated text is in the 'content' block
        generated_text = response_body['content'][0]['text']
        return generated_text

    except Exception as e:
        print(f"Error generating text: {e}")
        return None

# --- Example Usage ---
prompt = "Write a short, upbeat paragraph about the future of serverless computing."
response_text = generate_text(prompt)

if response_text:
    print(response_text)

Understanding the Request and Response

It's crucial to understand that the body you send to invoke_model and the structure of the response you get back are determined by the model provider, not by Bedrock itself.

  • For Anthropic's Claude models, you send a messages array with role and content objects. The response also contains a content block with the generated text.
  • For other models like Cohere or Llama, the request and response structure will be different. Always refer to the Amazon Bedrock User Guide for the correct format for your chosen model.

Streaming Responses

For more interactive applications (like a chatbot), you don't want to wait for the entire response to be generated. Bedrock supports streaming, where the model sends back tokens as soon as they are generated.

To do this, you use invoke_model_with_response_stream.

def generate_text_streaming(prompt):
    """Generates and streams text from the Claude 3 Sonnet model."""

    model_id = 'anthropic.claude-3-sonnet-20240229-v1:0'
    body = json.dumps({
        "anthropic_version": "bedrock-2023-05-31",
        "max_tokens": 1000,
        "messages": [
            {
                "role": "user",
                "content": [{ "type": "text", "text": prompt}]
            }
        ]
    })

    response = bedrock_runtime.invoke_model_with_response_stream(
        body=body, modelId=model_id
    )

    for event in response.get('body'):
        chunk = json.loads(event['chunk']['bytes'])
        if chunk['type'] == 'content_block_delta':
            yield chunk['delta']['text']

# --- Example Usage ---
# for chunk in generate_text_streaming(prompt):
#     print(chunk, end='')

Conclusion

Amazon Bedrock provides a powerful and straightforward way to integrate generative AI into your applications. By abstracting away the infrastructure and providing a unified API, it allows you to focus on building features while leveraging the best models on the market. This simple entry point is just the beginning of what's possible with Bedrock's more advanced features like Agents and Knowledge Bases.