Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 43 additions & 0 deletions BEDROCK_MANAGED_KB.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Bedrock Managed Knowledge Base Support

## Changes
- Added managed KB sample application demonstrating end-to-end workflow
- New sample: create managed KB, add data source, sync, and retrieve
- Retrieval sample uses `managedSearchConfiguration` as default
- Added `AgenticRetrieveStream` sample for agentic retrieval pattern
- Existing VECTOR samples preserved with clear labeling

## Design
- VECTOR is the default; MANAGED samples added as alternatives
- Samples demonstrate both Python (boto3) and JavaScript (AWS SDK) paths
- AgenticRetrieveStream sample shows streaming agentic retrieval
- Backward compatible: existing VECTOR samples unchanged, new managed samples added alongside

## API Shapes
- KB Creation: `type: MANAGED` + `managedKnowledgeBaseConfiguration.embeddingModelType: MANAGED`
- Data Source: `type: MANAGED_KNOWLEDGE_BASE_CONNECTOR`
- Retrieval: `managedSearchConfiguration` (not `vectorSearchConfiguration`)
- Agentic: `AgenticRetrieveStream` with `foundationModelType: MANAGED`, `rerankingModelType: MANAGED`

## Configuration
| Variable | Description | Default |
|---|---|---|
| KNOWLEDGE_BASE_TYPE | MANAGED or VECTOR | VECTOR |
| USE_AGENTIC_RETRIEVAL | Enable agentic retrieval | true |
| KNOWLEDGE_BASE_ID | KB ID | (required) |

## SDK Requirements
- boto3 >= 1.43 for managed search and agentic retrieval
- JS SDK >= 3.750.0 for managed KB support

## Required IAM Permissions
```json
{
"Effect": "Allow",
"Action": [
"bedrock:Retrieve",
"bedrock:AgenticRetrieveStream"
],
"Resource": "arn:aws:bedrock:<region>:<account-id>:knowledge-base/<kb-id>"
}
```
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,48 @@ Follow the instructions [here](https://strandsagents.com/latest/user-guide/quick
- **[01-learn](./typescript/01-learn/)** - SDK tutorials for the TypeScript SDK
- **[02-deploy](./typescript/02-deploy/)** - Deployment patterns for AgentCore

## Amazon Bedrock Knowledge Bases

Several samples demonstrate RAG using Amazon Bedrock Knowledge Bases. These samples support both **Managed Knowledge Bases** (recommended) and traditional vector search KBs.

### Managed Knowledge Bases (Recommended)

Managed knowledge bases let Bedrock handle embedding, storage, and retrieval automatically — no external vector store required:

```python
import os
os.environ["KNOWLEDGE_BASE_ID"] = "ABCDEFGHIJ"
os.environ["KNOWLEDGE_BASE_TYPE"] = "MANAGED"

from strands import Agent
from strands_tools import retrieve

agent = Agent(tools=[retrieve])
response = agent("What does our documentation say about deployment?")
```

Managed KBs support **agentic retrieval** with intelligent query decomposition and managed reranking. Set `USE_AGENTIC_RETRIEVAL=false` to disable and use simple managed search instead.

> **SDK requirements:** `boto3 >= 1.43` for managed search and agentic retrieval.

**Reranking options** for managed search: `MANAGED` (default — automatic), `NONE` (disable reranking), `CUSTOM` (your own Bedrock reranking model e.g. Cohere Rerank v3.5).

**Required IAM Permissions:**
```json
{
"Effect": "Allow",
"Action": [
"bedrock:Retrieve",
"bedrock:AgenticRetrieveStream"
],
"Resource": "arn:aws:bedrock:<region>:<account-id>:knowledge-base/<kb-id>"
}
```

**Resources:** [Build a Managed KB](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-build-managed.html) | [Retrieve API](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-retrieve.html) | [Agentic Retrieval](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-agentic.html)

See [05-technical-use-cases](./python/05-technical-use-cases/) for Agentic RAG patterns.

## Contributing ❤️

We welcome contributions! See our [Contributing Guide](CONTRIBUTING.md) for details on:
Expand Down
211 changes: 206 additions & 5 deletions python/01-learn/07-aws-services/prereqs/knowledge_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,195 @@ def __init__(self, suffix=None):
self.oss_client = None
self.data_bucket_name = None

def create_or_retrieve_managed_knowledge_base(
self,
kb_name: str,
kb_description: str = None,
data_bucket_name: str = None,
):
"""
Create or retrieve a MANAGED Knowledge Base (Bedrock handles storage and embeddings).

Managed KBs do not require OpenSearch Serverless, embedding model selection, or
vector index configuration. Bedrock manages all of this automatically.

Args:
kb_name: Knowledge Base Name
kb_description: Knowledge Base Description
data_bucket_name: Name of S3 Bucket containing Knowledge Base Data

Returns:
kb_id: str - Knowledge base id
ds_id: str - Data Source id
"""
kb_id = None
ds_id = None
kbs_available = self.bedrock_agent_client.list_knowledge_bases(
maxResults=100,
)
for kb in kbs_available["knowledgeBaseSummaries"]:
if kb_name == kb["name"]:
kb_id = kb["knowledgeBaseId"]
if kb_id is not None:
ds_available = self.bedrock_agent_client.list_data_sources(
knowledgeBaseId=kb_id,
maxResults=100,
)
for ds in ds_available["dataSourceSummaries"]:
if kb_id == ds["knowledgeBaseId"]:
ds_id = ds["dataSourceId"]
if not data_bucket_name:
self.data_bucket_name = self._get_knowledge_base_s3_bucket(
kb_id, ds_id
)
print(f"Managed Knowledge Base {kb_name} already exists.")
print(f"Retrieved Knowledge Base Id: {kb_id}")
print(f"Retrieved Data Source Id: {ds_id}")
else:
print(f"Creating Managed KB {kb_name}")
if data_bucket_name is None:
kb_name_temp = kb_name.replace("_", "-")
data_bucket_name = f"{kb_name_temp}-{self.suffix}"
print(
f"KB bucket name not provided, creating a new one called: {data_bucket_name}"
)

# Step 1: Create S3 bucket
print("Step 1 - Creating or retrieving S3 bucket")
self.create_s3_bucket(data_bucket_name)

# Step 2: Create execution role (only needs S3 access for managed KBs)
kb_execution_role_name = (
f"AmazonBedrockExecutionRoleForManagedKB_{self.suffix}"
)
s3_policy_name = f"AmazonBedrockS3PolicyForManagedKB_{self.suffix}"

assume_role_policy_document = {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"Service": "bedrock.amazonaws.com"},
"Action": "sts:AssumeRole",
}
],
}

