|
| 1 | +# AgentCore Integration |
| 2 | + |
| 3 | +Amazon Bedrock AgentCore enables you to deploy and operate highly capable AI agents securely, at scale. It offers infrastructure purpose-built for dynamic agent workloads, powerful tools to enhance agents, and essential controls for real-world deployment. AgentCore services can be used together or independently and work with any framework including CrewAI, LangGraph, LlamaIndex, and Strands Agents, as well as any foundation model in or outside of Amazon Bedrock, giving you ultimate flexibility. AgentCore eliminates the undifferentiated heavy lifting of building specialized agent infrastructure, so you can accelerate agents to production. |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | +## Prerequisites |
| 8 | + |
| 9 | +1. **Deploy Amazon Bedrock AgentCore Agent Runtime** in your AWS account |
| 10 | + |
| 11 | +The CDK deployment automatically configures the required IAM permissions (`bedrock-agentcore:InvokeAgentRuntime` and `bedrock-agentcore:ListAgentRuntimes`). |
| 12 | + |
| 13 | +## Using AgentCore |
| 14 | + |
| 15 | +### 1. Agent Discovery |
| 16 | + |
| 17 | +Agents are automatically discovered using the `listAgents` GraphQL query, which calls `list_agent_runtimes()` on the bedrock-agentcore-control client. Only users with `admin` or `workspace_manager` roles can access this query. |
| 18 | + |
| 19 | +### 2. Agent Selection |
| 20 | + |
| 21 | +In the chat interface: |
| 22 | + |
| 23 | +- Agents appear in a separate dropdown labeled "Select an agent (optional)" |
| 24 | +- Agents display using `agentRuntimeName` as the label |
| 25 | +- The `agentRuntimeArn` is used as the value |
| 26 | +- Agent selection is optional - you can use regular models instead |
| 27 | + |
| 28 | +### 3. Conversation |
| 29 | + |
| 30 | +- When an agent is selected, the system uses `modelInterface: "agent"` |
| 31 | +- **Thinking Steps**: The agent's reasoning process is displayed in a collapsible section with: |
| 32 | + - Compact vertical timeline layout with connecting lines |
| 33 | + - Real-time updates during streaming responses |
| 34 | + - Visual indicators (emojis) for different agent actions |
| 35 | + - Click to expand/collapse the full thinking process |
| 36 | +- **Streaming**: Both thinking steps and response content stream in real-time |
| 37 | +- **Tool Usage**: When agents use tools, thinking steps show tool invocation and execution |
| 38 | + |
| 39 | +## Interface Between Agent and Chatbot |
| 40 | + |
| 41 | +### Request Format |
| 42 | + |
| 43 | +The chatbot sends the complete request record as JSON payload to the agent's `@app.entrypoint` function: |
| 44 | + |
| 45 | +```python |
| 46 | +{ |
| 47 | + "userId": "user-id", |
| 48 | + "userGroups": ["group1", "group2"], |
| 49 | + "data": { |
| 50 | + "text": "User message", |
| 51 | + "agentRuntimeArn": "arn:aws:bedrock-agentcore:region:account:runtime/agent-id", |
| 52 | + "sessionId": "session-uuid", |
| 53 | + "conversation_history": [ |
| 54 | + {"role": "user", "content": "Previous user message"}, |
| 55 | + {"role": "assistant", "content": "Previous assistant response"} |
| 56 | + ], |
| 57 | + # Additional fields from original request... |
| 58 | + "modelName": "anthropic.claude-3-5-sonnet-20241022-v2:0", |
| 59 | + "modelKwargs": { |
| 60 | + "temperature": 0.7, |
| 61 | + "topP": 0.9, |
| 62 | + "maxTokens": 4000, |
| 63 | + "streaming": true |
| 64 | + } |
| 65 | + } |
| 66 | +} |
| 67 | +``` |
| 68 | + |
| 69 | +**Key Fields:** |
| 70 | + |
| 71 | +- `userId`: User identifier from the chatbot session |
| 72 | +- `userGroups`: User's group memberships for authorization |
| 73 | +- `data.text`: The user's current message |
| 74 | +- `data.agentRuntimeArn`: The selected agent's ARN |
| 75 | +- `data.sessionId`: Session identifier for conversation continuity |
| 76 | +- `data.conversation_history`: Array of previous messages with `role` and `content` fields (up to 20 recent messages) |
| 77 | +- `data.modelName`: Bedrock model identifier (if provided) |
| 78 | +- `data.modelKwargs`: Model configuration including streaming preference |
| 79 | + |
| 80 | +**Important Notes:** |
| 81 | + |
| 82 | +- The `conversation_history` is automatically added by the handler from DynamoDB |
| 83 | +- Messages are converted to simple `{role, content}` objects |
| 84 | +- The entire original request record is passed through, so agents receive all original fields |
| 85 | + |
| 86 | +### Response Format |
| 87 | + |
| 88 | +The agent returns Server-Sent Events (SSE) streaming data that the chatbot processes: |
| 89 | + |
| 90 | +**Streaming SSE Format:** |
| 91 | + |
| 92 | +```python |
| 93 | +# Thinking steps (agent reasoning) |
| 94 | +data: {"type": "thinking", "content": "💭 Assistant starting..."} |
| 95 | +data: {"type": "thinking", "content": "🔧 Calling calculator..."} |
| 96 | +data: {"type": "thinking", "content": "🧠 Analyzing the calculation..."} |
| 97 | +data: {"type": "thinking", "content": "✅ Block complete"} |
| 98 | + |
| 99 | +# Response content (actual answer) |
| 100 | +data: {"type": "content", "content": "The result is "} |
| 101 | +data: {"type": "content", "content": "42"} |
| 102 | +``` |
| 103 | + |
| 104 | +**Non-streaming Response:** |
| 105 | + |
| 106 | +```python |
| 107 | +{ |
| 108 | + "result": "Agent's complete response text" |
| 109 | +} |
| 110 | +``` |
| 111 | + |
| 112 | +**Event Processing:** |
| 113 | + |
| 114 | +- **Thinking Events**: `type: "thinking"` events are displayed in the expandable thinking steps section |
| 115 | +- **Content Events**: `type: "content"` events are accumulated to build the final response |
| 116 | +- **Visual Indicators**: Thinking steps support emoji indicators for different agent actions (needs to be sent by the agent): |
| 117 | + - 💭 Message start/thinking |
| 118 | + - 🔧 Tool usage |
| 119 | + - 🧠 Reasoning content |
| 120 | + - 📚 Citations |
| 121 | + - ✅ Completion markers |
| 122 | + - ⏸️ Tool execution |
| 123 | + - 🏁 Response complete |
| 124 | + |
| 125 | +The above are CoverseStream events sent by a Amazon Bedrock [more info here](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ConverseStream.html#API_runtime_ConverseStream_ResponseSyntax) |
| 126 | + |
| 127 | +### Security |
| 128 | + |
| 129 | +- **Session Isolation**: Each conversation maintains separate session state (Handled by AgentCore) |
| 130 | +- **Error Handling**: Graceful fallback with error recovery for session history |
| 131 | + |
| 132 | +## Getting Started |
| 133 | + |
| 134 | +[QuickStart: Your First Agent in 5 Minutes! 🚀](https://aws.github.io/bedrock-agentcore-starter-toolkit/user-guide/runtime/quickstart.html) |
| 135 | + |
| 136 | +### Simple Agent Example |
| 137 | + |
| 138 | +Here's a minimal agent implementation that demonstrates the core concepts: |
| 139 | + |
| 140 | +```python |
| 141 | +import boto3 |
| 142 | +import json |
| 143 | +from bedrock_agentcore import BedrockAgentCoreApp |
| 144 | +from strands import Agent |
| 145 | +from strands.models import BedrockModel |
| 146 | +from strands_tools import calculator, current_time |
| 147 | + |
| 148 | +app = BedrockAgentCoreApp() |
| 149 | +session = boto3.Session(region_name='il-central-1') |
| 150 | +bedrock_model = BedrockModel(boto_session=session) |
| 151 | + |
| 152 | +agent = Agent( |
| 153 | + system_prompt="You are a helpful AI assistant that can use tools to answer questions.", |
| 154 | + model=bedrock_model, |
| 155 | + tools=[calculator, current_time], |
| 156 | +) |
| 157 | + |
| 158 | +@app.entrypoint |
| 159 | +async def invoke(payload, context): |
| 160 | + """Main agent function with streaming support""" |
| 161 | + # Extract request data |
| 162 | + user_message = payload["data"]["text"] |
| 163 | + conversation_history = payload["data"].get("conversation_history", []) |
| 164 | + is_streaming = payload["data"].get("modelKwargs", {}).get("streaming", False) |
| 165 | + |
| 166 | + # Configure model from payload (if provided) |
| 167 | + if "modelName" in payload["data"]: |
| 168 | + bedrock_model.update_config( |
| 169 | + model_id=payload["data"]["modelName"], |
| 170 | + temperature=payload["data"]["modelKwargs"].get("temperature", 0.7), |
| 171 | + streaming=is_streaming, |
| 172 | + ) |
| 173 | + |
| 174 | + if is_streaming: |
| 175 | + async def generate_sse(): |
| 176 | + async for event in agent.stream_async(user_message): |
| 177 | + if "event" in event: |
| 178 | + bedrock_event = event["event"] |
| 179 | + |
| 180 | + # Handle different event types |
| 181 | + if "contentBlockDelta" in bedrock_event: |
| 182 | + delta = bedrock_event["contentBlockDelta"]["delta"] |
| 183 | + |
| 184 | + if "text" in delta: |
| 185 | + # Stream response content |
| 186 | + sse_data = json.dumps({"type": "content", "content": delta["text"]}) |
| 187 | + yield f"data: {sse_data}\n\n" |
| 188 | + |
| 189 | + elif "reasoningContent" in delta: |
| 190 | + # Stream thinking steps |
| 191 | + reasoning = delta["reasoningContent"]["text"] |
| 192 | + sse_data = json.dumps({"type": "thinking", "content": f"🧠 {reasoning}"}) |
| 193 | + yield f"data: {sse_data}\n\n" |
| 194 | + |
| 195 | + elif "contentBlockStart" in bedrock_event: |
| 196 | + start_data = bedrock_event["contentBlockStart"]["start"] |
| 197 | + if "toolUse" in start_data: |
| 198 | + tool_name = start_data["toolUse"]["name"] |
| 199 | + sse_data = json.dumps({"type": "thinking", "content": f"🔧 Using {tool_name}"}) |
| 200 | + yield f"data: {sse_data}\n\n" |
| 201 | + |
| 202 | + return generate_sse() |
| 203 | + else: |
| 204 | + # Non-streaming response |
| 205 | + result = agent(user_message) |
| 206 | + return {"result": result.message} |
| 207 | + |
| 208 | +if __name__ == "__main__": |
| 209 | + app.run() |
| 210 | +``` |
| 211 | + |
| 212 | +**Key Components:** |
| 213 | + |
| 214 | +- `BedrockAgentCoreApp()`: Main application wrapper |
| 215 | +- `Agent()`: Core agent with system prompt, model, and tools |
| 216 | +- `@app.entrypoint`: Decorator for the main handler function |
| 217 | +- **Streaming**: Uses `agent.stream_async()` for real-time responses |
| 218 | +- **Event Processing**: Handles Bedrock events to extract thinking and content |
| 219 | +- **SSE Format**: Returns properly formatted Server-Sent Events |
| 220 | + |
| 221 | +## Troubleshooting |
| 222 | + |
| 223 | +### Agent Not Available |
| 224 | + |
| 225 | +- Verify agent is deployed and active in Bedrock |
| 226 | +- Confirm agent ARN matches the exact pattern required |
| 227 | +- Check that your user has `admin` or `workspace_manager` role |
| 228 | + |
| 229 | +### Streaming Issues |
| 230 | + |
| 231 | +- Check WebSocket connection in browser developer tools |
| 232 | +- Verify session management in CloudWatch logs |
| 233 | +- Ensure agent provides data in expected `thinking`/`event` format |
| 234 | + |
| 235 | +### Performance |
| 236 | + |
| 237 | +- Agents may take longer than standard models due to reasoning complexity |
| 238 | +- Monitor CloudWatch metrics for agent invocation times |
| 239 | +- Conversation history is limited to prevent payload size issues |
0 commit comments