├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md └── notebooks ├── preview-agent-code-interpreter.ipynb └── preview-agent-long-memory.ipynb /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT No Attribution 2 | 3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 13 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Agents for Amazon Bedrock Feature Samples 2 | 3 | This repository contains Jupyter notebooks demonstrating the use of Amazon Bedrock Agents. These notebooks correspond to YouTube videos and blogs that explain and showcase different features of Amazon Bedrock Agents. 4 | 5 | ## Notebooks 6 | 7 | 1. `preview-agent-code-interpreter.ipynb`: Demonstrates how to set up and use an Amazon Bedrock Agent with Code Interpreter capabilities. 8 | 2. `preview-agent-long-memory.ipynb`: Shows how to create an Amazon Bedrock Agent with long-term memory functionality. 9 | 10 | ## Features Demonstrated 11 | 12 | ### Code Interpreter Agent 13 | - Setting up an AWS Bedrock Agent with Code Interpreter 14 | - Configuring the agent to use Claude 3 Sonnet as the foundation model 15 | - Interacting with the agent to perform tasks like: 16 | - Calculating Fibonacci sequences 17 | - Plotting graphs 18 | - Analyzing and visualizing sample data 19 | 20 | ### Long-Term Memory Agent 21 | - Creating an AWS Bedrock Agent with long-term memory capabilities 22 | - Using Claude 3 Haiku as the foundation model 23 | - Demonstrating how the agent retains information across multiple chat sessions 24 | 25 | ## Prerequisites 26 | 27 | - AWS account with access to Amazon Bedrock 28 | - Enabled access to required models in region (Anthropic Claude 3 Sonnet and Haiku) 29 | - Python 3.x 30 | - Jupyter Notebook 31 | - Required Python libraries: boto3==1.34.144, matplotlib 32 | 33 | ## Setup 34 | 35 | 1. Clone this repository 36 | 2. Install the required Python libraries 37 | 3. Set up your AWS credentials 38 | 4. Open the notebooks in Jupyter and follow the instructions within 39 | 40 | ## Usage 41 | 42 | Each notebook contains step-by-step instructions for creating, interacting with, and cleaning up the Bedrock Agents. They include explanations of the code and concepts, making them suitable for both learning and experimentation. 43 | 44 | ## Important Notes 45 | 46 | - These notebooks use features that may be in preview at the time of creation. Check the current status of Amazon Bedrock features before use. 47 | - Remember to run the cleanup cells at the end of each notebook to remove created resources and avoid unnecessary charges. 48 | 49 | ## Disclaimer 50 | 51 | The code in this repository is for demonstration purposes. Ensure you understand the AWS pricing for Bedrock and related services before running these notebooks in your own environment. 52 | 53 | ## Security 54 | 55 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 56 | 57 | ## License 58 | 59 | This library is licensed under the MIT-0 License. See the LICENSE file. 60 | 61 | -------------------------------------------------------------------------------- /notebooks/preview-agent-code-interpreter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Setting up and Testing an Agent for Amazon Bedrock with Code Interpreter\n", 8 | "\n", 9 | "In this notebook, we'll walk through the process of creating, testing, and cleaning up an Agent in Amazon Bedrock. We'll see how to set up the Code Interpreter action. Code Interpreter enables your agent to write and execute code, process documents, and respond to complex queries via access to a secure code execution sandbox.\n", 10 | "\n", 11 | "Let's dive in!\n", 12 | "\n", 13 | "_(Note: This notebook has cleanup cells at the end, so if you \"Run All\" cells then the resources will be created and then deleted.)_\n", 14 | "\n", 15 | "_Note: At the time of writing Code Interpreter is in public preview. " 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "## Step 1: Import Required Libraries\n", 23 | "\n", 24 | "First, we need to import the necessary Python libraries. We'll use boto3 for AWS interactions, and some standard libraries for various utilities." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "import boto3\n", 34 | "import json\n", 35 | "import time, random \n", 36 | "import uuid, string\n", 37 | "import matplotlib.pyplot as plt\n", 38 | "import io" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": {}, 44 | "source": [ 45 | "## Step 2: Set the AWS Region\n", 46 | "\n", 47 | "We're using the US East (N. Virginia) region for this demo. Feel free to change this to your preferred region, but make sure that a) the region supports Amazon Bedrock, b) Agents, c) the Claude Sonnet (3) model, and finally d) you have enabled access to the Sonnet (3) in this region. " 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "region_name = 'us-east-1'" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "## Step 3: Create the Bedrock Agent\n", 64 | "\n", 65 | "Now comes the exciting part! We're going to set up our Bedrock Agent. This involves creating an IAM role, setting up policies, and configuring the agent itself. We'll use Claude 3 Sonnet as our foundation model." 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "# Set up Bedrock Agent and IAM clients\n", 75 | "bedrock_agent = boto3.client(service_name = 'bedrock-agent', region_name = region_name)\n", 76 | "iam = boto3.client('iam')\n", 77 | "\n", 78 | "agentName = 'code-interpreter-test-agent'\n", 79 | "\n", 80 | "# Define the agent's personality and behavior\n", 81 | "instruction = \"\"\"You are an advanced AI agent with capabilities in code execution, chart generation, and complex data analysis. Your primary function is to assist users by solving problems and fulfilling requests through these capabilities. Here are your key attributes and instructions:\n", 82 | "\n", 83 | "Code Execution:\n", 84 | "\n", 85 | "You have access to a Python environment where you can write and execute code in real-time.\n", 86 | "When asked to perform calculations or data manipulations, always use this code execution capability to ensure accuracy.\n", 87 | "After executing code, report the exact output and explain the results.\n", 88 | "\n", 89 | "\n", 90 | "Data Analysis:\n", 91 | "\n", 92 | "You excel at complex data analysis tasks. This includes statistical analysis, data visualization, and machine learning applications.\n", 93 | "Approach data analysis tasks systematically: understand the problem, prepare the data, perform the analysis, and interpret the results.\n", 94 | "\n", 95 | "\n", 96 | "Problem-Solving Approach:\n", 97 | "\n", 98 | "When presented with a problem or request, break it down into steps.\n", 99 | "Clearly communicate your thought process and the steps you're taking.\n", 100 | "If a task requires multiple steps or tools, outline your approach before beginning.\n", 101 | "\n", 102 | "\n", 103 | "Transparency and Accuracy:\n", 104 | "\n", 105 | "Always be clear about what you're doing. If you're running code, say so. If you're generating an image, explain that.\n", 106 | "If you're unsure about something or if a task is beyond your capabilities, communicate this clearly.\n", 107 | "Do not present hypothetical results as actual outcomes. Only report real results from your code execution or image generation.\n", 108 | "\n", 109 | "\n", 110 | "Interaction Style:\n", 111 | "\n", 112 | "Be concise in simple queries but provide detailed explanations for complex tasks.\n", 113 | "Use technical language appropriately, but be prepared to explain concepts in simpler terms if asked.\n", 114 | "Proactively offer relevant information or alternative approaches that might be helpful.\n", 115 | "\n", 116 | "\n", 117 | "Continuous Improvement:\n", 118 | "\n", 119 | "After completing a task, ask if the user needs any clarification or has follow-up questions.\n", 120 | "Be receptive to feedback and adjust your approach accordingly.\n", 121 | "\n", 122 | "\n", 123 | "Remember, your goal is to provide accurate, helpful, and insightful assistance by leveraging your unique capabilities in code execution, image generation, and data analysis. Always strive to give the most practical and effective solution to the user's request.\"\"\"\n", 124 | "\n", 125 | "# Specify the foundation model to use (for 'code interpreter' it must be Sonnet or Haiku).\n", 126 | "foundationModel = 'anthropic.claude-3-sonnet-20240229-v1:0'\n", 127 | "\n", 128 | "# Generate a random suffix for unique naming\n", 129 | "randomSuffix = \"\".join(\n", 130 | " random.choices(string.ascii_uppercase + string.digits, k=5)\n", 131 | ")\n", 132 | "\n", 133 | "print(\"Creating the IAM policy and role...\")\n", 134 | "\n", 135 | "# Define IAM trust policy\n", 136 | "trustPolicy = {\n", 137 | " \"Version\": \"2012-10-17\",\n", 138 | " \"Statement\": [\n", 139 | " {\n", 140 | " \"Effect\": \"Allow\",\n", 141 | " \"Principal\": {\n", 142 | " \"Service\": \"bedrock.amazonaws.com\"\n", 143 | " },\n", 144 | " \"Action\": \"sts:AssumeRole\"\n", 145 | " }\n", 146 | " ]\n", 147 | "}\n", 148 | "\n", 149 | "# Define IAM policy for invoking the foundation model\n", 150 | "policy = {\n", 151 | " \"Version\": \"2012-10-17\",\n", 152 | " \"Statement\": [\n", 153 | " {\n", 154 | " \"Effect\": \"Allow\",\n", 155 | " \"Action\": [\n", 156 | " \"bedrock:InvokeModel\"\n", 157 | " ],\n", 158 | " \"Resource\": [\n", 159 | " f\"arn:aws:bedrock:{region_name}::foundation-model/{foundationModel}\"\n", 160 | " ]\n", 161 | " }\n", 162 | " ]\n", 163 | "}\n", 164 | "\n", 165 | "role_name = f\"test-agent-{randomSuffix}\"\n", 166 | "\n", 167 | "# Create IAM role and attach policy\n", 168 | "role = iam.create_role(\n", 169 | " RoleName=role_name,\n", 170 | " AssumeRolePolicyDocument = json.dumps(trustPolicy)\n", 171 | ")\n", 172 | "iam.put_role_policy(\n", 173 | " RoleName=role_name,\n", 174 | " PolicyName = f\"policy-test-agent-{randomSuffix}\",\n", 175 | " PolicyDocument = json.dumps(policy)\n", 176 | ")\n", 177 | "\n", 178 | "roleArn = role['Role']['Arn']\n", 179 | "\n", 180 | "print(f\"IAM Role: {roleArn[:13]}{'*' * 12}{roleArn[25:]}\")\n", 181 | "\n", 182 | "print(\"Creating the agent...\")\n", 183 | "\n", 184 | "# Create the Bedrock Agent\n", 185 | "response = bedrock_agent.create_agent(\n", 186 | " agentName=f\"{agentName}-{randomSuffix}\",\n", 187 | " foundationModel=foundationModel,\n", 188 | " instruction=instruction,\n", 189 | " agentResourceRoleArn=roleArn,\n", 190 | ")\n", 191 | "\n", 192 | "agentId = response['agent']['agentId']\n", 193 | "\n", 194 | "print(\"Waiting for agent status of 'NOT_PREPARED'...\")\n", 195 | "\n", 196 | "# Wait for agent to reach 'NOT_PREPARED' status\n", 197 | "agentStatus = ''\n", 198 | "while agentStatus != 'NOT_PREPARED':\n", 199 | " response = bedrock_agent.get_agent(\n", 200 | " agentId=agentId\n", 201 | " )\n", 202 | " agentStatus = response['agent']['agentStatus']\n", 203 | " print(f\"Agent status: {agentStatus}\")\n", 204 | " time.sleep(2)\n", 205 | "\n", 206 | "######################################### Configure code interpreter for the agent\n", 207 | "response = bedrock_agent.create_agent_action_group(\n", 208 | " \n", 209 | " actionGroupName='CodeInterpreterAction',\n", 210 | " actionGroupState='ENABLED',\n", 211 | " agentId=agentId,\n", 212 | " agentVersion='DRAFT',\n", 213 | "\n", 214 | " parentActionGroupSignature='AMAZON.CodeInterpreter' # <- To allow your agent to generate, \n", 215 | " # run, and troubleshoot code when trying \n", 216 | " # to complete a task, set this field to \n", 217 | " # AMAZON.CodeInterpreter. \n", 218 | " # You must leave the `description`, `apiSchema`, \n", 219 | " # and `actionGroupExecutor` fields blank for \n", 220 | " # this action group.\n", 221 | ")\n", 222 | "\n", 223 | "actionGroupId = response['agentActionGroup']['actionGroupId']\n", 224 | "\n", 225 | "print(\"Waiting for action group status of 'ENABLED'...\")\n", 226 | "\n", 227 | "# Wait for action group to reach 'ENABLED' status\n", 228 | "actionGroupStatus = ''\n", 229 | "while actionGroupStatus != 'ENABLED':\n", 230 | " response = bedrock_agent.get_agent_action_group(\n", 231 | " agentId=agentId,\n", 232 | " actionGroupId=actionGroupId,\n", 233 | " agentVersion='DRAFT'\n", 234 | " )\n", 235 | " actionGroupStatus = response['agentActionGroup']['actionGroupState']\n", 236 | " print(f\"Action Group status: {actionGroupStatus}\")\n", 237 | " time.sleep(2)\n", 238 | "\n", 239 | "print(\"Preparing the agent...\")\n", 240 | "\n", 241 | "# Prepare the agent for use\n", 242 | "response = bedrock_agent.prepare_agent(\n", 243 | " agentId=agentId\n", 244 | ")\n", 245 | "\n", 246 | "print(\"Waiting for agent status of 'PREPARED'...\")\n", 247 | "\n", 248 | "# Wait for agent to reach 'PREPARED' status\n", 249 | "agentStatus = ''\n", 250 | "while agentStatus != 'PREPARED':\n", 251 | " response = bedrock_agent.get_agent(\n", 252 | " agentId=agentId\n", 253 | " )\n", 254 | " agentStatus = response['agent']['agentStatus']\n", 255 | " print(f\"Agent status: {agentStatus}\")\n", 256 | " time.sleep(2)\n", 257 | "\n", 258 | "print(\"Creating an agent alias...\")\n", 259 | "\n", 260 | "# Create an alias for the agent\n", 261 | "response = bedrock_agent.create_agent_alias(\n", 262 | " agentAliasName='test',\n", 263 | " agentId=agentId\n", 264 | ")\n", 265 | "\n", 266 | "agentAliasId = response['agentAlias']['agentAliasId']\n", 267 | "\n", 268 | "# Wait for agent alias to be prepared\n", 269 | "agentAliasStatus = ''\n", 270 | "while agentAliasStatus != 'PREPARED':\n", 271 | " response = bedrock_agent.get_agent_alias(\n", 272 | " agentId=agentId,\n", 273 | " agentAliasId=agentAliasId\n", 274 | " )\n", 275 | " agentAliasStatus = response['agentAlias']['agentAliasStatus']\n", 276 | " print(f\"Agent alias status: {agentAliasStatus}\")\n", 277 | " time.sleep(2)\n", 278 | "\n", 279 | "print('Done.\\n')\n", 280 | "\n", 281 | "print(f\"agentId: {agentId}, agentAliasId: {agentAliasId}\")" 282 | ] 283 | }, 284 | { 285 | "cell_type": "markdown", 286 | "metadata": {}, 287 | "source": [ 288 | "Phew! That was a lot, but we've successfully set up our Bedrock Agent. Let's break down what we did:\n", 289 | "\n", 290 | "1. We created an IAM role and policy to allow our agent to invoke the foundation model.\n", 291 | "2. We created the agent itself, using Claude 3 Sonnet as the foundation model.\n", 292 | "3. We created an action group and enabled Code Interpreter.\n", 293 | "4. We prepared the agent and created an alias for it.\n", 294 | "\n", 295 | "Now that our agent is ready, let's set up the runtime client to interact with it!" 296 | ] 297 | }, 298 | { 299 | "cell_type": "code", 300 | "execution_count": null, 301 | "metadata": {}, 302 | "outputs": [], 303 | "source": [ 304 | "bedrock_agent_runtime = boto3.client(service_name = 'bedrock-agent-runtime', region_name = region_name)" 305 | ] 306 | }, 307 | { 308 | "cell_type": "markdown", 309 | "metadata": {}, 310 | "source": [ 311 | "## Step 5: Create an Invoke Function\n", 312 | "\n", 313 | "Now, let's create a handy function to interact with our agent. This function will handle sending messages to the agent and processing its responses." 314 | ] 315 | }, 316 | { 317 | "cell_type": "code", 318 | "execution_count": null, 319 | "metadata": {}, 320 | "outputs": [], 321 | "source": [ 322 | "def invoke(inputText, showTrace=False, endSession=False):\n", 323 | "\n", 324 | " try:\n", 325 | "\n", 326 | " # Invoke the Agent - Sends a prompt for the agent to process and respond to.\n", 327 | " response = bedrock_agent_runtime.invoke_agent(\n", 328 | " agentAliasId=agentAliasId, # (string) – [REQUIRED] The alias of the agent to use.\n", 329 | " agentId=agentId, # (string) – [REQUIRED] The unique identifier of the agent to use.\n", 330 | " sessionId=sessionId, # (string) – [REQUIRED] The unique identifier of the session. Use the same value across requests to continue the same conversation.\n", 331 | " inputText=inputText, # (string) - The prompt text to send the agent.\n", 332 | " endSession=endSession, # (boolean) – Specifies whether to end the session with the agent or not.\n", 333 | " enableTrace=True, # (boolean) – Specifies whether to turn on the trace or not to track the agent's reasoning process.\n", 334 | " )\n", 335 | "\n", 336 | " # To upload files to the agent, for use in the sandbox use sessionState:\n", 337 | " # sessionState = {\n", 338 | " # \"files\": [\n", 339 | " # {\n", 340 | " # \"name\": \"test_data.json\",\n", 341 | " # \"source\": {\n", 342 | " # \"byteContent\": {\n", 343 | " # \"data\": data,\n", 344 | " # \"mediaType\": \"application/json\"\n", 345 | " # },\n", 346 | " # \"sourceType\": \"BYTE_CONTENT\"\n", 347 | " # },\n", 348 | " # \"useCase\": \"CODE_INTERPRETER\"\n", 349 | " # }\n", 350 | " # ]\n", 351 | " # }\n", 352 | "\n", 353 | " # The response of this operation contains an EventStream member. \n", 354 | " event_stream = response[\"completion\"]\n", 355 | "\n", 356 | " # When iterated the EventStream will yield events.\n", 357 | " for event in event_stream:\n", 358 | "\n", 359 | " # chunk contains a part of an agent response\n", 360 | " if 'chunk' in event:\n", 361 | " chunk = event['chunk']\n", 362 | " if 'bytes' in chunk:\n", 363 | " text = chunk['bytes'].decode('utf-8')\n", 364 | " print(f\"Chunk: {text}\")\n", 365 | " else:\n", 366 | " print(\"Chunk doesn't contain 'bytes'\")\n", 367 | "\n", 368 | " # files contains intermediate response for code interpreter if any files have been generated.\n", 369 | " if 'files' in event:\n", 370 | " files = event['files']['files']\n", 371 | " for file in files:\n", 372 | " name = file['name']\n", 373 | " type = file['type']\n", 374 | " bytes_data = file['bytes']\n", 375 | " \n", 376 | " # It the file is a PNG image then we can display it...\n", 377 | " if type == 'image/png':\n", 378 | " # Display PNG image using Matplotlib\n", 379 | " img = plt.imread(io.BytesIO(bytes_data))\n", 380 | " plt.figure(figsize=(10, 10))\n", 381 | " plt.imshow(img)\n", 382 | " plt.axis('off')\n", 383 | " plt.title(name)\n", 384 | " plt.show()\n", 385 | " plt.close()\n", 386 | " \n", 387 | " # If the file is NOT a PNG then we save it to disk...\n", 388 | " else:\n", 389 | " # Save other file types to local disk\n", 390 | " with open(name, 'wb') as f:\n", 391 | " f.write(bytes_data)\n", 392 | " print(f\"File '{name}' saved to disk.\")\n", 393 | "\n", 394 | " except Exception as e:\n", 395 | " print(f\"Error: {e}\")" 396 | ] 397 | }, 398 | { 399 | "cell_type": "markdown", 400 | "metadata": {}, 401 | "source": [ 402 | "This `invoke` function is our Swiss Army knife for interacting with the agent. It handles sending messages, processing responses, and even allows us to view and save files created by the agent." 403 | ] 404 | }, 405 | { 406 | "cell_type": "markdown", 407 | "metadata": {}, 408 | "source": [ 409 | "## Step 6: Interacting with the Agent _(Remember this is preview.)_" 410 | ] 411 | }, 412 | { 413 | "cell_type": "code", 414 | "execution_count": null, 415 | "metadata": {}, 416 | "outputs": [], 417 | "source": [ 418 | "sessionId = str(uuid.uuid4())\n", 419 | "invoke(\"Calculate the sum of the Fibonacci sequence up to 1000.\")" 420 | ] 421 | }, 422 | { 423 | "cell_type": "code", 424 | "execution_count": null, 425 | "metadata": {}, 426 | "outputs": [], 427 | "source": [ 428 | "invoke(\"Plot a graph of the Fibonacci sequence.\")" 429 | ] 430 | }, 431 | { 432 | "cell_type": "code", 433 | "execution_count": null, 434 | "metadata": {}, 435 | "outputs": [], 436 | "source": [ 437 | "sessionId = str(uuid.uuid4())\n", 438 | "\n", 439 | "invoke(\"\"\"Using the billing data provided below, create a bar \n", 440 | "graph that shows the total spend by product category (cat). \n", 441 | "The graph should have the category names on the x-axis and \n", 442 | "the total spend amount on the y-axis.\n", 443 | "\n", 444 | "Billing Data: \n", 445 | "date,cat,id,product_name,cost \n", 446 | "2023-01-15,Electronics,E001,Smartphone,799.99 \n", 447 | "2023-01-20,Home,H001,Vacuum Cleaner,199.99 \n", 448 | "2023-02-03,Electronics,E002,Laptop,1299.99 \n", 449 | "2023-02-10,Clothing,C001,Winter Jacket,129.99 \n", 450 | "2023-02-25,Home,H002,Coffee Maker,89.99 \n", 451 | "2023-03-05,Electronics,E003,Wireless Earbuds,159.99 \n", 452 | "2023-03-12,Clothing,C002,Running Shoes,99.99 \n", 453 | "2023-03-30,Home,H003,Blender,79.99 \n", 454 | "2023-04-08,Electronics,E004,Smart Watch,299.99 \n", 455 | "2023-04-15,Clothing,C003,Jeans,59.99 \n", 456 | "2023-04-28,Home,H004,Toaster Oven,129.99 \n", 457 | "2023-05-10,Electronics,E005,Tablet,499.99 \n", 458 | "2023-05-18,Clothing,C004,Dress Shirt,49.99 \n", 459 | "2023-05-25,Home,H005,Air Purifier,199.99 \n", 460 | "2023-06-02,Electronics,E006,Gaming Console,399.99\n", 461 | "\n", 462 | "Ensure that the graph is clearly labeled and easy to read. \n", 463 | "After generating the graph, provide a brief interpretation \n", 464 | "of the results, highlighting which category has the highest \n", 465 | "total spend and any other notable observations.\"\"\")" 466 | ] 467 | }, 468 | { 469 | "cell_type": "code", 470 | "execution_count": null, 471 | "metadata": {}, 472 | "outputs": [], 473 | "source": [ 474 | "invoke(\"Format the sales data into a JSON format. And save to a file.\")" 475 | ] 476 | }, 477 | { 478 | "cell_type": "markdown", 479 | "metadata": {}, 480 | "source": [ 481 | "## Step 9: Cleaning Up\n", 482 | "\n", 483 | "We've had a great time chatting with our Bedrock Agent, but now it's time to clean up. Let's delete the agent and its associated resources." 484 | ] 485 | }, 486 | { 487 | "cell_type": "code", 488 | "execution_count": null, 489 | "metadata": {}, 490 | "outputs": [], 491 | "source": [ 492 | "response = bedrock_agent.delete_agent(\n", 493 | " agentId=agentId,\n", 494 | " skipResourceInUseCheck=True\n", 495 | ")\n", 496 | "\n", 497 | "response['agentStatus']" 498 | ] 499 | }, 500 | { 501 | "cell_type": "markdown", 502 | "metadata": {}, 503 | "source": [ 504 | "Finally, let's clean up the IAM role and policies we created for this demo." 505 | ] 506 | }, 507 | { 508 | "cell_type": "code", 509 | "execution_count": null, 510 | "metadata": {}, 511 | "outputs": [], 512 | "source": [ 513 | "inline_policies = iam.list_role_policies(RoleName=role_name)\n", 514 | "for policy_name in inline_policies.get('PolicyNames', []):\n", 515 | " iam.delete_role_policy(RoleName=role_name, PolicyName=policy_name)\n", 516 | " print(f\"Deleted inline policy: {policy_name}\")\n", 517 | "\n", 518 | "response = iam.delete_role(\n", 519 | " RoleName=role_name\n", 520 | ")\n", 521 | "\n", 522 | "print(f\"Deleted role.\")" 523 | ] 524 | }, 525 | { 526 | "cell_type": "markdown", 527 | "metadata": {}, 528 | "source": [ 529 | "## Conclusion\n", 530 | "\n", 531 | "And there you have it! We've successfully created a Bedrock Agent, access to a sandbox to execute code in order to be able to answer complex queries, had a conversation with it, and then cleaned everything up. \n", 532 | "\n", 533 | "Through this process, we've seen how to:\n", 534 | "1. Set up the necessary AWS resources for a Bedrock Agent\n", 535 | "2. Create and configure an agent with Code Interpreter \n", 536 | "3. Interact with the agent and observe its responses\n", 537 | "4. Clean up all the resources when we're done\n", 538 | "\n", 539 | "This demo showcases the power of Bedrock Agents and how they can be used to create interactive AI assistants that can process complex queries. The possibilities for using this in various applications are endless!" 540 | ] 541 | } 542 | ], 543 | "metadata": { 544 | "kernelspec": { 545 | "display_name": "base", 546 | "language": "python", 547 | "name": "python3" 548 | }, 549 | "language_info": { 550 | "codemirror_mode": { 551 | "name": "ipython", 552 | "version": 3 553 | }, 554 | "file_extension": ".py", 555 | "mimetype": "text/x-python", 556 | "name": "python", 557 | "nbconvert_exporter": "python", 558 | "pygments_lexer": "ipython3", 559 | "version": "3.10.14" 560 | } 561 | }, 562 | "nbformat": 4, 563 | "nbformat_minor": 2 564 | } 565 | -------------------------------------------------------------------------------- /notebooks/preview-agent-long-memory.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Setting up and Testing an Agent for Amazon Bedrock with Long Term Memory\n", 8 | "\n", 9 | "In this notebook, we'll walk through the process of creating, testing, and cleaning up an Agent in Amazon Bedrock. We'll see how to set up long-term memory, interact with the agent, and even peek into its thought process. \n", 10 | "\n", 11 | "We're going to use Agents for Amazon Bedrock in it's simplest form, as a basic chatbot, without any actions. We do this so that we can focus on the long term memory feature. Keep in mind that one of the main points of agents is to have actions, so these could be added later. \n", 12 | "\n", 13 | "Let's dive in!\n", 14 | "\n", 15 | "_(Note: This notebook has cleanup cells at the end, so if you \"Run All\" cells then the resources will be created and then deleted.)_" 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "## Step 1: Import Required Libraries\n", 23 | "\n", 24 | "First, we need to import the necessary Python libraries. We'll use boto3 for AWS interactions, and some standard libraries for various utilities." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "import boto3\n", 34 | "import json\n", 35 | "import time, random \n", 36 | "import uuid, string" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": {}, 42 | "source": [ 43 | "## Step 2: Set the AWS Region\n", 44 | "\n", 45 | "We're using the US West (Oregon) region for this demo. Feel free to change this to your preferred region, but make sure that a) the region supports Amazon Bedrock, b) Agents, c) the Claude Haiku model, and finally d) you have enabled access to the Haiku in this region. " 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "region_name = 'us-west-2' " 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "## Step 3: Create the Bedrock Agent\n", 62 | "\n", 63 | "Now comes the exciting part! We're going to set up our Bedrock Agent. This involves creating an IAM role, setting up policies, and configuring the agent itself. We'll use Claude 3 Haiku as our foundation model." 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": null, 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [ 72 | "# Set up Bedrock Agent and IAM clients\n", 73 | "bedrock_agent = boto3.client(service_name = 'bedrock-agent', region_name = region_name)\n", 74 | "iam = boto3.client('iam')\n", 75 | "\n", 76 | "agentName = 'long-term-memory-test-agent'\n", 77 | "\n", 78 | "# Define the agent's personality and behavior\n", 79 | "instruction = \"\"\"You are a witty and knowledgeable AI assistant with a passion for obscure facts and wordplay. Your personality traits include:\n", 80 | "\n", 81 | "Curiosity: You love learning new things and asking thought-provoking questions.\n", 82 | "Humor: You have a dry wit and enjoy making subtle jokes and puns.\n", 83 | "Creativity: You approach problems from unique angles and enjoy coming up with inventive solutions.\n", 84 | "Empathy: You're attentive to the user's mood and adapt your tone accordingly.\n", 85 | "Enthusiasm: You get excited about interesting topics and aren't afraid to show it.\n", 86 | "\n", 87 | "Your primary goals in any conversation are to:\n", 88 | "\n", 89 | "Engage the user in stimulating dialogue.\n", 90 | "Share interesting and relevant information when appropriate.\n", 91 | "Encourage the user to think critically and creatively.\n", 92 | "Provide helpful assistance while maintaining a light-hearted tone.\n", 93 | "\n", 94 | "When you don't know the answer to a question:\n", 95 | "\n", 96 | "Admit it honestly.\n", 97 | "Speculate playfully about what the answer might be.\n", 98 | "Suggest how you might go about finding the answer if you were human.\n", 99 | "\n", 100 | "Remember, you're here for friendly chats and intellectual exploration. Have fun with the conversation, but always remain helpful and respectful.\"\"\"\n", 101 | "\n", 102 | "# Specify the foundation model to use (for 'memory' it must be Sonnet or Haiku).\n", 103 | "foundationModel = 'anthropic.claude-3-haiku-20240307-v1:0'\n", 104 | "\n", 105 | "# Generate a random suffix for unique naming\n", 106 | "randomSuffix = \"\".join(\n", 107 | " random.choices(string.ascii_uppercase + string.digits, k=5)\n", 108 | ")\n", 109 | "\n", 110 | "print(\"Creating the IAM policy and role...\")\n", 111 | "\n", 112 | "# Define IAM trust policy\n", 113 | "trustPolicy = {\n", 114 | " \"Version\": \"2012-10-17\",\n", 115 | " \"Statement\": [\n", 116 | " {\n", 117 | " \"Effect\": \"Allow\",\n", 118 | " \"Principal\": {\n", 119 | " \"Service\": \"bedrock.amazonaws.com\"\n", 120 | " },\n", 121 | " \"Action\": \"sts:AssumeRole\"\n", 122 | " }\n", 123 | " ]\n", 124 | "}\n", 125 | "\n", 126 | "# Define IAM policy for invoking the foundation model\n", 127 | "policy = {\n", 128 | " \"Version\": \"2012-10-17\",\n", 129 | " \"Statement\": [\n", 130 | " {\n", 131 | " \"Effect\": \"Allow\",\n", 132 | " \"Action\": [\n", 133 | " \"bedrock:InvokeModel\"\n", 134 | " ],\n", 135 | " \"Resource\": [\n", 136 | " f\"arn:aws:bedrock:{region_name}::foundation-model/{foundationModel}\"\n", 137 | " ]\n", 138 | " }\n", 139 | " ]\n", 140 | "}\n", 141 | "\n", 142 | "role_name = f\"test-agent-{randomSuffix}\"\n", 143 | "\n", 144 | "# Create IAM role and attach policy\n", 145 | "role = iam.create_role(\n", 146 | " RoleName=role_name,\n", 147 | " AssumeRolePolicyDocument = json.dumps(trustPolicy)\n", 148 | ")\n", 149 | "iam.put_role_policy(\n", 150 | " RoleName=role_name,\n", 151 | " PolicyName = f\"policy-test-agent-{randomSuffix}\",\n", 152 | " PolicyDocument = json.dumps(policy)\n", 153 | ")\n", 154 | "\n", 155 | "roleArn = role['Role']['Arn']\n", 156 | "\n", 157 | "print(f\"IAM Role: {roleArn[:13]}{'*' * 12}{roleArn[25:]}\")\n", 158 | "\n", 159 | "print(\"Creating the agent...\")\n", 160 | "\n", 161 | "# Create the Bedrock Agent\n", 162 | "response = bedrock_agent.create_agent(\n", 163 | " agentName=f\"{agentName}-{randomSuffix}\",\n", 164 | " foundationModel=foundationModel,\n", 165 | " instruction=instruction,\n", 166 | " agentResourceRoleArn=roleArn,\n", 167 | " \n", 168 | " ######################################### Configure memory for the agent\n", 169 | " memoryConfiguration={\n", 170 | " 'enabledMemoryTypes': [\n", 171 | " 'SESSION_SUMMARY', # Type of memory to store\n", 172 | " ],\n", 173 | " 'storageDays': 30 # Number of days to retain conversational context\n", 174 | " }\n", 175 | ")\n", 176 | "\n", 177 | "agentId = response['agent']['agentId']\n", 178 | "\n", 179 | "print(\"Waiting for agent status of 'NOT_PREPARED'...\")\n", 180 | "\n", 181 | "# Wait for agent to reach 'NOT_PREPARED' status\n", 182 | "agentStatus = ''\n", 183 | "while agentStatus != 'NOT_PREPARED':\n", 184 | " response = bedrock_agent.get_agent(\n", 185 | " agentId=agentId\n", 186 | " )\n", 187 | " agentStatus = response['agent']['agentStatus']\n", 188 | " print(f\"Agent status: {agentStatus}\")\n", 189 | " time.sleep(2)\n", 190 | "\n", 191 | "print(\"Preparing the agent...\")\n", 192 | "\n", 193 | "# Prepare the agent for use\n", 194 | "response = bedrock_agent.prepare_agent(\n", 195 | " agentId=agentId\n", 196 | ")\n", 197 | "\n", 198 | "print(\"Waiting for agent status of 'PREPARED'...\")\n", 199 | "\n", 200 | "# Wait for agent to reach 'PREPARED' status\n", 201 | "agentStatus = ''\n", 202 | "while agentStatus != 'PREPARED':\n", 203 | " response = bedrock_agent.get_agent(\n", 204 | " agentId=agentId\n", 205 | " )\n", 206 | " agentStatus = response['agent']['agentStatus']\n", 207 | " print(f\"Agent status: {agentStatus}\")\n", 208 | " time.sleep(2)\n", 209 | "\n", 210 | "print(\"Creating an agent alias...\")\n", 211 | "\n", 212 | "# Create an alias for the agent\n", 213 | "response = bedrock_agent.create_agent_alias(\n", 214 | " agentAliasName='test',\n", 215 | " agentId=agentId\n", 216 | ")\n", 217 | "\n", 218 | "agentAliasId = response['agentAlias']['agentAliasId']\n", 219 | "\n", 220 | "# Wait for agent alias to be prepared\n", 221 | "agentAliasStatus = ''\n", 222 | "while agentAliasStatus != 'PREPARED':\n", 223 | " response = bedrock_agent.get_agent_alias(\n", 224 | " agentId=agentId,\n", 225 | " agentAliasId=agentAliasId\n", 226 | " )\n", 227 | " agentAliasStatus = response['agentAlias']['agentAliasStatus']\n", 228 | " print(f\"Agent alias status: {agentAliasStatus}\")\n", 229 | " time.sleep(2)\n", 230 | "\n", 231 | "print('Done.\\n')\n", 232 | "\n", 233 | "print(f\"agentId: {agentId}, agentAliasId: {agentAliasId}\")" 234 | ] 235 | }, 236 | { 237 | "cell_type": "markdown", 238 | "metadata": {}, 239 | "source": [ 240 | "Phew! That was a lot, but we've successfully set up our Bedrock Agent. Let's break down what we did:\n", 241 | "\n", 242 | "1. We created an IAM role and policy to allow our agent to invoke the foundation model.\n", 243 | "2. We created the agent itself, using Claude 3 Haiku as the foundation model.\n", 244 | "3. We enabled long-term memory (SESSION_SUMMARY) for our agent...\n", 245 | "\n", 246 | "```\n", 247 | " memoryConfiguration={\n", 248 | " 'enabledMemoryTypes': [\n", 249 | " 'SESSION_SUMMARY',\n", 250 | " ],\n", 251 | " 'storageDays': 30\n", 252 | " }\n", 253 | "```\n", 254 | "\n", 255 | "4. We prepared the agent and created an alias for it.\n", 256 | "\n", 257 | "Now that our agent is ready, let's set up the runtime client to interact with it!" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": null, 263 | "metadata": {}, 264 | "outputs": [], 265 | "source": [ 266 | "bedrock_agent_runtime = boto3.client(service_name = 'bedrock-agent-runtime', region_name = region_name)" 267 | ] 268 | }, 269 | { 270 | "cell_type": "markdown", 271 | "metadata": {}, 272 | "source": [ 273 | "## Step 4: Set Up Session and Memory IDs\n", 274 | "\n", 275 | "To keep track of our conversations and memories, we need to set up session and memory IDs. The session ID will change for each new conversation, while the memory ID remains constant to maintain long-term memory." 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": null, 281 | "metadata": {}, 282 | "outputs": [], 283 | "source": [ 284 | "sessionId = str(uuid.uuid4())\n", 285 | "memoryId = \"TEST-MEMORY-ID-ABC123\"" 286 | ] 287 | }, 288 | { 289 | "cell_type": "markdown", 290 | "metadata": {}, 291 | "source": [ 292 | "## Step 5: Create an Invoke Function\n", 293 | "\n", 294 | "Now, let's create a handy function to interact with our agent. This function will handle sending messages to the agent and processing its responses." 295 | ] 296 | }, 297 | { 298 | "cell_type": "code", 299 | "execution_count": null, 300 | "metadata": {}, 301 | "outputs": [], 302 | "source": [ 303 | "def invoke(inputText, showTrace=False, endSession=False):\n", 304 | "\n", 305 | " try:\n", 306 | "\n", 307 | " # Invoke the Agent - Sends a prompt for the agent to process and respond to.\n", 308 | " response = bedrock_agent_runtime.invoke_agent(\n", 309 | " agentAliasId=agentAliasId, # (string) – [REQUIRED] The alias of the agent to use.\n", 310 | " agentId=agentId, # (string) – [REQUIRED] The unique identifier of the agent to use.\n", 311 | " sessionId=sessionId, # (string) – [REQUIRED] The unique identifier of the session. Use the same value across requests to continue the same conversation.\n", 312 | " inputText=inputText, # (string) - The prompt text to send the agent.\n", 313 | " memoryId=memoryId, # (string) – The unique identifier of the agent memory.\n", 314 | " endSession=endSession, # (boolean) – Specifies whether to end the session with the agent or not.\n", 315 | " enableTrace=True, # (boolean) – Specifies whether to turn on the trace or not to track the agent's reasoning process.\n", 316 | " )\n", 317 | "\n", 318 | " # The response of this operation contains an EventStream member. \n", 319 | " event_stream = response[\"completion\"]\n", 320 | "\n", 321 | " # When iterated the EventStream will yield events.\n", 322 | " for event in event_stream:\n", 323 | " \n", 324 | " # chunk contains a part of an agent response\n", 325 | " if 'chunk' in event:\n", 326 | " chunk = event['chunk']\n", 327 | " if 'bytes' in chunk:\n", 328 | " text = chunk['bytes'].decode('utf-8')\n", 329 | " print(f\"Chunk: {text}\\n\")\n", 330 | " else:\n", 331 | " print(\"Chunk doesn't contain 'bytes'\")\n", 332 | " \n", 333 | " # Trace enablement helps you follow the agent's reasoning process that led it to \n", 334 | " # the information it processed, the actions it took, and the final result it yielded. \n", 335 | " # Here we will print out some trace info, and do some basic formatting for convenance.\n", 336 | " if showTrace:\n", 337 | " if 'trace' in event:\n", 338 | " trace = event['trace']\n", 339 | " if 'modelInvocationInput' in trace['trace']['orchestrationTrace']:\n", 340 | " mii = trace['trace']['orchestrationTrace']['modelInvocationInput']['text']\n", 341 | " system_prompt = json.loads(mii)['system']\n", 342 | " system_prompt_format = ((system_prompt.replace(' ','\\n')).replace('.-', '.\\n\\t-')).replace('<','\\n<')\n", 343 | " print(f\"Trace: Systems Prompt: {system_prompt_format}\\n{'-'*100}\")\n", 344 | " if 'rationale' in trace['trace']['orchestrationTrace']:\n", 345 | " print(f\"Trace: Rationale: {trace['trace']['orchestrationTrace']['rationale']['text']}\\n{'-'*100}\")\n", 346 | "\n", 347 | " except Exception as e:\n", 348 | " print(f\"Error: {e}\")\n", 349 | "\n", 350 | "def end_session():\n", 351 | " invoke(\"Goodbye\", False, True)" 352 | ] 353 | }, 354 | { 355 | "cell_type": "markdown", 356 | "metadata": {}, 357 | "source": [ 358 | "This `invoke` function is our Swiss Army knife for interacting with the agent. It handles sending messages, processing responses, and even allows us to peek into the agent's thought process with the `showTrace` option. The `end_session` function is a convenient way to politely end our conversation with the agent." 359 | ] 360 | }, 361 | { 362 | "cell_type": "markdown", 363 | "metadata": {}, 364 | "source": [ 365 | "## Step 6: Interacting with the Agent _(Remember this is preview.)_\n", 366 | "\n", 367 | "Now that we have everything set up, let's have a conversation with our agent! We'll start with a simple greeting and then share some information about our preferences." 368 | ] 369 | }, 370 | { 371 | "cell_type": "code", 372 | "execution_count": null, 373 | "metadata": {}, 374 | "outputs": [], 375 | "source": [ 376 | "invoke(\"Hello.\")" 377 | ] 378 | }, 379 | { 380 | "cell_type": "markdown", 381 | "metadata": {}, 382 | "source": [ 383 | "Let's tell our agent about our beverage preferences. This information will be stored in its long-term memory." 384 | ] 385 | }, 386 | { 387 | "cell_type": "code", 388 | "execution_count": null, 389 | "metadata": {}, 390 | "outputs": [], 391 | "source": [ 392 | "invoke(\"I really like tea, its my favorite drink. I do not like coffee much.\")" 393 | ] 394 | }, 395 | { 396 | "cell_type": "markdown", 397 | "metadata": {}, 398 | "source": [ 399 | "Now, let's get more specific about our tea preferences." 400 | ] 401 | }, 402 | { 403 | "cell_type": "code", 404 | "execution_count": null, 405 | "metadata": {}, 406 | "outputs": [], 407 | "source": [ 408 | "invoke(\"I like black tea, with no milk or sugar. Its super easy to make and its what I like.\")" 409 | ] 410 | }, 411 | { 412 | "cell_type": "markdown", 413 | "metadata": {}, 414 | "source": [ 415 | "Great! We've had a nice chat with our agent and shared some personal preferences. Now, let's end this session and see how the agent's memory works." 416 | ] 417 | }, 418 | { 419 | "cell_type": "code", 420 | "execution_count": null, 421 | "metadata": {}, 422 | "outputs": [], 423 | "source": [ 424 | "end_session()" 425 | ] 426 | }, 427 | { 428 | "cell_type": "markdown", 429 | "metadata": {}, 430 | "source": [ 431 | "## Step 7: Checking the Agent's Memory\n", 432 | "\n", 433 | "After ending the session, let's check what the agent has stored in its long-term memory. This process might take a few minutes as the agent processes and summarizes the conversation." 434 | ] 435 | }, 436 | { 437 | "cell_type": "code", 438 | "execution_count": null, 439 | "metadata": {}, 440 | "outputs": [], 441 | "source": [ 442 | "start_time = time.time()\n", 443 | "timeout = 300 # 5 minutes in seconds\n", 444 | "memoryContents = []\n", 445 | "\n", 446 | "while len(memoryContents) < 1 and (time.time() - start_time) < timeout:\n", 447 | " response = bedrock_agent_runtime.get_agent_memory(\n", 448 | " agentAliasId=agentAliasId,\n", 449 | " agentId=agentId,\n", 450 | " memoryId=memoryId,\n", 451 | " memoryType='SESSION_SUMMARY',\n", 452 | " )\n", 453 | " memoryContents = response.get('memoryContents', [])\n", 454 | " \n", 455 | " if len(memoryContents) == 0:\n", 456 | " print(\"Waiting for memory to be captured...\")\n", 457 | " time.sleep(15)\n", 458 | "\n", 459 | "if len(memoryContents) > 0:\n", 460 | " print(\"Memory is captured.\")\n", 461 | " print(memoryContents[0]['sessionSummary']['summaryText'])\n", 462 | "else:\n", 463 | " raise TimeoutError(\"Timeout reached. Memory was not captured within 5 minutes.\")" 464 | ] 465 | }, 466 | { 467 | "cell_type": "markdown", 468 | "metadata": {}, 469 | "source": [ 470 | "## Step 8: Starting a New Session\n", 471 | "\n", 472 | "Now that we've seen what the agent remembers, let's start a new session and see if it can recall our preferences." 473 | ] 474 | }, 475 | { 476 | "cell_type": "code", 477 | "execution_count": null, 478 | "metadata": {}, 479 | "outputs": [], 480 | "source": [ 481 | "sessionId = str(uuid.uuid4())" 482 | ] 483 | }, 484 | { 485 | "cell_type": "markdown", 486 | "metadata": {}, 487 | "source": [ 488 | "Let's ask the agent about our drink preference and see if it remembers!" 489 | ] 490 | }, 491 | { 492 | "cell_type": "code", 493 | "execution_count": null, 494 | "metadata": {}, 495 | "outputs": [], 496 | "source": [ 497 | "invoke(\"Hello again. If you could make me a drink, what would it be?\")" 498 | ] 499 | }, 500 | { 501 | "cell_type": "markdown", 502 | "metadata": {}, 503 | "source": [ 504 | "Now, let's mention something new and see how the agent responds. We'll also enable the trace to see the agent's thought process." 505 | ] 506 | }, 507 | { 508 | "cell_type": "code", 509 | "execution_count": null, 510 | "metadata": {}, 511 | "outputs": [], 512 | "source": [ 513 | "invoke(\"I nice biscuit would be great around now!\", True)" 514 | ] 515 | }, 516 | { 517 | "cell_type": "markdown", 518 | "metadata": {}, 519 | "source": [ 520 | "## Step 9: Cleaning Up\n", 521 | "\n", 522 | "We've had a great time chatting with our Bedrock Agent, but now it's time to clean up. Let's delete the agent and its associated resources." 523 | ] 524 | }, 525 | { 526 | "cell_type": "code", 527 | "execution_count": null, 528 | "metadata": {}, 529 | "outputs": [], 530 | "source": [ 531 | "response = bedrock_agent.delete_agent(\n", 532 | " agentId=agentId,\n", 533 | " skipResourceInUseCheck=True\n", 534 | ")\n", 535 | "\n", 536 | "response['agentStatus']" 537 | ] 538 | }, 539 | { 540 | "cell_type": "markdown", 541 | "metadata": {}, 542 | "source": [ 543 | "Finally, let's clean up the IAM role and policies we created for this demo." 544 | ] 545 | }, 546 | { 547 | "cell_type": "code", 548 | "execution_count": null, 549 | "metadata": {}, 550 | "outputs": [], 551 | "source": [ 552 | "inline_policies = iam.list_role_policies(RoleName=role_name)\n", 553 | "for policy_name in inline_policies.get('PolicyNames', []):\n", 554 | " iam.delete_role_policy(RoleName=role_name, PolicyName=policy_name)\n", 555 | " print(f\"Deleted inline policy: {policy_name}\")\n", 556 | "\n", 557 | "response = iam.delete_role(\n", 558 | " RoleName=role_name\n", 559 | ")\n", 560 | "\n", 561 | "print(f\"Deleted role.\")" 562 | ] 563 | }, 564 | { 565 | "cell_type": "markdown", 566 | "metadata": {}, 567 | "source": [ 568 | "## Conclusion\n", 569 | "\n", 570 | "And there you have it! We've successfully created a Bedrock Agent, given it some long-term memory, had a conversation with it, and then cleaned everything up. \n", 571 | "\n", 572 | "Through this process, we've seen how to:\n", 573 | "1. Set up the necessary AWS resources for a Bedrock Agent\n", 574 | "2. Create and configure an agent with long-term memory\n", 575 | "3. Interact with the agent and observe its responses\n", 576 | "4. Check what information the agent stores in its memory\n", 577 | "5. Start a new session and test the agent's recall\n", 578 | "6. Clean up all the resources when we're done\n", 579 | "\n", 580 | "This demo showcases the power of Bedrock Agents and how they can be used to create interactive, memory-enabled AI assistants. The possibilities for using this in various applications are endless!" 581 | ] 582 | } 583 | ], 584 | "metadata": { 585 | "kernelspec": { 586 | "display_name": "base", 587 | "language": "python", 588 | "name": "python3" 589 | }, 590 | "language_info": { 591 | "codemirror_mode": { 592 | "name": "ipython", 593 | "version": 3 594 | }, 595 | "file_extension": ".py", 596 | "mimetype": "text/x-python", 597 | "name": "python", 598 | "nbconvert_exporter": "python", 599 | "pygments_lexer": "ipython3", 600 | "version": "3.10.14" 601 | } 602 | }, 603 | "nbformat": 4, 604 | "nbformat_minor": 2 605 | } 606 | --------------------------------------------------------------------------------