s3_policy_document = {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
f"arn:aws:s3:::{data_bucket_name}",
f"arn:aws:s3:::{data_bucket_name}/*",
],
"Condition": {
"StringEquals": {
"aws:ResourceAccount": f"{self.account_number}"
}
},
}
],
}

try:
s3_policy = self.iam_client.create_policy(
PolicyName=s3_policy_name,
PolicyDocument=json.dumps(s3_policy_document),
Description="Policy for reading documents from S3 for managed KB",
)
except self.iam_client.exceptions.EntityAlreadyExistsException:
print(f"{s3_policy_name} already exists, retrieving it!")
s3_policy = self.iam_client.get_policy(
PolicyArn=f"arn:aws:iam::{self.account_number}:policy/{s3_policy_name}"
)

try:
bedrock_kb_execution_role = self.iam_client.create_role(
RoleName=kb_execution_role_name,
AssumeRolePolicyDocument=json.dumps(assume_role_policy_document),
Description="Amazon Bedrock Managed Knowledge Base Execution Role",
MaxSessionDuration=3600,
)
except self.iam_client.exceptions.EntityAlreadyExistsException:
print(f"{kb_execution_role_name} already exists, retrieving it!")
bedrock_kb_execution_role = self.iam_client.get_role(
RoleName=kb_execution_role_name
)

self.iam_client.attach_role_policy(
RoleName=bedrock_kb_execution_role["Role"]["RoleName"],
PolicyArn=s3_policy["Policy"]["Arn"],
)

# Wait for role propagation
print("Waiting for IAM role propagation...")
interactive_sleep(10)

