diff --git a/01-tutorials/07-AgentCore-E2E/images/architecture_lab1_strands.png b/01-tutorials/07-AgentCore-E2E/images/architecture_lab1_strands.png index 61b7c091..fcc5c4f7 100644 Binary files a/01-tutorials/07-AgentCore-E2E/images/architecture_lab1_strands.png and b/01-tutorials/07-AgentCore-E2E/images/architecture_lab1_strands.png differ diff --git a/01-tutorials/07-AgentCore-E2E/images/architecture_lab2_memory.png b/01-tutorials/07-AgentCore-E2E/images/architecture_lab2_memory.png index 9d1991c3..10672cd6 100644 Binary files a/01-tutorials/07-AgentCore-E2E/images/architecture_lab2_memory.png and b/01-tutorials/07-AgentCore-E2E/images/architecture_lab2_memory.png differ diff --git a/01-tutorials/07-AgentCore-E2E/images/architecture_lab3_gateway.png b/01-tutorials/07-AgentCore-E2E/images/architecture_lab3_gateway.png index 92e8ab1b..b1470fd9 100644 Binary files a/01-tutorials/07-AgentCore-E2E/images/architecture_lab3_gateway.png and b/01-tutorials/07-AgentCore-E2E/images/architecture_lab3_gateway.png differ diff --git a/01-tutorials/07-AgentCore-E2E/images/architecture_lab4_runtime.png b/01-tutorials/07-AgentCore-E2E/images/architecture_lab4_runtime.png index 80cfaf1f..4fc77bfc 100644 Binary files a/01-tutorials/07-AgentCore-E2E/images/architecture_lab4_runtime.png and b/01-tutorials/07-AgentCore-E2E/images/architecture_lab4_runtime.png differ diff --git a/01-tutorials/07-AgentCore-E2E/images/architecture_lab5_streamlit.png b/01-tutorials/07-AgentCore-E2E/images/architecture_lab5_streamlit.png index ec6d8736..dd2edded 100644 Binary files a/01-tutorials/07-AgentCore-E2E/images/architecture_lab5_streamlit.png and b/01-tutorials/07-AgentCore-E2E/images/architecture_lab5_streamlit.png differ diff --git a/01-tutorials/07-AgentCore-E2E/lab-01-create-an-agent.ipynb b/01-tutorials/07-AgentCore-E2E/lab-01-create-an-agent.ipynb index 59152fe0..96cb18b8 100644 --- a/01-tutorials/07-AgentCore-E2E/lab-01-create-an-agent.ipynb +++ b/01-tutorials/07-AgentCore-E2E/lab-01-create-an-agent.ipynb @@ -23,6 +23,7 @@ "- **get_return_policy()** - Get return policy for specific products\n", "- **get_product_info()** - Get product information\n", "- **web_search()** - Search the web for troubleshooting help\n", + "- **get_technical_support()** - Search a Bedrock Knowledge Base\n", "\n", "\n", "### Architecture for Lab 1\n", @@ -80,7 +81,7 @@ "from ddgs import DDGS\n", "\n", "from strands.tools import tool\n", - "from scripts.utils import put_ssm_parameter" + "from lab_helpers.utils import put_ssm_parameter" ] }, { @@ -290,6 +291,176 @@ "print(\"✅ Web search tool ready\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Customer Support Agent - Knowledge Base Integration Steps\n", + "\n", + "##### Download product technical_support files from S3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "def download_files():\n", + " # Get account and region\n", + " account_id = boto3.client('sts').get_caller_identity()['Account']\n", + " region = boto3.Session().region_name\n", + " bucket_name = f\"{account_id}-{region}-kb-data-bucket\"\n", + " \n", + " # Create local folder\n", + " os.makedirs(\"knowledge_base_data\", exist_ok=True)\n", + " \n", + " # Download all files\n", + " s3 = boto3.client('s3')\n", + " objects = s3.list_objects_v2(Bucket=bucket_name)\n", + " \n", + " for obj in objects['Contents']:\n", + " file_name = obj['Key']\n", + " s3.download_file(bucket_name, file_name, f\"knowledge_base_data/{file_name}\")\n", + " print(f\"Downloaded: {file_name}\")\n", + " \n", + " print(f\"All files saved to: knowledge_base_data/\")\n", + "\n", + "# Run it\n", + "download_files()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Knowledge Base Sync Job\n", + "\n", + "##### Sync the knowledge base with product technical_support files from S3 which can be integrated with the agent" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import boto3\n", + "import time\n", + "\n", + "# Get parameters\n", + "ssm = boto3.client('ssm')\n", + "bedrock = boto3.client('bedrock-agent')\n", + "s3 = boto3.client('s3')\n", + "\n", + "account_id = boto3.client('sts').get_caller_identity()['Account']\n", + "region = boto3.Session().region_name\n", + "\n", + "kb_id = ssm.get_parameter(Name=f\"/{account_id}-{region}/kb/knowledge-base-id\")['Parameter']['Value']\n", + "ds_id = ssm.get_parameter(Name=f\"/{account_id}-{region}/kb/data-source-id\")['Parameter']['Value']\n", + "\n", + "# Get file names from S3 bucket\n", + "bucket_name = f\"{account_id}-{region}-kb-data-bucket\"\n", + "s3_objects = s3.list_objects_v2(Bucket=bucket_name)\n", + "file_names = [obj['Key'] for obj in s3_objects.get('Contents', [])]\n", + "\n", + "# Start sync job\n", + "response = bedrock.start_ingestion_job(\n", + " knowledgeBaseId=kb_id,\n", + " dataSourceId=ds_id,\n", + " description=\"Quick sync\"\n", + ")\n", + "\n", + "job_id = response['ingestionJob']['ingestionJobId']\n", + "print(\"Bedrock knowledge base sync job started, ingesting the data files from s3\")\n", + "\n", + "# Monitor until complete\n", + "while True:\n", + " job = bedrock.get_ingestion_job(\n", + " knowledgeBaseId=kb_id,\n", + " dataSourceId=ds_id,\n", + " ingestionJobId=job_id\n", + " )['ingestionJob']\n", + " \n", + " status = job['status']\n", + " \n", + " if status in ['COMPLETE', 'FAILED']:\n", + " break\n", + " \n", + " time.sleep(10)\n", + "\n", + "# Print final result\n", + "if status == 'COMPLETE':\n", + " file_count = job.get('statistics', {}).get('numberOfDocumentsScanned', 0)\n", + " files_list = ', '.join(file_names)\n", + " print(f\"Bedrock knowledge base sync job completed Successfully, ingested {file_count} files\")\n", + " print(f\"Files ingested: {files_list}\")\n", + "else:\n", + " print(f\"Bedrock knowledge base sync job failed with status: {status}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Tool 4: Get Technical Support\n", + "\n", + "**Purpose:** This tool provides customers with comprehensive technical support and troubleshooting assistance by accessing our knowledge base of electronics documentation. It includes detailed setup guides, maintenance instructions, troubleshooting steps, connectivity solutions, and warranty service information. This tool helps customers resolve technical issues, properly configure their devices, and understand maintenance requirements for optimal product performance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from strands.tools.mcp.mcp_client import MCPClient\n", + "from mcp.client.stdio import stdio_client\n", + "from mcp.client.stdio import StdioServerParameters\n", + "from strands.models import BedrockModel\n", + "from strands import Agent\n", + "from strands_tools import retrieve\n", + "\n", + "@tool\n", + "def get_technical_support(issue_description: str) -> str:\n", + "\ttry:\n", + "\t\t# Get KB ID from parameter store\n", + "\t\tssm = boto3.client('ssm')\n", + "\t\taccount_id = boto3.client('sts').get_caller_identity()['Account']\n", + "\t\tregion = boto3.Session().region_name\n", + "\n", + "\t\tkb_id = ssm.get_parameter(Name=f\"/{account_id}-{region}/kb/knowledge-base-id\")['Parameter']['Value']\n", + "\t\tprint(f\"Successfully retrieved KB ID: {kb_id}\")\n", + "\n", + "\t\t# Use strands retrieve tool\n", + "\t\ttool_use = {\n", + "\t\t\t\"toolUseId\": \"tech_support_query\",\n", + "\t\t\t\"input\": {\n", + "\t\t\t\t\"text\": issue_description,\n", + "\t\t\t\t\"knowledgeBaseId\": kb_id,\n", + "\t\t\t\t\"region\": region,\n", + "\t\t\t\t\"numberOfResults\": 3,\n", + "\t\t\t\t\"score\": 0.4\n", + "\t\t\t}\n", + "\t\t}\n", + "\n", + "\t\tresult = retrieve.retrieve(tool_use)\n", + "\n", + "\t\tif result[\"status\"] == \"success\":\n", + "\t\t\treturn result[\"content\"][0][\"text\"]\n", + "\t\telse:\n", + "\t\t\treturn f\"Unable to access technical support documentation. Error: {result['content'][0]['text']}\"\n", + "\n", + "\texcept Exception as e:\n", + "\t\tprint(f\"Detailed error in get_technical_support: {str(e)}\")\n", + "\t\treturn f\"Unable to access technical support documentation. Error: {str(e)}\"\n", + "\n", + "print(\"✅ Technical support tool ready\")" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -311,7 +482,7 @@ "SYSTEM_PROMPT = \"\"\"You are a helpful and professional customer support assistant for an electronics e-commerce company.\n", "Your role is to:\n", "- Provide accurate information using the tools available to you\n", - "- Support the customer with technical information and product specifications.\n", + "- Support the customer with technical information and product specifications, and maintenance questions\n", "- Be friendly, patient, and understanding with customers\n", "- Always offer additional help after answering questions\n", "- If you can't help with something, direct customers to the appropriate contact\n", @@ -320,6 +491,9 @@ "1. get_return_policy() - For warranty and return policy questions\n", "2. get_product_info() - To get information about a specific product\n", "3. web_search() - To access current technical documentation, or for updated information. \n", + "4. get_technical_support() - For troubleshooting issues, setup guides, maintenance tips, and detailed technical assistance\n", + "For any technical problems, setup questions, or maintenance concerns, always use the get_technical_support() tool as it contains our comprehensive technical documentation and step-by-step guides.\n", + "\n", "Always use the appropriate tool to get accurate, up-to-date information rather than making assumptions about electronic products or specifications.\"\"\"\n", "\n", "# Initialize the Bedrock model (Anthropic Claude 3.7 Sonnet)\n", @@ -335,7 +509,8 @@ " tools=[\n", " get_product_info, # Tool 1: Simple product information lookup\n", " get_return_policy, # Tool 2: Simple return policy lookup\n", - " web_search # Tool 3: Access the web for updated information\n", + " web_search, # Tool 3: Access the web for updated information\n", + " get_technical_support # Tool 4: Technical support & troubleshooting\n", " ],\n", " system_prompt=SYSTEM_PROMPT,\n", ")\n", @@ -363,6 +538,15 @@ "response = agent(\"What's the return policy for my thinkpad X1 Carbon?\")" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response = agent(\"My laptop won't turn on, what should I check?\")" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/01-tutorials/07-AgentCore-E2E/lab-02-agentcore-memory.ipynb b/01-tutorials/07-AgentCore-E2E/lab-02-agentcore-memory.ipynb index 2a1b4dbc..64bba217 100644 --- a/01-tutorials/07-AgentCore-E2E/lab-02-agentcore-memory.ipynb +++ b/01-tutorials/07-AgentCore-E2E/lab-02-agentcore-memory.ipynb @@ -45,7 +45,25 @@ "* **Python 3.10+** installed locally\n", "* **AWS CLI configured** with credentials\n", "* **Anthropic Claude 3.7** enabled on [Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html)\n", - "* **Strands Agents** and other libraries installed in the next cells" + "* **Strands Agents** and other libraries installed in the next cells\n", + "* These resources are created for you within an AWS workshop account\n", + " - AWS Lambda function \n", + " - AWS Lambda Execution IAM Role\n", + " - AgentCore Gateway IAM Role\n", + " - DynamoDB tables used by the AWS Lambda function. \n", + " - Cognito User Pool and User Pool Client\n", + "#### Not using an AWS workshop account? \n", + "\n", + "**Note:** If you are running this as a self-paced lab you must run create the cloudformation resources as shown in the workshop self-paced steps. If you have not, then uncomment and run the below code segment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#!bash scripts/prereq.sh" ] }, { @@ -482,7 +500,7 @@ "from lab_helpers.lab1_strands_agent import (\n", " SYSTEM_PROMPT,\n", " get_return_policy, web_search,\n", - " get_product_info, MODEL_ID\n", + " get_product_info, get_technical_support, MODEL_ID\n", ")\n", "\n", "SESSION_ID = str(uuid.uuid4())\n", @@ -503,6 +521,7 @@ " get_product_info, # Tool 1: Simple product information lookup\n", " get_return_policy, # Tool 2: Simple return policy lookup\n", " web_search,\n", + " get_technical_support\n", " ],\n", " system_prompt=SYSTEM_PROMPT\n", ")" diff --git a/01-tutorials/07-AgentCore-E2E/lab-03-agentcore-gateway.ipynb b/01-tutorials/07-AgentCore-E2E/lab-03-agentcore-gateway.ipynb index 74abb2dc..73dec415 100644 --- a/01-tutorials/07-AgentCore-E2E/lab-03-agentcore-gateway.ipynb +++ b/01-tutorials/07-AgentCore-E2E/lab-03-agentcore-gateway.ipynb @@ -60,7 +60,7 @@ " \n", "\n", "\n", - "*Web search tool is now centralized in AgentCore Gateway with secure identity-based access control. Multiple agents and use cases can share the same tool securely. We will also reuse the `check_warranty()` and `get_customer_profile()` tools built for other applications. `get_return_policy()` and `get_product_info()` remain as local tools as they are specific to the customer support use case* \n", + "*Web search tool is now centralized in AgentCore Gateway with secure identity-based access control. Multiple agents and use cases can share the same tool securely. We will also reuse the `check_warranty()` tool built for other applications and add the `web_search()` tool for use within other applications. `get_product_info()`, `get_return_policy()`, and `get_technical_support` remain as local tools as they are specific to the customer support use case*\n", "\n", "### Key Features\n", "- **Seamlessly integrate AWS Lambda functions:** This example shows how to integrate your Agent with existing AWS Lambda functions to check the warranty of an item and to get the customer profile using Amazon Bedrock AgentCore Gateway.\n", @@ -78,20 +78,7 @@ " - AWS Lambda Execution IAM Role\n", " - AgentCore Gateway IAM Role\n", " - DynamoDB tables used by the AWS Lambda function. \n", - " - Cognito User Pool and User Pool Client\n", - "#### Not using an AWS workshop account? \n", - "\n", - "**Note:** If you are running this as a self-paced lab you must run create the cloudformation resources as shown in the workshop self-paced steps. If you have not, then uncomment and run the below code segment" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "3dc894f0-8014-4451-8e4d-0cad8dd1b486", - "metadata": {}, - "outputs": [], - "source": [ - "#!bash scripts/prereq.sh" + " - Cognito User Pool and User Pool Client" ] }, { @@ -495,7 +482,7 @@ "metadata": {}, "outputs": [], "source": [ - "from lab_helpers.lab1_strands_agent import get_product_info, get_return_policy, SYSTEM_PROMPT\n", + "from lab_helpers.lab1_strands_agent import get_product_info, get_return_policy, get_technical_support, SYSTEM_PROMPT\n", "from lab_helpers.lab2_memory import CustomerSupportMemoryHooks,create_or_get_memory_resource \n", "import uuid\n", "from bedrock_agentcore.memory import MemoryClient\n", @@ -524,6 +511,7 @@ " [\n", " get_product_info,\n", " get_return_policy,\n", + " get_technical_support\n", " ]\n", " + mcp_client.list_tools_sync()\n", " )\n", @@ -561,6 +549,7 @@ "test_prompts = [\n", " # Warranty Checks\n", " \"List all of your tools\",\n", + " \"I bought an iphone 14 last month. I don't like it because it heats up. How do I solve it?\",\n", " \"I have a Gaming Console Pro device , I want to check my warranty status, warranty serial number is MNO33333333.\",\n", " \"What are the warranty support guidelines?\",\n", " \"How can I fix Lenovo Thinkpad with a blue screen\",\n", diff --git a/01-tutorials/07-AgentCore-E2E/lab-04-agentcore-runtime.ipynb b/01-tutorials/07-AgentCore-E2E/lab-04-agentcore-runtime.ipynb index b6331825..15fa7ca5 100644 --- a/01-tutorials/07-AgentCore-E2E/lab-04-agentcore-runtime.ipynb +++ b/01-tutorials/07-AgentCore-E2E/lab-04-agentcore-runtime.ipynb @@ -131,6 +131,7 @@ "from lab_helpers.lab1_strands_agent import (\n", " get_return_policy,\n", " get_product_info,\n", + " get_technical_support,\n", " SYSTEM_PROMPT,\n", " MODEL_ID,\n", ")\n", @@ -154,7 +155,7 @@ "# Create the agent with all customer support tools\n", "agent = Agent(\n", " model=model,\n", - " tools=[get_return_policy, get_product_info],\n", + " tools=[get_return_policy, get_product_info, get_technical_support],\n", " system_prompt=SYSTEM_PROMPT,\n", " hooks=[memory_hooks],\n", ")\n", diff --git a/01-tutorials/07-AgentCore-E2E/lab-05-frontend.ipynb b/01-tutorials/07-AgentCore-E2E/lab-05-frontend.ipynb index 4c86ca9a..900898a8 100644 --- a/01-tutorials/07-AgentCore-E2E/lab-05-frontend.ipynb +++ b/01-tutorials/07-AgentCore-E2E/lab-05-frontend.ipynb @@ -270,7 +270,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.9" + "version": "3.11.11" } }, "nbformat": 4, diff --git a/01-tutorials/07-AgentCore-E2E/lab_helpers/lab1_strands_agent.py b/01-tutorials/07-AgentCore-E2E/lab_helpers/lab1_strands_agent.py index 77c5e660..baa01ea6 100644 --- a/01-tutorials/07-AgentCore-E2E/lab_helpers/lab1_strands_agent.py +++ b/01-tutorials/07-AgentCore-E2E/lab_helpers/lab1_strands_agent.py @@ -1,6 +1,8 @@ from strands.tools import tool from ddgs.exceptions import DDGSException, RatelimitException from ddgs import DDGS +from strands_tools import retrieve +import boto3 MODEL_ID = "us.anthropic.claude-3-7-sonnet-20250219-v1:0" @@ -152,4 +154,38 @@ def get_product_info(product_type: str) -> str: f"• Specifications: {product['specs']}\n" \ f"• Key Features: {product['features']}\n" \ f"• Compatibility: {product['compatibility']}\n" \ - f"• Support: {product['support']}" \ No newline at end of file + f"• Support: {product['support']}" + +@tool +def get_technical_support(issue_description: str) -> str: + try: + # Get KB ID from parameter store + ssm = boto3.client('ssm') + account_id = boto3.client('sts').get_caller_identity()['Account'] + region = boto3.Session().region_name + + kb_id = ssm.get_parameter(Name=f"/{account_id}-{region}/kb/knowledge-base-id")['Parameter']['Value'] + print(f"Successfully retrieved KB ID: {kb_id}") + + # Use strands retrieve tool + tool_use = { + "toolUseId": "tech_support_query", + "input": { + "text": issue_description, + "knowledgeBaseId": kb_id, + "region": region, + "numberOfResults": 3, + "score": 0.4 + } + } + + result = retrieve.retrieve(tool_use) + + if result["status"] == "success": + return result["content"][0]["text"] + else: + return f"Unable to access technical support documentation. Error: {result['content'][0]['text']}" + + except Exception as e: + print(f"Detailed error in get_technical_support: {str(e)}") + return f"Unable to access technical support documentation. Error: {str(e)}" \ No newline at end of file diff --git a/01-tutorials/07-AgentCore-E2E/lab_helpers/lab4_runtime.py b/01-tutorials/07-AgentCore-E2E/lab_helpers/lab4_runtime.py index fbee6d85..07a1002c 100644 --- a/01-tutorials/07-AgentCore-E2E/lab_helpers/lab4_runtime.py +++ b/01-tutorials/07-AgentCore-E2E/lab_helpers/lab4_runtime.py @@ -7,6 +7,7 @@ from lab_helpers.lab1_strands_agent import ( get_return_policy, get_product_info, + get_technical_support, SYSTEM_PROMPT, MODEL_ID, ) @@ -30,7 +31,7 @@ # Create the agent with all customer support tools agent = Agent( model=model, - tools=[get_return_policy, get_product_info], + tools=[get_return_policy, get_product_info, get_technical_support], system_prompt=SYSTEM_PROMPT, hooks=[memory_hooks], )