I-Amazon Bedrock Agents iinkonzo ze-smart ye-infrastructure yakho ye-AWS - zinokufundisa, ukhethe into elandelayo kunye nokukhuthaza imisebenzi usebenzisa i-Lambda function. Kule nqaku, ndiya kubonisa njani i-Supervisor Agent eyenza i-AWS Lambdas ezininzi ukuze: List EC2 instances, Fetch their CPU metrics from CloudWatch, Combine both results intelligently — all without the agent ever calling AWS APIs directly. By the end, you’ll understand how Bedrock Agents work, how to use action groups, and how to chain Lambdas through a supervisor function — a clean, scalable pattern for multi-step automation. Sishayele kwi-diagram kunye nezinye iingxelo yokuba i-agent, ukuze ufumane kunye nokunxibelelana kakuhle: Umdlali uqhagamshelane ne-Agent ye-Bedrock (1) kunye nemisebenzi, umzekelo, "ngaba uninzi le-TV emangalisayo?" I-Agent uyazi ngexesha elidlulileyo ukuba ukuba umxholo uqhagamshelane ne-check-stock status, kufuneka uqhagamshelane (2) kwi-action group ye-"database" (3, AG). Kwi-database AG, sisebenzisa i-lambda function (4), kwaye le lambda uqhagamshelane ne-status kwi-DynamoDB table (5), ufumane isibhozo (6,7) kwaye uqhagamshelane isibhozo kwi-user (8). Nceda siphinde enye isibonelo: Wonke i-agent ingaba iindidi ezininzi zokusebenza, umzekelo, siya ufuna ukufumana ulwazi malunga neengxaki ze-AWS, njenge-listing zonke iingxaki ze-ECS, i-logic yinto efanayo kunye neengxaki ezidlulileyo. Ukucacisa i-agent e-AG ukuba uqhagamshele - kufuneka usebenzisa i-prompt. Kwakhona umzekelo: I-AG ye-EKS yeengxaki zokusebenza ezininzi. Njengoko ufumana apha, ngamnye iengxaki ingaba i-lambda engaphezulu kweengxaki. Kule isibonelo, iingxaki zihlanganisa kunye nokunciphisa izixeko ezininzi zeengxaki ze-K8S ezikhoyo. I-action group kunye ne-lambda function ingaba nayiphi na umsebenzi, nangona ufuna ukufumana idatha kwi-API ye-third-party ukufumana idatha ye-weather okanye i-flight ticket availability. Ndingathanda ukuba i-clarity yinto elula ngoku, kwaye siyafumane kwi-supervisor agent setup yethu: Kwi-Console ye-AWS, ufake i-Bedrock → Agents → Yenza i-agent Yenza i-imeyile kwaye Yenza Emva kokufumana, unako ukuguqulwa imodeli ukuba ufuna okanye ukugcina Claude ngokufanelekileyo. Ndicinga Nova Premier 1.0 Ukongeza umzekelo kunye neengxelo ye-Agent. Iqela le-action siya kuvelisa ngexesha elandelayo Ngaba unomdla we-AWS Supervisor. Indawo: Ukuncedisa i-infrastructure ye-AWS. Iingxowa zokusebenza: ec2: list_instances → ivumela i-instance list + instanceIds Ukucaciswa: Uya kuthetha kwi-AWS APIs ngqo. For EC2: Call ec2__list_instances Ukusetyenziswa njalo kwi-"Thinking" ngaphambi kokusebenza. Ngaba unomdla we-AWS Supervisor. Indawo: Ukuncedisa i-infrastructure ye-AWS. Iingxowa zokusebenza: ec2: list_instances → ivumela i-instance list + instanceIds Ukucaciswa: Uya kuthetha kwi-AWS APIs ngqo. For EC2: Call ec2__list_instances Ukusetyenziswa njalo kwi-"Thinking" ngaphambi kokusebenza. Ukucinga: ec2 - i-action group igama list_instances - i-function name, njengoko ngexesha elandelayo - ungenza i-functions ezininzi ngalinye iqela le-action Nqakraza kwi "Save" Kwaye i- "Prepare" ibhotile kwi-top. I-Prepare iya kuba ifumaneka xa uxhaswa. Shiya phantsi kwi-actions group → Add Igama - EC2. Group Action. invocation - ukuvelisa isicelo esitsha lambda, apho kufuneka yintoni efanayo njengoko sisaziwe kwizicelo ze-agent list_instances Ukongeza igama kunye ne-description yeqela le-action, nqakraza Create kwaye kwakhona "Save" kunye "Prepare". Ngena kwi-function yakho ye-lambda, i-Bedrock yenza i-function kunye ne-EC2 ye-prefix kwi-imeyili kunye nokongeza ikhowudi elandelayo: import logging from typing import Dict, Any from http import HTTPStatus import boto3 logger = logging.getLogger() logger.setLevel(logging.INFO) ec2_client = boto3.client('ec2') def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]: """ AWS Lambda handler for processing Bedrock agent requests related to EC2 instances. Supports: - Listing all EC2 instances - Describing a specific instance by ID """ try: action_group = event['actionGroup'] function = event['function'] message_version = event.get('messageVersion', 1) parameters = event.get('parameters', []) response_text = "" if function == "list_instances": # List all EC2 instances instances = ec2_client.describe_instances() instance_list = [] for reservation in instances['Reservations']: for instance in reservation['Instances']: instance_list.append({ 'InstanceId': instance.get('InstanceId'), 'State': instance.get('State', {}).get('Name'), 'InstanceType': instance.get('InstanceType'), 'PrivateIpAddress': instance.get('PrivateIpAddress', 'N/A'), 'PublicIpAddress': instance.get('PublicIpAddress', 'N/A') }) response_text = f"Found {len(instance_list)} EC2 instance(s): {instance_list}" elif function == "describe_instance": # Expect a parameter with the instance ID instance_id_param = next((p for p in parameters if p['name'] == 'instanceId'), None) if not instance_id_param: raise KeyError("Missing required parameter: instanceId") instance_id = instance_id_param['value'] result = ec2_client.describe_instances(InstanceIds=[instance_id]) instance = result['Reservations'][0]['Instances'][0] response_text = ( f"Instance {instance_id} details: " f"State={instance['State']['Name']}, " f"Type={instance['InstanceType']}, " f"Private IP={instance.get('PrivateIpAddress', 'N/A')}, " f"Public IP={instance.get('PublicIpAddress', 'N/A')}" ) else: response_text = f"Unknown function '{function}' requested." # Format Bedrock agent response response_body = { 'TEXT': { 'body': response_text } } action_response = { 'actionGroup': action_group, 'function': function, 'functionResponse': { 'responseBody': response_body } } response = { 'response': action_response, 'messageVersion': message_version } logger.info('Response: %s', response) return response except KeyError as e: logger.error('Missing required field: %s', str(e)) return { 'statusCode': HTTPStatus.BAD_REQUEST, 'body': f'Error: {str(e)}' } except Exception as e: logger.error('Unexpected error: %s', str(e)) return { 'statusCode': HTTPStatus.INTERNAL_SERVER_ERROR, 'body': f'Internal server error: {str(e)}' } Qaphela: Ukusabela umsebenzi kufuneka kwi-Bedrock-specific format, iinkcukacha ziyafumaneka kwi-documentation: https://docs.aws.amazon.com/bedrock/latest/userguide/agents-lambda.html Emva kokuba uhlaziywa ikhowudi yakho ye-function - ufike kwi-Configuration → permissions → role name ukwenza i-inline policy entsha: Njengoko JSON: { "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Action": [ "ec2:DescribeInstances" ], "Resource": [ "*" ] } ] } Ngoku kunokufika kwi-agent yethu kwaye nqakraza "Test", ubeka i-text ukuze zibonise ukuba isebenza ngokwenene: Cool! Iqela leqela leqela lokuqala isebenza njenge-anticipated, ukongeza iqela elinye leqela ukuyifaka i-cloudwatch: Igama le-action group - i-cloudwatch Igama le-function yi-getMetrics, ukongezela isifundo kunye neengxaki, njengoko le lambda kufuneka uyazi i-instance okanye i-intances ukuyifaka i-metric ye-Lambda. Ukuhlaziywa kwe-agent yokubonisa indlela yokusebenzisa i-action group entsha, kwaye nqakraza "Save" kunye ne-"Prepare" kwakhona Ngaba unomdla we-AWS Supervisor. Indawo: Ukuncedisa i-infrastructure ye-AWS. Iingxowa zokusebenza: ec2: describeInstances → ivumela umxokozelo umxokozelo + instanceIds i-cloudwatch: getMetrics → iimfuno ye-instance_ids Ukucaciswa: Never call AWS APIs directly. For EC2 + CPU: Call ec2__describeInstances Extract instanceIds Call cloudwatch__getMetrics Ukudibanisa imiphumela. Ukusetyenziswa njalo kwi-"Thinking" ngaphambi kokusebenza. Ngaba unomdla we-AWS Supervisor. Indawo: Ukuncedisa i-infrastructure ye-AWS. Iingxowa zokusebenza: ec2: describeInstances → ivumela umxokozelo umxokozelo + instanceIds i-cloudwatch: getMetrics → iimfuno ye-instance_ids Ukucaciswa: Uya kuthetha kwi-AWS APIs ngqo. For EC2 + CPU: Call ec2__describeInstances Extract instanceIds Call cloudwatch__getMetrics Ukudibanisa imiphumela. Ukusetyenziswa njalo kwi-"Thinking" ngaphambi kokusebenza. Ngaba ufake ikhowudi yethu ye-cloudwatch: import boto3 import datetime import logging import json from typing import Dict, Any from http import HTTPStatus logger = logging.getLogger() logger.setLevel(logging.INFO) def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]: try: action_group = event["actionGroup"] function = event["function"] message_version = event.get("messageVersion", 1) parameters = event.get("parameters", []) region = "us-east-1" instance_ids = [] # --- Parse parameters --- for param in parameters: if param.get("name") == "region": region = param.get("value") elif param.get("name") == "instance_ids": raw_value = param.get("value") if isinstance(raw_value, str): # Clean up stringified list from Bedrock agent raw_value = raw_value.strip().replace("[", "").replace("]", "").replace("'", "") instance_ids = [x.strip() for x in raw_value.split(",") if x.strip()] elif isinstance(raw_value, list): instance_ids = raw_value logger.info(f"Parsed instance IDs: {instance_ids}") if not instance_ids: response_text = f"No instance IDs provided for CloudWatch metrics in {region}." else: cloudwatch = boto3.client("cloudwatch", region_name=region) now = datetime.datetime.utcnow() start_time = now - datetime.timedelta(hours=1) metrics_output = [] for instance_id in instance_ids: try: metric = cloudwatch.get_metric_statistics( Namespace="AWS/EC2", MetricName="CPUUtilization", Dimensions=[{"Name": "InstanceId", "Value": instance_id}], StartTime=start_time, EndTime=now, Period=300, Statistics=["Average"] ) datapoints = metric.get("Datapoints", []) if datapoints: datapoints.sort(key=lambda x: x["Timestamp"]) avg_cpu = round(datapoints[-1]["Average"], 2) metrics_output.append(f"{instance_id}: {avg_cpu}% CPU (avg last hour)") else: metrics_output.append(f"{instance_id}: No recent CPU data") except Exception as e: logger.error(f"Error fetching metrics for {instance_id}: {e}") metrics_output.append(f"{instance_id}: Error fetching metrics") response_text = ( f"CPU Utilization (last hour) in {region}:\n" + "\n".join(metrics_output) ) # --- Bedrock Agent response format --- response_body = { "TEXT": { "body": response_text } } action_response = { "actionGroup": action_group, "function": function, "functionResponse": { "responseBody": response_body } } response = { "response": action_response, "messageVersion": message_version } logger.info("Response: %s", response) return response except Exception as e: logger.error(f"Unexpected error: {e}") return { "statusCode": HTTPStatus.INTERNAL_SERVER_ERROR, "body": f"Internal server error: {str(e)}" } Kwaye ukuguqula iingcebiso ze-cloudwatch ze-lambda efana ne-ec2 lambda: { "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Action": [ "cloudwatch:GetMetricStatistics" ], "Resource": [ "*" ] } ] } Ukubuyekeza kwakhona Thina i-EC2 kunye ne-CloudWatch action groups, kwaye ziya kubhalwe kwi-agent ukuze ufumane i-instances ye-EC2 kunye ne-CPU ye-metric zayo. Ngoku, siza ukongezelela i-Supervisor yokwenza le nkqubo emangalisayo kunye ne-efficient. Kwimeko ye-agent yokufaka i-EC2 kunye ne-CloudWatch ngokufanelekileyo, i-Supervisor ithatha i-logic yayo. Okokuqala ithetha i-EC2 yokufaka zonke iingxaki, ke i-ID yeengxaki zithunyelwe kwi-CloudWatch yokufaka ama-metric, kwaye ekugqibeleni iye yenza yonke into efanayo. Ngokwenza oku, umlawuli kufuneka uqhagamshelane nje umsebenzi - umlawuli - kwaye umlawuli uqhagamshelane zonke iingxaki kwi-background. I-Clean, i-Faster, kunye ne-Maintenance elula. Yenza igama kunye ne-description Faka igama le function kunye ne-description Kwakhona ukuguqulwa izicelo ze-agent ukuze ukunceda ukuhanjiswa ngqo kwi-ec2 kunye ne-CloudWatch action groups: Nqakraza “Save” kunye “Prepare”. Ukuhlaziywa kwe-supervisor lambda function code, NOTE: need to update your EC2 and Cloudwatch functions name in the code below: import boto3 import json import logging import re import ast logger = logging.getLogger() logger.setLevel(logging.INFO) lambda_client = boto3.client("lambda") def lambda_handler(event, context): try: action_group = event["actionGroup"] function = event["function"] parameters = event.get("parameters", []) message_version = event.get("messageVersion", "1.0") # Parse parameters region = "us-east-1" for param in parameters: if param.get("name") == "region": region = param.get("value") # Decide routing if function == "analyzeInfrastructure": logger.info("Supervisor: calling EC2 and CloudWatch") # Step 1: call EC2 Lambda ec2_payload = { "actionGroup": "ec2", "function": "list_instances", "parameters": [{"name": "region", "value": region}], "messageVersion": "1.0" } ec2_response = invoke_lambda("ec2-yeikw", ec2_payload) #### CHANGE TO YOUR EC2 FUNCTION NAME instances = extract_instance_ids(ec2_response) # Step 2: call CloudWatch Lambda (if instances found) if instances: cw_payload = { "actionGroup": "cloudwatch", "function": "getMetrics", "parameters": [ {"name": "region", "value": region}, {"name": "instance_ids", "value": instances} ], "messageVersion": "1.0" } cw_response = invoke_lambda("cloudwatch-ef6ty", cw_payload) #### CHANGE TO YOUR CLOUDWATCH FUNCTION NAME final_text = merge_responses(ec2_response, cw_response) else: final_text = "No instances found to analyze." else: final_text = f"Unknown function: {function}" # Construct Bedrock-style response response = { "messageVersion": message_version, "response": { "actionGroup": action_group, "function": function, "functionResponse": { "responseBody": { "TEXT": {"body": final_text} } } } } logger.info("Supervisor response: %s", response) return response except Exception as e: logger.exception("Error in supervisor") return { "statusCode": 500, "body": f"Supervisor error: {str(e)}" } def invoke_lambda(name, payload): """Helper to call another Lambda and parse response""" response = lambda_client.invoke( FunctionName=name, InvocationType="RequestResponse", Payload=json.dumps(payload), ) result = json.loads(response["Payload"].read()) return result def extract_instance_ids(ec2_response): """Extract instance IDs from EC2 Lambda response""" try: body = ec2_response["response"]["functionResponse"]["responseBody"]["TEXT"]["body"] # Try to extract JSON-like data after "Found X EC2 instance(s):" if "Found" in body and "[" in body and "]" in body: data_part = body.split(":", 1)[1].strip() try: instances = ast.literal_eval(data_part) # safely parse the list return [i["InstanceId"] for i in instances if "InstanceId" in i] except Exception: pass # fallback regex in case of plain text return re.findall(r"i-[0-9a-f]+", body) except Exception as e: logger.error("extract_instance_ids error: %s", e) return [] def merge_responses(ec2_resp, cw_resp): """Combine EC2 and CloudWatch outputs""" ec2_text = ec2_resp["response"]["functionResponse"]["responseBody"]["TEXT"]["body"] cw_text = cw_resp["response"]["functionResponse"]["responseBody"]["TEXT"]["body"] return f"{ec2_text}\n\n{cw_text}" Kwakhona, ukongeza izicelo ze-supervisor lambda ukufumana iinkqubo zethu ze-EC2 kunye ne-Cloudwatch, umzekelo: { "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "lambda:InvokeFunction", "Resource": [ "arn:aws:lambda:us-east-1:<account_id>:function:ec2-<id>", "arn:aws:lambda:us-east-1:<account_id>:function:cloudwatch-<id>" ] } ] } Lets ukuhlola umsebenzi kwakhona, kwaye ngokucacileyo ibonakali Ndicinga i-superusor supervisor i-function logs yaye ndingathanda oku Enye kuziwa ukuba akubonisa akukho nto elithakazelisayo, kodwa akukho - i-hint 3000.00ms. i-default lambda function timeout, ivumela ukucacisa. Go to supervisor function - configuration - general and edit Timeout parameter , Ndicala kwi-10 iiveki Ndiya kukunceda! Uyakwazi ukuvelisa oku kwimfuneko ngokongeza i-AWS Billing Analysis ukufumana iimveliso ezininzi ezininzi okanye ezininzi , njl. yaye ungenza ukuba ungenza kuphela iimveliso ze-AWS. Nceda uqhagamshelane ukuba ungenza iimveliso ze-external. iindidi ezininzi ze-ec2 eziqhutywa