# Step 3: Create the managed Knowledge Base
print(f"Step 3 - Creating Managed Knowledge Base: {kb_name}")
try:
create_kb_response = self.bedrock_agent_client.create_knowledge_base(
name=kb_name,
description=kb_description or kb_name,
roleArn=bedrock_kb_execution_role["Role"]["Arn"],
knowledgeBaseConfiguration={
"type": "MANAGED",
"managedKnowledgeBaseConfiguration": {
"embeddingModelType": "MANAGED",
},
},
# No storageConfiguration needed for managed KBs
)
kb = create_kb_response["knowledgeBase"]
pp.pprint(kb)
except self.bedrock_agent_client.exceptions.ConflictException:
kbs = self.bedrock_agent_client.list_knowledge_bases(maxResults=100)
kb_id_found = None
for existing_kb in kbs["knowledgeBaseSummaries"]:
if existing_kb["name"] == kb_name:
kb_id_found = existing_kb["knowledgeBaseId"]
response = self.bedrock_agent_client.get_knowledge_base(
knowledgeBaseId=kb_id_found
)
kb = response["knowledgeBase"]
pp.pprint(kb)

# Step 4: Create Data Source
print(f"Step 4 - Creating S3 Data Source")
s3_configuration = {
"bucketArn": f"arn:aws:s3:::{data_bucket_name}",
}
try:
create_ds_response = self.bedrock_agent_client.create_data_source(
name=kb_name,
description=kb_description or kb_name,
knowledgeBaseId=kb["knowledgeBaseId"],
dataDeletionPolicy="RETAIN",
dataSourceConfiguration={
"type": "S3",
"s3Configuration": s3_configuration,
},
)
ds = create_ds_response["dataSource"]
pp.pprint(ds)
except self.bedrock_agent_client.exceptions.ConflictException:
ds_id_found = self.bedrock_agent_client.list_data_sources(
knowledgeBaseId=kb["knowledgeBaseId"], maxResults=100
)["dataSourceSummaries"][0]["dataSourceId"]
get_ds_response = self.bedrock_agent_client.get_data_source(
dataSourceId=ds_id_found, knowledgeBaseId=kb["knowledgeBaseId"]
)
ds = get_ds_response["dataSource"]
pp.pprint(ds)

interactive_sleep(30)
kb_id = kb["knowledgeBaseId"]
ds_id = ds["dataSourceId"]
return kb_id, ds_id

def create_or_retrieve_knowledge_base(
self,
kb_name: str,
Expand All @@ -113,7 +302,8 @@ def create_or_retrieve_knowledge_base(
embedding_model: str = "amazon.titan-embed-text-v2:0",
):
"""
Function used to create a new Knowledge Base or retrieve an existent one
Function used to create a new Knowledge Base or retrieve an existent one.
Creates a VECTOR type KB with OpenSearch Serverless storage.

Args:
kb_name: Knowledge Base Name
Expand Down Expand Up @@ -1047,16 +1237,27 @@ def delete_s3(self, bucket_name: str):
parser.add_argument(
"--mode",
required=True,
help="Knowledge Base helper model. One for: create or delete.",
help="Knowledge Base helper mode. One of: create or delete.",
)
parser.add_argument(
"--kb-type",
choices=["VECTOR", "MANAGED"],
default="MANAGED",
help="Knowledge Base type: VECTOR (default, uses OpenSearch) or MANAGED (fully managed by Bedrock).",
)

args = parser.parse_args()

print(data)
if args.mode == "create":
kb_id, ds_id = kb.create_or_retrieve_knowledge_base(
data["knowledge_base_name"], data["knowledge_base_description"]
)
if args.kb_type == "MANAGED":
kb_id, ds_id = kb.create_or_retrieve_managed_knowledge_base(
data["knowledge_base_name"], data["knowledge_base_description"]
)
else:
kb_id, ds_id = kb.create_or_retrieve_knowledge_base(
data["knowledge_base_name"], data["knowledge_base_description"]
)
print(f"Knowledge Base ID: {kb_id}")
print(f"Data Source ID: {ds_id}")
kb.upload_directory(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,13 @@ def client_meeting_analysis(query: str) -> str:

logger.info(f"📋 Using KB ID: {kb_id} (source: {kb_source})")

# Determine KB type from config (VECTOR or MANAGED)
kb_type = load_config().get("knowledge_base_type", "MANAGED").upper()

os.environ.update({
"BYPASS_TOOL_CONSENT": "true",
"KNOWLEDGE_BASE_ID": kb_id
"BYPASS_TOOL_CONSENT": "true",
"KNOWLEDGE_BASE_ID": kb_id,
"KNOWLEDGE_BASE_TYPE": kb_type,
})

model = get_model()
Expand Down
Loading
Loading