Skip to content

Add support for AWS Bedrock LLM Provider #238

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

Open
wants to merge 59 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
f39c450
Fix broken links in examples documentation (#177)
dagardner-nv Apr 30, 2025
3b3f59b
Remove support for Python `3.13` (#178)
yczhang-nv Apr 30, 2025
b3ccd3f
Add transitional packages (#181)
dagardner-nv Apr 30, 2025
ca5ac3a
Add a tunable RAG evaluator (#110)
liamy-nv May 1, 2025
f2fc50b
CLI Documentation fixes in remote registry configuration section (#184)
mpenn May 1, 2025
8bcaada
Fix uploading of transitional packages (#187)
dagardner-nv May 1, 2025
c1561f6
Update `AIQChatRequest` to support image and audio input (#182)
yczhang-nv May 1, 2025
0202e10
Fix hyperlink ins the simple_calculator README (#188)
AnuradhaKaruppiah May 1, 2025
91eb97c
Add support for fine-grained tracing using W&B Weave (#170)
ayulockin May 1, 2025
cda127c
Fix typo in CPR detected by co-pilot (#190)
AnuradhaKaruppiah May 1, 2025
b47651e
Note the name change in the top-level documentation and README.md (#163)
dagardner-nv May 1, 2025
bf04088
fix typo in evaluate documentation for max_concurrency (#191)
soumilinandi May 1, 2025
650d43a
Fix a typo in the weave README (#195)
AnuradhaKaruppiah May 2, 2025
8cc8481
Update simple example `eval` dataset (#200)
yczhang-nv May 2, 2025
99c034d
Config option to specify the intermediate step types in workflow_outp…
AnuradhaKaruppiah May 2, 2025
d35a94b
Update the Judge LLM settings in the examples to avoid retries (#204)
AnuradhaKaruppiah May 2, 2025
813ffca
Make `opentelemetry` and `phoenix` as optional dependencies (#167)
yczhang-nv May 2, 2025
bada671
Support user-defined HTTP request metadata in workflow tools. (#130)
ericevans-nv May 2, 2025
840fa9c
Check if request is present before setting attributes (#209)
AnuradhaKaruppiah May 5, 2025
6e3eb77
Add the alert triage agent example (#193)
hsin-c May 5, 2025
2e442e0
Updating ui submodule (#211)
ericevans-nv May 5, 2025
52e30c0
Fix plugin dependencies (#208)
dagardner-nv May 5, 2025
b8a7e2d
[FEA]add profiler agent to the examples folder (#120)
zac-wang-nv May 5, 2025
f5ac178
Regenerate `uv.lock`, cleaned up `pyproject.toml` for profiler agent …
yczhang-nv May 6, 2025
251ae1d
Removed `disable=unused-argument` from pylint checks (#186)
Hritik003 May 6, 2025
edf21ae
Exception handling for discovery_metadata.py (#215)
VictorYudin May 6, 2025
dccaa17
Fix incorrect eval output config access (#219)
AnuradhaKaruppiah May 6, 2025
3e23ab6
Treat a tagged commit the same as a nightly build (#217)
dagardner-nv May 6, 2025
3fb2d4c
Feature/add aiqtoolkit UI submodule (#214)
ericevans-nv May 6, 2025
bf5a587
Add a CLI command to list all tools available via the MCP server (#221)
AnuradhaKaruppiah May 7, 2025
ef4d503
For remote evaluation, workflow config is not needed (#225)
AnuradhaKaruppiah May 7, 2025
46db735
Move configurable parameters from env vars to config file (#222)
hsin-c May 8, 2025
1e98a4c
Fix vulnerabilities in the alert triage agent example (#227)
hsin-c May 8, 2025
63e705b
Add e2e test for the alert triage agent (#226)
hsin-c May 8, 2025
f047bee
Fix remaining nSpect vulnerabilities for `1.1.0` (#229)
yczhang-nv May 8, 2025
58f16f0
Remove redundant span stack handling and error logging (#231)
dnandakumar-nv May 9, 2025
01b7cd2
Feature/add aiqtoolkit UI submodule (#234)
ericevans-nv May 9, 2025
7cace86
Move configurable parameters from env vars to config file (#222)
hsin-c May 8, 2025
baacee8
Fix vulnerabilities in the alert triage agent example (#227)
hsin-c May 8, 2025
c790a6c
Fix remaining nSpect vulnerabilities for `1.1.0` (#229)
yczhang-nv May 8, 2025
5144dca
update uv.lock
yczhang-nv Apr 25, 2025
9be5767
fix comments
yczhang-nv Apr 28, 2025
a3d05eb
update uv.lock
yczhang-nv May 5, 2025
2f66d0f
Initial commit for AWSBedrock LLM provider
yczhang-nv May 7, 2025
d57b8c9
add aws bedrock llm client for llama-index
yczhang-nv May 9, 2025
8c1b336
added unit tests for llm provider and llm framework combinations
yczhang-nv May 9, 2025
c842424
add headers
yczhang-nv May 9, 2025
d652426
roll back
yczhang-nv May 9, 2025
84938d2
re-generate uv.lock
yczhang-nv May 9, 2025
4ab57f5
merge upstream
yczhang-nv May 9, 2025
70f9c22
update uv.lock and pyproject.toml
yczhang-nv May 9, 2025
587113a
fix CI
yczhang-nv May 10, 2025
356ee0f
fix CI
yczhang-nv May 10, 2025
b0fc780
Merge remote-tracking branch 'upstream/develop' into yuchen-fix-aiq-1213
yczhang-nv May 14, 2025
8113a7b
Merge branch 'NVIDIA:develop' into yuchen-fix-aiq-1213
yczhang-nv May 20, 2025
d49db6c
remove comments
yczhang-nv May 21, 2025
984d7a1
update uv.lock
yczhang-nv May 21, 2025
52dd239
Merge remote-tracking branch 'upstream/develop' into yuchen-fix-aiq-1213
yczhang-nv May 22, 2025
4110244
add documentation of AWS account set up
yczhang-nv May 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions docs/source/extend/adding-an-llm-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,37 @@ Similar to the registration function for the provider, the client registration f
In the above example, the `ChatOpenAI` class is imported lazily, allowing for the client to be registered without importing the client class until it is needed. Thus, improving performance and startup times.
:::

## Test the Combination of LLM Provider and Client

After implementing a new LLM provider, it's important to verify that it works correctly with all existing LLM clients. This can be done by writing integration tests. Here's an example of how to test the integration between the NIM LLM provider and the LangChain framework:

```python
@pytest.mark.integration
@pytest.mark.asyncio
async def test_nim_langchain_agent():
"""
Test NIM LLM with LangChain agent. Requires NVIDIA_API_KEY to be set.
"""

prompt = ChatPromptTemplate.from_messages([("system", "You are a helpful AI assistant."), ("human", "{input}")])

llm_config = NIMModelConfig(model_name="meta/llama-3.1-70b-instruct", temperature=0.0)

async with WorkflowBuilder() as builder:
await builder.add_llm("nim_llm", llm_config)
llm = await builder.get_llm("nim_llm", wrapper_type=LLMFrameworkEnum.LANGCHAIN)

agent = prompt | llm

response = await agent.ainvoke({"input": "What is 1+2?"})
assert isinstance(response, AIMessage)
assert response.content is not None
assert isinstance(response.content, str)
assert "3" in response.content.lower()
```

Note: Since this test requires an API key, it's marked with `@pytest.mark.integration` to exclude it from CI runs. However, these tests are valuable for maintaining and verifying the functionality of LLM providers and their client integrations.

## Packaging the Provider and Client

The provider and client will need to be bundled into a Python package, which in turn will be registered with AIQ toolkit as a [plugin](../extend/plugins.md). In the `pyproject.toml` file of the package the `project.entry-points.'aiq.components'` section, defines a Python module as the entry point of the plugin. Details on how this is defined are found in the [Entry Point](../extend/plugins.md#entry-point) section of the plugins document. By convention, the entry point module is named `register.py`, but this is not a requirement.
Expand Down
49 changes: 49 additions & 0 deletions docs/source/extend/integrating-aws-bedrock-models.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!--
SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

# Integrating AWS Bedrock Models to AIQ Toolkit Workflow

To integrate AWS Bedrock models into your AIQ Toolkit workflow, follow these steps:

1. **Prerequisites**:
- Set up AWS credentials by configuring `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`. For detailed setup instructions, refer to the [AWS Bedrock setup guide](https://docs.aws.amazon.com/bedrock/latest/userguide/setting-up.html)

1. **Configuration**:
Add the AWS Bedrock LLM configuration to your workflow config file. Make sure the `region_name` matches the region of your `AWS` account, and the `credentials_profile_name` matches the field in your credential file. Here's an example:

```yaml
llms:
aws_bedrock_llm:
_type: aws_bedrock
model_name: meta.llama3-3-70b-instruct-v1:0
temperature: 0.0
max_tokens: 1024
region_name: us-east-2
credentials_profile_name: default
```

3. **Usage in Workflow**:
Reference the AWS Bedrock LLM in your workflow configuration:

```yaml
workflow:
_type: react_agent
llm_name: aws_bedrock_llm
# ... other workflow configurations
```

The AWS Bedrock integration supports various models and configurations, allowing you to leverage AWS's managed LLM services within your AIQ Toolkit workflows.
1 change: 1 addition & 0 deletions packages/aiqtoolkit_langchain/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies = [
# version when adding a new package. If unsure, default to using `~=` instead of `==`. Does not apply to aiq packages.
# Keep sorted!!!
"aiqtoolkit~=1.2",
"langchain-aws~=0.2.1",
"langchain-core~=0.3.7",
"langchain-nvidia-ai-endpoints~=0.3.5",
"langchain-milvus~=0.1.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from aiq.builder.builder import Builder
from aiq.builder.framework_enum import LLMFrameworkEnum
from aiq.cli.register_workflow import register_llm_client
from aiq.llm.aws_bedrock_llm import AWSBedrockModelConfig
from aiq.llm.nim_llm import NIMModelConfig
from aiq.llm.openai_llm import OpenAIModelConfig

Expand All @@ -34,3 +35,11 @@ async def openai_langchain(llm_config: OpenAIModelConfig, builder: Builder):
from langchain_openai import ChatOpenAI

yield ChatOpenAI(**llm_config.model_dump(exclude={"type"}, by_alias=True))


@register_llm_client(config_type=AWSBedrockModelConfig, wrapper_type=LLMFrameworkEnum.LANGCHAIN)
async def aws_bedrock_langchain(llm_config: AWSBedrockModelConfig, builder: Builder):

from langchain_aws import ChatBedrockConverse

yield ChatBedrockConverse(**llm_config.model_dump(exclude={"type", "context_size"}, by_alias=True))
1 change: 1 addition & 0 deletions packages/aiqtoolkit_llama_index/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ dependencies = [
# error
"llama-index-core==0.12.21",
"llama-index-embeddings-nvidia==0.3.1",
"llama-index-llms-bedrock==0.3.8",
"llama-index-llms-nvidia==0.3.1",
"llama-index-readers-file==0.4.4",
"llama-index==0.12.21",
Expand Down
14 changes: 12 additions & 2 deletions packages/aiqtoolkit_llama_index/src/aiq/plugins/llama_index/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from aiq.builder.builder import Builder
from aiq.builder.framework_enum import LLMFrameworkEnum
from aiq.cli.register_workflow import register_llm_client
from aiq.llm.aws_bedrock_llm import AWSBedrockModelConfig
from aiq.llm.nim_llm import NIMModelConfig
from aiq.llm.openai_llm import OpenAIModelConfig

Expand Down Expand Up @@ -47,7 +48,16 @@ async def openai_llama_index(llm_config: OpenAIModelConfig, builder: Builder):

llm = OpenAI(**kwargs)

# Disable content blocks
llm.supports_content_blocks = False
yield llm


@register_llm_client(config_type=AWSBedrockModelConfig, wrapper_type=LLMFrameworkEnum.LLAMA_INDEX)
async def aws_bedrock_llama_index(llm_config: AWSBedrockModelConfig, builder: Builder):

from llama_index.llms.bedrock import Bedrock

kwargs = llm_config.model_dump(exclude={"type", "max_tokens"}, by_alias=True)

llm = Bedrock(**kwargs)

yield llm
54 changes: 54 additions & 0 deletions src/aiq/llm/aws_bedrock_llm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from pydantic import AliasChoices
from pydantic import ConfigDict
from pydantic import Field

from aiq.builder.builder import Builder
from aiq.builder.llm import LLMProviderInfo
from aiq.cli.register_workflow import register_llm_provider
from aiq.data_models.llm import LLMBaseConfig


class AWSBedrockModelConfig(LLMBaseConfig, name="aws_bedrock"):
"""An AWS Bedrock llm provider to be used with an LLM client."""

model_config = ConfigDict(protected_namespaces=())

# Completion parameters
model_name: str = Field(validation_alias=AliasChoices("model_name", "model"),
serialization_alias="model",
description="The model name for the hosted AWS Bedrock.")
temperature: float = Field(default=0.0, description="Sampling temperature in [0, 1].")
max_tokens: int | None = Field(default=1024,
description="Maximum number of tokens to generate."
"This field is ONLY required when using AWS Bedrock with Langchain.")
context_size: int | None = Field(default=1024,
description="Maximum number of tokens to generate."
"This field is ONLY required when using AWS Bedrock with LlamaIndex.")

# Client parameters
region_name: str | None = Field(default="None", description="AWS region to use.")
base_url: str | None = Field(
default=None, description="Bedrock endpoint to use. Needed if you don't want to default to us-east-1 endpoint.")
credentials_profile_name: str | None = Field(
default=None, description="The name of the profile in the ~/.aws/credentials or ~/.aws/config files.")


@register_llm_provider(config_type=AWSBedrockModelConfig)
async def aws_bedrock_model(llm_config: AWSBedrockModelConfig, builder: Builder):

yield LLMProviderInfo(config=llm_config, description="A AWS Bedrock model for use with an LLM client.")
1 change: 1 addition & 0 deletions src/aiq/llm/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
# Import any providers which need to be automatically registered here
from . import nim_llm
from . import openai_llm
from . import aws_bedrock_llm
98 changes: 98 additions & 0 deletions tests/aiq/llm_providers/test_langchain_agents.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import pytest
from langchain_core.messages import AIMessage
from langchain_core.prompts import ChatPromptTemplate

from aiq.builder.framework_enum import LLMFrameworkEnum
from aiq.builder.workflow_builder import WorkflowBuilder
from aiq.llm.aws_bedrock_llm import AWSBedrockModelConfig
from aiq.llm.nim_llm import NIMModelConfig
from aiq.llm.openai_llm import OpenAIModelConfig


@pytest.mark.integration
@pytest.mark.asyncio
async def test_nim_langchain_agent():
"""
Test NIM LLM with LangChain agent. Requires NVIDIA_API_KEY to be set.
"""

prompt = ChatPromptTemplate.from_messages([("system", "You are a helpful AI assistant."), ("human", "{input}")])

llm_config = NIMModelConfig(model_name="meta/llama-3.1-70b-instruct", temperature=0.0)

async with WorkflowBuilder() as builder:
await builder.add_llm("nim_llm", llm_config)
llm = await builder.get_llm("nim_llm", wrapper_type=LLMFrameworkEnum.LANGCHAIN)

agent = prompt | llm

response = await agent.ainvoke({"input": "What is 1+2?"})
assert isinstance(response, AIMessage)
assert response.content is not None
assert isinstance(response.content, str)
assert "3" in response.content.lower()


@pytest.mark.integration
@pytest.mark.asyncio
async def test_openai_langchain_agent():
"""
Test OpenAI LLM with LangChain agent. Requires OPENAI_API_KEY to be set.
"""
prompt = ChatPromptTemplate.from_messages([("system", "You are a helpful AI assistant."), ("human", "{input}")])

llm_config = OpenAIModelConfig(model_name="gpt-3.5-turbo", temperature=0.0)

async with WorkflowBuilder() as builder:
await builder.add_llm("openai_llm", llm_config)
llm = await builder.get_llm("openai_llm", wrapper_type=LLMFrameworkEnum.LANGCHAIN)

agent = prompt | llm

response = await agent.ainvoke({"input": "What is 1+2?"})
assert isinstance(response, AIMessage)
assert response.content is not None
assert isinstance(response.content, str)
assert "3" in response.content.lower()


@pytest.mark.integration
@pytest.mark.asyncio
async def test_aws_bedrock_langchain_agent():
"""
Test AWS Bedrock LLM with LangChain agent.
Requires AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to be set.
See https://docs.aws.amazon.com/bedrock/latest/userguide/setting-up.html for more information.
"""
prompt = ChatPromptTemplate.from_messages([("system", "You are a helpful AI assistant."), ("human", "{input}")])

llm_config = AWSBedrockModelConfig(model_name="meta.llama3-3-70b-instruct-v1:0",
temperature=0.0,
region_name="us-east-2",
max_tokens=1024)

async with WorkflowBuilder() as builder:
await builder.add_llm("aws_bedrock_llm", llm_config)
llm = await builder.get_llm("aws_bedrock_llm", wrapper_type=LLMFrameworkEnum.LANGCHAIN)

agent = prompt | llm

response = await agent.ainvoke({"input": "What is 1+2?"})
assert isinstance(response, AIMessage)
assert response.content is not None
assert isinstance(response.content, str)
assert "3" in response.content.lower()
Loading
Loading