![Generating JSON with the Amazon Bedrock Converse API](https://assets.community.aws/a/2hWHtSFWankuhuDTcYcgMCVjr8M/gene.webp)
Generating JSON with the Amazon Bedrock Converse API
Learn how to return JSON output from large language models using Amazon Bedrock Converse API’s tool use capabilities.
Jason Stehle
Amazon Employee
Published Jun 9, 2024
This article is part of a series on tool use with Amazon Bedrock. In part 1, I provided a quick tutorial on the Amazon Bedrock Converse API. In part 2, I introduced how to use tools with the Converse API. In this article, I’ll demonstrate using Amazon Bedrock large language models to generate JSON that conforms to a pre-defined JSON Schema. I’ll walk through some key JSON Schema elements and a Python code example.
The Amazon Bedrock Converse API provides a consistent way to access large language models (LLMs) using Amazon Bedrock. It supports turn-based messages between the user and the generative AI model. It also provides a consistent format for tool definitions for the models that support tool use (aka “function calling”).
Tool use is a technique that allows a large language model to tell the calling application to invoke a function with parameters supplied by the model. The available tools and supported parameters are passed to the model along with a prompt. The model then can select a tool and define parameters according to the tool definition's JSON Schema. The calling application then calls the function and passes the provided parameters to it.
We can also use this tool use capability to skip the function call and just use the generated JSON directly. The example in this article will demonstrate how it works.
Why is JSON generation important? It allows us to more reliably convert unstructured content into structured data. In the past, massive amounts of unstructured data was buried and practically unusable, locked away in documents, customer feedback, and notes fields. For the most part, we only had keyword search as a means to work with that content at scale. With LLM-based JSON generation, we now have the ability to convert that raw content into quantitative data that we can better process and understand.
Generating JSON with the Amazon Bedrock Converse API follows these steps:
- The calling application passes (A) a tool definition that includes the desired JSON schema and (B) a triggering message to the large language model.
- The model generates a tool use request, including the JSON conforming to the tool definition’s JSON schema.
- The calling application extracts the JSON from the model’s tool use request and processes it.
You’ll want to have the latest AWS SDK and Amazon Bedrock model access configured before proceeding:
- Set up the Boto3 AWS SDK and Python: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html
- Select an AWS region that supports the Anthropic Claude 3 Sonnet model. I'm using us-west-2 (Oregon). You can check the documentation for model support by region.
- Configure Amazon Bedrock model access for your account and region. Example here: https://catalog.workshops.aws/building-with-amazon-bedrock/en-US/prerequisites/bedrock-setup
- If you don’t have your own local integrated development environment, you can try AWS Cloud9. Setup instructions here: https://catalog.workshops.aws/building-with-amazon-bedrock/en-US/prerequisites/cloud9-setup
- Large language models are non-deterministic. You should expect different results than those shown in this article.
- If you run this code from your own AWS account, you will be charged for the tokens consumed.
- I generally subscribe to a “Minimum Viable Prompt” philosophy. You may need to write more detailed prompts for your use case.
- Not every model supports all of the capabilities of the Converse API, so it’s important to review the supported model features in the official documentation.
Let’s say we’re an investment management company, and we get thousands of customer emails per day to a shared inbox. Normally we need our customer service team to review each email and decide if an action is required, and who should handle it. We might then store that information in a database or pass the data along to another application for further processing. But what if we could use generative AI to interpret the customer request, extract information from it, and recommend which team should handle the request?
We want to take a request like this:
Dear Acme Investments,I am writing to compliment one of your customer service representatives, Shirley Scarry. I recently had the pleasure of speaking with Shirley regarding my account deposit. Shirley was extremely helpful and knowledgeable, and went above and beyond to ensure that all of my questions were answered. Shirley also had Robert Herbford join the call, who franky seemed distracted. My wife Clara had some more detailed questions that Shirley was able to resolve for us.Shirley's professionalism and expertise were greatly appreciated, and I would be happy to recommend Acme Investments to others based on my experience.Sincerely,Carson Bradford
And extract data from it like this:
We’ll do this by:
- Defining a tool that specifies a JSON Schema for the desired output.
- Directly using the JSON generated by a Converse API tool use request.
Let’s start by reviewing the various components of a Converse API tool definition. I’ll share the full tool definition in the Python code later in this article.
We’ll start by defining a toolSpec element, and give the tool a name and a description. The name and description will help the model correctly determine when to request the tool.
I highly recommend reading Anthropic’s Best practices for tool definitions - although Amazon Bedrock uses a slightly different tool definition format, these best practices are still applicable.
The inputSchema is where we put the JSON schema for the JSON we want generated.
Now we can define the properties we want returned in the JSON response.
This fragment shows how to define a string property:
That will become something like this in the generated JSON:
You can learn more about string types here: https://json-schema.org/understanding-json-schema/reference/string
This fragment shows how to define a boolean property:
That will become something like this in the generated JSON:
Learn more about the boolean type here: https://json-schema.org/understanding-json-schema/reference/boolean
This fragment shows how to define a numeric property. It also specifies a range between 1 and 10, inclusive.
That will become something like this in the generated JSON:
You can learn more about numeric types and ranges here: https://json-schema.org/understanding-json-schema/reference/numeric
These fragments show how to define a string property with the enum keyword. This limits the allowed values to those listed for the enum.
That will become something like this in the generated JSON:
You can learn more about enums here: https://json-schema.org/understanding-json-schema/reference/enum
This fragment shows how to define a property that contains a list of strings. The property has type
array
and the items have type string
.That will become something like this in the generated JSON:
You can learn more about array definitions here: https://json-schema.org/understanding-json-schema/reference/array
This fragment shows how to define a property that contains a list of objects. The property has type
array
and the items have type object
. We then define the properties for the objects in the list (employee_name
and sentiment
).That will become something like this in the generated JSON:
You can learn more about object definitions here: https://json-schema.org/understanding-json-schema/reference/object
Finally, we specify that all of the above properties are required. Any properties not included in this list would be considered optional.
You can learn more about the
required
keyword here: https://json-schema.org/understanding-json-schema/reference/object#requiredWe use the
bedrock-runtime
service name to make calls to Amazon Bedrock models.Now behold the tool definition in its full glory:
Now we define the content to process and merge it into our prompt template:
This is one possible approach to merge the email content into your prompt. You could choose not to use XML tags or could use a different prompt for your specific use case.
We’re now ready to pass the tool definition and message to Amazon Bedrock. We specify Anthropic’s Claude 3 Sonnet as the target model. We also configure the toolChoice parameter to force Claude to use the
summarize_email
tool.You can review the tool choice options in the Converse API documentation and learn more about forcing tool use in the official Anthropic documentation.
As a final step, we now extract and print the JSON from the model’s tool use response:
Your script should display something like the following:
That looks about right!
I hope this gave you a good sense of how to define a JSON Schema and generate JSON from unstructured content. Now you can try coming up with a schema for your own use case!
- Not every model supports every capability of the Converse API, so it’s important to review the supported model features in the official documentation.
- You can find more generative AI hands-on activities at the Building with Amazon Bedrock workshop guide.
Any opinions in this post are those of the individual author and may not reflect the opinions of AWS.