Contents
Hello everyone. This is my first post. I work as a system integrator in Japan. My work involves system architecture using services like Bedrock and serverless. I plan to continue posting here regularly, so please stay tuned. Thank you.
Original Japanese Version is here.
https://qiita.com/moritalous/items/f828c5d7d2d116884f9a
There is a feature called Agents for Amazon Bedrock that allows you to build agents on Amazon Bedrock. This feature is built on Lambda, but requires the following:
- A Lambda function containing the business logic for the actions the agent will execute
- An OpenAPI schema containing the API description, structure, and parameters
Additionally, since the event JSON is in a dedicated format, you need to be mindful of what kind of events will arrive while developing.
AWS’s AWS Lambda Web Adapter now supports Agents for Amazon Bedrock, so we’ll introduce how to use it.
What is AWS Lambda Web Adapter?
It’s a tool for running web applications on AWS Lambda.
With AWS Lambda Web Adaptor, developers can build web apps (HTTP APIs) using their familiar frameworks (Express.js, Next.js, Flask, SpringBoot, ASP.NET, Laravel, etc., anything that uses HTTP 1.1/1.0) and run them on AWS Lambda. You can also run the same Docker image on AWS Lambda, Amazon EC2, AWS Fargate, and your local computer.
https://github.com/awslabs/aws-lambda-web-adapter
Here’s an image showing the configuration (from the official site):
Until now, only HTTP events from API Gateway or ALB were supported, but Non-HTTP Events have now been supported!
Here’s an image for Non-HTTP events:
Non-HTTP events such as SNS or SQS can now be received. The event type is automatically identified, with HTTP events forwarded to their respective path, and Non-HTTP events forwarded to /events
(which can be changed).
For Agents for Amazon Bedrock, the following JSON will be sent to /events
. If the JSON received at /events
can be parsed and routed to the desired path, it will work as intended.
Reference: Lambda input event from Amazon Bedrock
{
"messageVersion": "1.0",
"agent": {
"name": "string",
"id": "string",
"alias": "string",
"version": "string"
},
"inputText": "string",
"sessionId": "string",
"actionGroup": "string",
"apiPath": "string",
"httpMethod": "string",
"parameters": [
{
"name": "string",
"type": "string",
"value": "string"
},
...
],
"requestBody": {
"content": {
"<content_type>": {
"properties": [
{
"name": "string",
"type": "string",
"value": "string"
},
...
]
}
}
},
"sessionAttributes": {
"string": "string",
},
"promptSessionAttributes": {
"string": "string"
}
}
The routing process is common, so I’ve published a library using FastAPI’s Middleware mechanism.
With this library, you can develop APIs with FastAPI without worrying about /events
.
https://github.com/moritalous/lwa-fastapi-middleware-bedrock-agent
Note
I requested support for Agents for Amazon Bedrock for Lambda Web Adapter, which led to its implementation. I was also asked to create a sample and a general library.
I hope support Agents for Amazon Bedrock #317
It was a very valuable experience.
Sample App Explanation
Here’s a sample app using this configuration:
-
Directory structure
bedrock-agent-fastapi โโโ README.md โโโ app โ โโโ Dockerfile โ โโโ __init__.py โ โโโ main.py โ โโโ requirements.txt โโโ events โ โโโ s3_bucket_count.json โ โโโ s3_object.json โ โโโ s3_object_count.json โโโ template.yaml
-
Libraries used
Main Python application libraries used:
-
Integrating Lambda Web Adapter
The deployment type for Lambda is containers. In the Dockerfile’s second line, we copy the contents of Lambda Web Adapter. This single line is the minimum required to use Lambda Web Adapter.
FROM public.ecr.aws/docker/library/python:3.12.0-slim COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.1 /lambda-adapter /opt/extensions/lambda-adapter ENV PORT=8000 AWS_LWA_READINESS_CHECK_PROTOCOL=tcp WORKDIR /var/task COPY requirements.txt ./ RUN python -m pip install -r requirements.txt COPY *.py ./ CMD exec uvicorn --port=$PORT main:app
-
FastAPI API Development
The program code is only in
main.py
. Except for specifying the Middleware, it’s the same as a general FastAPI application.This sample includes the following APIs:
Path Method Description /s3_bucket_count GET Returns the number of S3 buckets /s3_object_count GET Returns the number of objects in the specified S3 bucket /s3_object GET Returns the last modified date of the specified S3 bucket and object key import datetime import logging import boto3 from fastapi import FastAPI, Query from pydantic import BaseModel, Field from bedrock_agent.middleware import BedrockAgentMiddleware app = FastAPI( description="This agent allows you to query the S3 information in your AWS account.", ) app.openapi_version = "3.0.2" app.add_middleware(BedrockAgentMiddleware) middleware_logger = logging.getLogger("bedrockagent-middleware") middleware_logger.setLevel(level=logging.DEBUG) s3 = boto3.resource("s3") class S3BucketCountResponse(BaseModel): count: int = Field(description="the number of S3 buckets") @app.get("/s3_bucket_count") async def get_s3_bucket_count() -> S3BucketCountResponse: """ This method returns the number of S3 buckets in your AWS account. Return: S3BucketCountResponse: A json object containing the number of S3 buckets in your AWS account. """ count = len(list(s3.buckets.all())) return S3BucketCountResponse(count=count) class S3ObjectCountResponse(BaseModel): count: int = Field(description="the number of S3 objects") @app.get("/s3_object_count") async def get_s3_object_count( bucket_name: str = Query(description="Bucket name"), ) -> S3ObjectCountResponse: """ This method returns the number of S3 objects in your specified bucket. Return: S3ObjectCountResponse: A json object containing the number of S3 objects in your specified bucket. """ count = len(list(s3.Bucket(bucket_name).objects.all())) return S3ObjectCountResponse(count=count) class S3GetObjectRequest(BaseModel): bucket_name: str = Field(description="Bucket name") object_key: str = Field(description="Object key") class S3GetObjectResponse(BaseModel): last_modified: datetime.datetime = Field(description="the last modified date") @app.post("/s3_object") async def get_s3_object(request: S3GetObjectRequest): """ This method returns the last modified date of S3 object. Return: S3GetObjectResponse: A json object containing the last modified date of S3 objects. """ object = s3.Object(request.bucket_name, request.object_key) last_modified = object.get()["LastModified"] return S3GetObjectResponse(last_modified=last_modified)
The Middleware specification is in this part. This single specification routes events received at
/events
appropriately.from bedrock_agent.middleware import BedrockAgentMiddleware app.add_middleware(BedrockAgentMiddleware)
-
Running FastAPI Locally
Install library
pip install fastapi uvicorn pydantic==1.10.13 lwa-fastapi-middleware-bedrock-agent boto3
Since it’s a FastAPI app, you can run it as is.
uvicorn main:app --reload
(console log)
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO: Started reloader process [4999] using StatReload INFO: Started server process [5001] INFO: Waiting for application startup. INFO: pass_through_path: /events INFO: Application startup complete.
Accessing
http://127.0.0.1:8000/docs
will display the OpenAPI documentation via Swagger UI.You can proceed with agent development as FastAPI APIs.
-
Generating OpenAPI Schema
The OpenAPI schema can be output using FastAPI’s functionality. This output can be used as-is for Agents for Amazon Bedrock.
(Run in the app directory)
python -c "import main;import json; print(json.dumps(main.app.openapi()))" > openapi.json
-
Build and Deploy
Since it’s a SAM project, you can build and deploy using standard commands.
sam build sam deploy --guided
-
Local Testing
You can also test locally with the
sam local invoke
command.sam local invoke --event events/s3_bucket_count.json
-
Creating Agents for Amazon Bedrock
With the Lambda and OpenAPI schema ready, you can create the agent using the management console.
Summary
Thank you for reading until the end. Since you can focus solely on API definition for agent development, please make use of it.
[fluentform id="8"]