Skip to content

Commit c91ce99

Browse files
authored
Merge pull request #3008 from bfreiberg/sfn-parallel-bedrock-agentcore-multi-agent
feat: Add multi-agent orchestration pattern with Step Functions and Bedrock AgentCore
2 parents 8dc50d1 + ae2a47a commit c91ce99

13 files changed

Lines changed: 551 additions & 0 deletions

File tree

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Multi-agent orchestration with AWS Step Functions and Amazon Bedrock AgentCore
2+
3+
This pattern deploys an AWS Step Functions workflow that orchestrates multiple specialized AI agents running on Amazon Bedrock AgentCore. Using the native Step Functions SDK integration for Bedrock AgentCore, a Parallel state fans out three branches simultaneously, each invoking a specialized AgentCore runtime built with the Strands Agents SDK. When all branches complete, a synthesis agent combines the findings into a single result.
4+
5+
Learn more about this pattern at Serverless Land Patterns: [https://serverlessland.com/patterns/sfn-parallel-bedrock-agentcore-multi-agent-cdk](https://serverlessland.com/patterns/sfn-parallel-bedrock-agentcore-multi-agent-cdk)
6+
7+
Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.
8+
9+
## Requirements
10+
11+
* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
12+
* [AWS CLI v2](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) (latest available version) installed and configured
13+
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
14+
* [AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html) (version 2.221.0 or later) installed and configured
15+
* [Node.js 22.x](https://nodejs.org/) installed
16+
* [Finch](https://runfinch.com/), [Docker](https://www.docker.com/products/docker-desktop/) or a compatible tool (required to build the agent container image)
17+
18+
## Deployment Instructions
19+
20+
1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
21+
22+
```bash
23+
git clone https://github.com/aws-samples/serverless-patterns
24+
```
25+
26+
1. Change directory to the pattern directory:
27+
28+
```bash
29+
cd sfn-parallel-bedrock-agentcore-multi-agent-cdk
30+
```
31+
32+
1. Install the project dependencies:
33+
34+
```bash
35+
npm install
36+
```
37+
38+
1. Deploy the CDK stacks:
39+
40+
```bash
41+
cdk deploy --all
42+
```
43+
44+
Note: This deploys two stacks — `MultiAgentCoreStack` (the agent runtimes) and `MultiAgentOrchestratorStack` (the Step Functions workflow). Deploy to your default AWS region. Please refer to the [AWS capabilities explorer](https://builder.aws.com/build/capabilities/explore) for feature availability in your desired region.
45+
46+
1. Note the outputs from the CDK deployment process. These contain the resource ARNs used for testing.
47+
48+
## How it works
49+
50+
This pattern creates two stacks:
51+
52+
![state-machine](state-machine.png)
53+
54+
1. **MultiAgentOrchestratorStack** — Deploys a Step Functions state machine that orchestrates the multi-agent workflow using the native [AWS SDK integration for Bedrock AgentCore](https://aws.amazon.com/about-aws/whats-new/2026/03/aws-step-functions-sdk-integrations/) (`aws-sdk:bedrockagentcore:invokeAgentRuntime`):
55+
- A **Parallel** state fans out three branches simultaneously
56+
- Each branch includes built-in retries (2 attempts with exponential backoff) for fault tolerance
57+
- A **SynthesisAgent** Task state combines the three research outputs into a synthesis prompt, invokes the synthesis runtime, and formats the final output
58+
59+
2. **MultiAgentCoreStack** — Deploys two containerized Python agent runtimes on Amazon Bedrock AgentCore using the Strands Agents SDK:
60+
- A **research runtime** that handles three specialized roles (market data, competitive analysis, and news) based on the `role` field in the payload
61+
- A **synthesis runtime** that combines research findings into a cohesive executive report
62+
63+
## Testing
64+
65+
After deployment, start an execution using the AWS CLI or from the AWS Console.
66+
67+
### Start an execution
68+
69+
Use the state machine ARN from the CDK output (`StateMachineArn`):
70+
71+
```bash
72+
aws stepfunctions start-execution \
73+
--state-machine-arn <StateMachineArn> \
74+
--input '{"prompt": "What is the current state of the electric vehicle market in Europe?"}' \
75+
--query 'executionArn' --output text
76+
```
77+
78+
### Check execution status
79+
80+
```bash
81+
aws stepfunctions describe-execution \
82+
--execution-arn <executionArn> \
83+
--query '{status: status, output: output}'
84+
```
85+
86+
### Expected Output
87+
88+
Once the execution completes (typically 60–90 seconds), the output contains:
89+
90+
```json
91+
{
92+
"question": "What is the current state of the electric vehicle market in Europe?",
93+
"report": "{\"role\": \"synthesis\", \"answer\": \"# Executive Research Report: European EV Market\\n\\n## Key Findings\\n...\"}",
94+
"timestamp": "2026-03-27T22:09:46.253Z"
95+
}
96+
```
97+
98+
The three research agents run in parallel, and the synthesis agent produces a unified report combining market data, competitive intelligence, and recent news.
99+
100+
## Cleanup
101+
102+
1. Delete the stacks:
103+
104+
```bash
105+
cdk destroy --all
106+
```
107+
108+
1. Confirm the stacks have been deleted by checking the AWS CloudFormation console or running:
109+
110+
```bash
111+
aws cloudformation list-stacks --stack-status-filter DELETE_COMPLETE
112+
```
113+
114+
----
115+
Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved.
116+
117+
SPDX-License-Identifier: MIT-0
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__pycache__
2+
*.pyc
3+
.git
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM ghcr.io/astral-sh/uv:python3.13-alpine
2+
3+
WORKDIR /app
4+
5+
ENV UV_SYSTEM_PYTHON=1 \
6+
UV_COMPILE_BYTECODE=1
7+
8+
COPY requirements.txt requirements.txt
9+
RUN uv pip install -r requirements.txt
10+
11+
RUN adduser -D -u 1000 bedrock_agentcore
12+
USER bedrock_agentcore
13+
14+
EXPOSE 8080 8000
15+
16+
COPY . .
17+
18+
CMD ["python", "-m", "agent"]
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"""
2+
Strands Agent for AgentCore Runtime.
3+
Accepts a role-based prompt, invokes the LLM, and returns the result.
4+
Used by Step Functions via synchronous InvokeAgentRuntime calls.
5+
"""
6+
import json
7+
import logging
8+
9+
from strands import Agent
10+
from strands.models import BedrockModel
11+
from bedrock_agentcore.runtime import BedrockAgentCoreApp
12+
13+
logger = logging.getLogger(__name__)
14+
app = BedrockAgentCoreApp()
15+
16+
SYSTEM_PROMPTS = {
17+
"market_data": (
18+
"You are a market data research analyst. "
19+
"Provide quantitative market data, trends, market size, growth rates, "
20+
"and key financial metrics relevant to the topic."
21+
),
22+
"competitive_analysis": (
23+
"You are a competitive intelligence analyst. "
24+
"Identify key competitors, their strengths and weaknesses, market positioning, "
25+
"and strategic differentiators relevant to the topic."
26+
),
27+
"news": (
28+
"You are a news research analyst. "
29+
"Summarize the most recent and relevant news, announcements, regulatory changes, "
30+
"and industry developments related to the topic."
31+
),
32+
"synthesis": (
33+
"You are a senior research director. "
34+
"You receive research findings from three analysts covering market data, "
35+
"competitive analysis, and recent news. Synthesize these into a single cohesive "
36+
"executive report with key findings, implications, and recommendations."
37+
),
38+
}
39+
40+
41+
@app.entrypoint
42+
def entrypoint(payload):
43+
"""
44+
Main entrypoint invoked by AgentCore Runtime.
45+
46+
Expects payload:
47+
- prompt: the research question or combined findings
48+
- role: one of market_data, competitive_analysis, news, synthesis
49+
- model (optional): { modelId: "..." }
50+
"""
51+
prompt = payload.get("prompt", "")
52+
role = payload.get("role", "synthesis")
53+
model_config = payload.get("model", {})
54+
model_id = model_config.get(
55+
"modelId", "us.anthropic.claude-sonnet-4-5-20250929-v1:0"
56+
)
57+
58+
system_prompt = SYSTEM_PROMPTS.get(role, SYSTEM_PROMPTS["synthesis"])
59+
60+
model = BedrockModel(model_id=model_id, max_tokens=4096, temperature=0.7)
61+
agent = Agent(model=model, system_prompt=system_prompt)
62+
63+
result = agent(prompt)
64+
return {"role": role, "answer": str(result)}
65+
66+
67+
if __name__ == "__main__":
68+
app.run()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
strands-agents
2+
bedrock-agentcore
3+
boto3
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env node
2+
import 'source-map-support/register';
3+
import * as cdk from 'aws-cdk-lib';
4+
import { AgentCoreStack } from '../lib/agentcore-stack';
5+
import { OrchestratorStack } from '../lib/orchestrator-stack';
6+
7+
const app = new cdk.App();
8+
9+
const env = {
10+
account: process.env.CDK_DEFAULT_ACCOUNT,
11+
region: process.env.CDK_DEFAULT_REGION,
12+
};
13+
14+
const agentCoreStack = new AgentCoreStack(app, 'MultiAgentCoreStack', { env });
15+
16+
new OrchestratorStack(app, 'MultiAgentOrchestratorStack', {
17+
env,
18+
researchRuntimeArn: agentCoreStack.researchRuntimeArn,
19+
researchEndpointUrl: agentCoreStack.researchEndpointUrl,
20+
synthesisRuntimeArn: agentCoreStack.synthesisRuntimeArn,
21+
synthesisEndpointUrl: agentCoreStack.synthesisEndpointUrl,
22+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"app": "npx ts-node --prefer-ts-exts bin/app.ts",
3+
"context": {
4+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
5+
"@aws-cdk/core:checkSecretUsage": true,
6+
"@aws-cdk/core:target-partitions": ["aws", "aws-cn"]
7+
}
8+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{
2+
"title": "Multi-agent orchestration with AWS Step Functions",
3+
"description": "Orchestrate parallel specialized AI agents on Amazon Bedrock AgentCore using the native Step Functions SDK integration with Parallel state for fan-out",
4+
"language": "TypeScript",
5+
"level": "300",
6+
"framework": "AWS CDK",
7+
"introBox": {
8+
"headline": "How it works",
9+
"text": [
10+
"This pattern deploys an AWS Step Functions workflow that orchestrates multiple specialized AI agents running on Amazon Bedrock AgentCore and synthesizes their results into a single output.",
11+
"Using the native Step Functions SDK integration for Bedrock AgentCore, a Parallel state fans out three research branches simultaneously: market data, competitive analysis, and recent news. When all branches complete, a synthesis agent receives the combined outputs and produces the final report. Each branch includes built-in retries for fault tolerance, and Step Functions handles the fan-out, join, and result aggregation automatically."
12+
]
13+
},
14+
"gitHub": {
15+
"template": {
16+
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/sfn-parallel-bedrock-agentcore-multi-agent-cdk",
17+
"templateURL": "serverless-patterns/sfn-parallel-bedrock-agentcore-multi-agent-cdk",
18+
"projectFolder": "sfn-parallel-bedrock-agentcore-multi-agent-cdk",
19+
"templateFile": "lib/orchestrator-stack.ts"
20+
}
21+
},
22+
"resources": {
23+
"bullets": [
24+
{
25+
"text": "AWS Step Functions adds 28 new service integrations, including Amazon Bedrock AgentCore",
26+
"link": "https://aws.amazon.com/about-aws/whats-new/2026/03/aws-step-functions-sdk-integrations/"
27+
},
28+
{
29+
"text": "AWS Step Functions SDK service integrations",
30+
"link": "https://docs.aws.amazon.com/step-functions/latest/dg/supported-services-awssdk.html"
31+
},
32+
{
33+
"text": "AWS Step Functions Parallel state documentation",
34+
"link": "https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-parallel-state.html"
35+
},
36+
{
37+
"text": "Amazon Bedrock AgentCore documentation",
38+
"link": "https://docs.aws.amazon.com/bedrock/latest/userguide/agentcore.html"
39+
},
40+
{
41+
"text": "Strands Agents SDK",
42+
"link": "https://github.com/strands-agents/sdk-python"
43+
},
44+
{
45+
"text": "AWS CDK Developer Guide",
46+
"link": "https://docs.aws.amazon.com/cdk/latest/guide/"
47+
}
48+
]
49+
},
50+
"deploy": {
51+
"text": [
52+
"npm install",
53+
"cdk deploy --all"
54+
]
55+
},
56+
"testing": {
57+
"text": [
58+
"See the GitHub repo for detailed testing instructions."
59+
]
60+
},
61+
"cleanup": {
62+
"text": [
63+
"Delete the stacks: <code>cdk destroy --all</code>."
64+
]
65+
},
66+
"authors": [
67+
{
68+
"name": "Ben Freiberg",
69+
"image": "https://serverlessland.com/assets/images/resources/contributors/ben-freiberg.jpg",
70+
"bio": "Ben is a Senior Solutions Architect at Amazon Web Services (AWS) based in Frankfurt, Germany.",
71+
"linkedin": "benfreiberg"
72+
}
73+
]
74+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import * as cdk from 'aws-cdk-lib';
2+
import * as iam from 'aws-cdk-lib/aws-iam';
3+
import * as path from 'path';
4+
import { Construct } from 'constructs';
5+
import * as agentcore from '@aws-cdk/aws-bedrock-agentcore-alpha';
6+
7+
export class AgentCoreStack extends cdk.Stack {
8+
public readonly researchRuntimeArn: string;
9+
public readonly researchEndpointUrl: string;
10+
public readonly synthesisRuntimeArn: string;
11+
public readonly synthesisEndpointUrl: string;
12+
13+
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
14+
super(scope, id, props);
15+
16+
const agentRuntimeArtifact = agentcore.AgentRuntimeArtifact.fromAsset(
17+
path.join(__dirname, '../agent'),
18+
);
19+
20+
const bedrockPolicy = new iam.PolicyStatement({
21+
effect: iam.Effect.ALLOW,
22+
actions: [
23+
'bedrock:InvokeModel',
24+
'bedrock:InvokeModelWithResponseStream',
25+
],
26+
resources: [
27+
'arn:aws:bedrock:*::foundation-model/*',
28+
'arn:aws:bedrock:*:*:inference-profile/*',
29+
],
30+
});
31+
32+
const ecrPolicy = new iam.PolicyStatement({
33+
effect: iam.Effect.ALLOW,
34+
actions: [
35+
'ecr:GetAuthorizationToken',
36+
'ecr:BatchGetImage',
37+
'ecr:GetDownloadUrlForLayer',
38+
'ecr:BatchCheckLayerAvailability',
39+
],
40+
resources: ['*'],
41+
});
42+
43+
// Research runtime — handles market data, competitive analysis, and news roles
44+
const researchRuntime = new agentcore.Runtime(this, 'ResearchAgentRuntime', {
45+
runtimeName: 'researchAgent',
46+
agentRuntimeArtifact,
47+
description: 'Specialized research agent for market data, competitive analysis, and news',
48+
});
49+
researchRuntime.addToRolePolicy(bedrockPolicy);
50+
researchRuntime.addToRolePolicy(ecrPolicy);
51+
52+
// Synthesis runtime — combines findings into a final report
53+
const synthesisRuntime = new agentcore.Runtime(this, 'SynthesisAgentRuntime', {
54+
runtimeName: 'synthesisAgent',
55+
agentRuntimeArtifact,
56+
description: 'Synthesis agent that combines research findings into an executive report',
57+
});
58+
synthesisRuntime.addToRolePolicy(bedrockPolicy);
59+
synthesisRuntime.addToRolePolicy(ecrPolicy);
60+
61+
this.researchRuntimeArn = researchRuntime.agentRuntimeArn;
62+
this.researchEndpointUrl = `https://bedrock-agentcore-runtime.${this.region}.amazonaws.com/runtimes/${researchRuntime.agentRuntimeId}/endpoints/DEFAULT`;
63+
this.synthesisRuntimeArn = synthesisRuntime.agentRuntimeArn;
64+
this.synthesisEndpointUrl = `https://bedrock-agentcore-runtime.${this.region}.amazonaws.com/runtimes/${synthesisRuntime.agentRuntimeId}/endpoints/DEFAULT`;
65+
66+
new cdk.CfnOutput(this, 'ResearchRuntimeArn', { value: researchRuntime.agentRuntimeArn });
67+
new cdk.CfnOutput(this, 'SynthesisRuntimeArn', { value: synthesisRuntime.agentRuntimeArn });
68+
}
69+
}

0 commit comments

Comments
 (0)