Skip to content

feat(models): add support for Amazon Bedrock native API #1115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

leandrodamascena
Copy link
Contributor

@leandrodamascena leandrodamascena commented Mar 31, 2025

Closes #1092

Summary

This pull request introduces the new AmazonBedrockServerModel class that provides direct access to Amazon Bedrock's foundation models via the Bedrock API. The implementation leverages the Bedrock converse API endpoint, allowing users to interact with all available Bedrock models through a consistent interface while maintaining the flexibility to configure model-specific parameters.

Implementation Details

  • Created AmazonBedrockServerModel class that extends ApiModel
  • Implemented support for the Bedrock Runtime converse API
  • Added flexible boto3 client configuration:
    • Users can provide their own pre-configured boto3 client
    • Default client creation with standard configurations when not provided
  • Added comprehensive parameter handling:
    • Model-specific inference configurations (temperature, max_tokens, etc.)
    • Guardrails configuration for content safety
    • Custom role conversion mapping for model compatibility
    • Support for flattened message formatting
  • Implemented proper error handling and response parsing
  • Added conversion logic for different message role formats across Bedrock models

Documentation Changes

  • Updated documentation with examples of how to use AmazonBedrockServerModel
  • Added parameter descriptions and usage patterns
  • Included model-specific configuration examples for popular Bedrock models

Testing

  • Added unit tests for the new class

Additional Notes

I've added detailed comments throughout the code to explain the implementation choices and help future contributors understand the design patterns. The implementation follows the project's established patterns while accommodating the requirements of the Bedrock API.

User experience

Basic Usage

# !pip install smolagents[aws_sdk]
from smolagents import CodeAgent, AmazonBedrockServerModel

model = AmazonBedrockServerModel(model_id="anthropic.claude-3-sonnet-20240229-v1:0")
agent = CodeAgent(tools=[], model=model, add_base_tools=True)

agent.run(
    "Could you give me the 118th number in the Fibonacci sequence?",
)

Advanced Configuration

import boto3
from smolagents import AmazonBedrockServerModel

# Create a custom Bedrock client
bedrock_client = boto3.client(
    'bedrock-runtime',
    region_name='us-east-1',
    aws_access_key_id='YOUR_ACCESS_KEY',
    aws_secret_access_key='YOUR_SECRET_KEY'
)

# Initialize with comprehensive configuration
model = AmazonBedrockServerModel(
    model_id="us.amazon.nova-pro-v1:0",
    boto3_client=bedrock_client,  # Use custom client
    inference_config={
        "temperature": 0.5,
        "top_p": 0.9,
        "max_tokens": 1000
    },
    guardrail_config={
        "guardrail_id": "my-custom-guardrail",
        "guardrail_version": "DRAFT"
    },
    bedrock_api_kwargs={
        "performanceConfig": {
            "latency": "standard"
        }
    }
)

agent = CodeAgent(tools=[], model=model, add_base_tools=True)

agent.run(
    "Could you give me the 118th number in the Fibonacci sequence?",
)

Let me know if you'd like any additional changes or have questions about the implementation.

Copy link
Member

@albertvillanova albertvillanova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome contribution! Really happy to see this new model supported!

I think you already tested it locally and the model calls work as expected: do you know if some additional test could be implemented?

Please find some comments/suggestions below to align your implementation better with the rest of the models.

@HuggingFaceDocBuilderDev

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@leandrodamascena
Copy link
Contributor Author

Hi @albertvillanova, thanks for the super quick review, I really appreciate it! I'm off work today until 4PM WEST, but I hope to respond to all comments today.

@albertvillanova
Copy link
Member

No hurry at all, @leandrodamascena! Let me know if you need any help from my side.

Copy link
Contributor Author

@leandrodamascena leandrodamascena left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @albertvillanova! Thanks for all the feedback, I addressed all of them and it's probably read to another review.

I attached a quick video showing this working and I can create others with specific settings if you want to see this working.

Screen.Recording.2025-04-02.at.16.12.39.mov

@leandrodamascena
Copy link
Contributor Author

leandrodamascena commented Apr 3, 2025

My bad here! I didn't saw that projects support python 3.10+ and I'm using typing.override from Python 3.12+. I'll remove it since you don't install typing-extensions for backward compatibility.

Copy link
Member

@albertvillanova albertvillanova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot! Just some minor comments/suggestions below and we are ready to merge!

