Building complex AI-powered applications often requires that the system has to parse and process an output of an AI. Previously, Amazon Bedrock developers had to instruct the AI to print JSON or XML as the response in their model prompts, which was error-prone and often contained hallucinations. With the introduction of Bedrock Agents, developers can define schemas in the OpenAPI format and instruct their AI to use external APIs to retrieve the required data or to perform the requested operations.
Architecture
In this article we’re going to build a serverless API that can answer any question. But rather than just using an AI chat interface, we’re going to instruct the AI to send its answers to an API in a strictly structured JSON format. This means that the response of the AI is going to have a pre-defined schema and is guaranteed to have a valid syntax, compared to a regular chat prompt response. Effectively, this means that the AI can communicate with another machine when answering a question, not just with a human.
The source code for this project is available at GitHub. It’s based on the Serverless framework and consists of two Lambda functions: one that can relay questions from the user to the AI and the other that the AI can call itself when nececcary. Answers are stored in a DynamoDB table and shared between those two Lambdas:
Implementation
When creating a Bedrock model, we’re going to use a very simple instruction for the AI:
You are an agent that answers questions. You must save the answer to POST::API::answerQuestion API.
And when asking questions, the prompt will be the following:
Save the answer the following question: <question>{question}</question>
Notice the POST::API::answerQuestion
part. It is the name of one of the APIs available to the AI. Bedrock agent can be provided with an OpenAPI schema of operations that it can use. The schema for our project looks like this:
{ |
The schema only provides the structure of available operations, agents can’t call an API directly and instead rely on a Lambda function for execution. Our Lambda function for handling agent API calls has the following code:
1 | const router = new Router(); |
It saves the answer from the AI in a DynamoDB table so that in can be retrieved later. But in order to process this call, we first need ask the AI to answer a question. We do that via another Lambda function that handles requests from a REST endpoint in API Gateway:
1 | const api = async (event) => { |
Let’s try to call this function with a simple math question:
{ |
If tracing is enabled, the AI should log its reasoning and implementation details:
To answer this question, I will:
- Solve the math problem: Betty originally had 25 pencil crayons. She gave 5 to Theresa and 3 to Mary. So she gave away 5 + 3 = 8 pencil crayons. So she has 25 - 8 = 17 pencil crayons left.
- Call the POST::m2m-ai-agent-api::answerQuestion function to save the answer.
I have checked that I have access to the POST::m2m-ai-agent-api::answerQuestion function.
<function_call>post::m2m-ai-agent-api::answerQuestion(answer="17")</function_call>
<function_result>{"status":"OK"}</function_result>
And the API response will contain the answer to the original question:
{ |
Conclusion
Agents for Amazon Bedrock is a powerful feature that can bring AI applications to a whole new level. It provides AIs with the tools to solve complex problems and to perform operations on your behalf by making possible the integration with other systems in a scalable and secure way.