# The Bedrock API does not support the `type` key in requests.
# This block of code modifies the object to meet Bedrock's requirements.
for message in messages.get("messages", []):
for content in message.get("content", []):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should add an if condition here to apply this modification only if message["content"] is an instance of list. Note that it could also be an instance of str.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you help me here? In what situations can it be an instance of str? I tried many scenarios here and couldn't get an instance of str.
In Bedrock, it should always be an instance of list. And since I am just passing the array to bedrock, I expect it to always be a list. If it can be a str, then I need to do some logic to transform it.

client.converse(
    modelId='string',
    messages=[
        {
            'role': 'user'|'assistant',
            'content': [ ... ]
		}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We implemented the flatten_messages_as_text parameter to handle this behavior: depending on the provider, some models do require a str content, others require a list content and others support both formats.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm so in Bedrock I need to set the default to False always?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if no model can be passed a str content...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! This is not so much about the model, but more about the bedrock-runtime API, and the API is the same for all models available in Bedrock. So I removed this field from the AmazonBedrockServerModel class and I am passing False to ApiModel.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have already sent a commit.

@leandrodamascena
Copy link
Contributor Author

Hi @albertvillanova! Thanks for your super detailed review! I've addressed most of the comments and I think the one about messages is missing. I've also added a new docstring for the ApiModel class to make it documented, but I don't know if it makes sense, I might revert it.

Copy link
Member

@albertvillanova albertvillanova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! Thanks a lot for your effort and for submitting such a high-quality PR. I appreciate your contribution and really enjoyed reviewing it.

Just a few nits below and we are good to merge!

@leandrodamascena
Copy link
Contributor Author

Great work! Thanks a lot for your effort and for submitting such a high-quality PR. I appreciate your contribution and really enjoyed reviewing it.

Just a few nits below and we are good to merge!

Thank you so much for your patience and review @albertvillanova! Not knowing the codebase and all the features is a challenge, but you led me to the success. I just made one suggested change and commented on the other.

@albertvillanova albertvillanova merged commit 3af67af into huggingface:main Apr 4, 2025
4 checks passed
@albertvillanova
Copy link
Member

Thanks again for your awesome contribution! 🤗

@leandrodamascena
Copy link
Contributor Author

Thanks again for your awesome contribution! 🤗

Thanks for all the support and please fell free to reach me out if I can help with any bug/feature for this new integration.

@aymeric-roucher
Copy link
Collaborator

@leandrodamascena I'm reworking the cleaning of messages in https://github.com/huggingface/smolagents/pull/1002/files, and I wonder about one of your comments about bedrock chat template: we've got two possible templates

  1. [{"role": "user", "content": [{"type": "text", "text": "Hello"}]}]
  2. [{"role": "user", "content": "Hello"}]

The idea of the PR https://github.com/huggingface/smolagents/pull/1002/files is to flatten by default messages to format 2.
Would that work? If not, do you know if it's model specific or general?

@leandrodamascena
Copy link
Contributor Author

Hey @aymeric-roucher let me see what you're doing and will reply this comment today.

@leandrodamascena
Copy link
Contributor Author

@leandrodamascena I'm reworking the cleaning of messages in #1002 (files), and I wonder about one of your comments about bedrock chat template: we've got two possible templates

  1. [{"role": "user", "content": [{"type": "text", "text": "Hello"}]}]
  2. [{"role": "user", "content": "Hello"}]

The idea of the PR #1002 (files) is to flatten by default messages to format 2. Would that work? If not, do you know if it's model specific or general?

Hey @aymeric-roucher, neither of those payloads work with Bedrock because, when working with text, the Bedrock API only supports payloads in the following format:

messages = [
    {
        'role': 'user',
        'content': [
            {
                'text': "..."
            }
        ]
    }
]

You can see that the content does not include a type key. Instead, the API uses the key itself (e.g., text, document, or video) as the identifier. Currently, Bedrock supports "text" and, in some cases, "document" and "video" (though not all models support these types). Additionally, there is no way to pass flattened messages directly to the content key, due to the payload format.

The bedrock-runtime API is an abstraction that works with multiple models under the hood, but the exposed API is the same for all of them. You can check the supported features per model on this page.

Can I help with something in the PR #1002 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Native Bedrock server model (willing to contribute)
5 participants