Businesses across industries face a common challenge: how to efficiently extract valuable information from vast amounts of unstructured data. Traditional approaches often involve resource-intensive processes and inflexible models. This post introduces a game-changing solution: Claude Tool use in Amazon Bedrock which uses the power of large language models (LLMs) to perform dynamic, adaptable entity recognition without extensive setup or training.
In this post, we walk through:
Claude Tool use, also known as function calling, is a powerful capability that allows us to augment Claude’s abilities by establishing and invoking external functions or tools. This feature enables us to provide Claude with a collection of pre-established tools that it can access and employ as needed, enhancing its functionality.
Amazon Bedrock is a fully managed generative artificial intelligence (AI) service that offers a range of high-performing foundation models (FMs) from industry leaders like Anthropic. Amazon Bedrock makes implementing Claude’s Tool use remarkably straightforward:
In this post, we demonstrate how to extract custom fields from driver’s licenses using Claude Tool use in Amazon Bedrock. This serverless solution processes documents in real-time, extracting information like names, dates, and addresses without traditional model training.
Our custom entity recognition solution uses a serverless architecture to process documents efficiently and extract relevant information using Amazon Bedrock’s Claude model. This approach minimizes the need for complex infrastructure management while providing scalable, on-demand processing capabilities.
The solution architecture uses several AWS services to create a seamless pipeline. Here’s how the process works:
The following diagram shows how these services work together:

This implementation guide demonstrates how to build a serverless document processing solution using Amazon Bedrock and related AWS services. By following these steps, you can create a system that automatically extracts information from documents like driver’s licenses, avoiding manual data entry and reducing processing time. Whether you’re handling a few documents or thousands, this solution can scale automatically to meet your needs while maintaining consistent accuracy in data extraction.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "bedrock:InvokeModel",
"Resource": "arn:aws:bedrock:*::foundation-model/*", "arn:aws:bedrock:*:111122223333:inference-profile/*”
},
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*"
}
]
}


import boto3, json
import base64
def lambda_handler(event, context):
bedrock = boto3.client("bedrock-runtime")
s3 = boto3.client("s3")
bucket = event["Records"][0]["s3"]["bucket"]["name"]
key = event["Records"][0]["s3"]["object"]["key"]
file = s3.get_object(Bucket=bucket, Key=key)
# Convert image to base64
image_data = file["Body"].read()
base64_image = base64.b64encode(image_data).decode('utf-8')
# Define tool schema
tools = [{
"name": "extract_license_fields",
"input_schema": {
"type": "object",
"properties": {
"first_name": { "type": "string" },
"last_name": { "type": "string" },
"issue_date": { "type": "string" },
"license_number": { "type": "string" },
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" },
"zip": { "type": "string" }
}
}
},
"required": ["first_name", "last_name", "issue_date", "license_number", "address"]
}
}]
payload = {
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 2048,
"messages": [{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": base64_image
}
},
{
"type": "text",
"text": "Extract the driver's license fields from this image."
}
]
}],
"tools": tools
}
try:
response = bedrock.invoke_model(
modelId="global.anthropic.claude-sonnet-4-5-20250929-v1:0",
body=json.dumps(payload)
)
result = json.loads(response["body"].read())
# Print every step for debugging
print("1. Raw Response:", json.dumps(result, indent=2))
if "content" in result:
print("2. Content found in response")
for content in result["content"]:
print("3. Content item:", json.dumps(content, indent=2))
if isinstance(content, dict):
print("4. Content type:", content.get("type"))
if content.get("type") == "text":
print("5. Text content:", content.get("text"))
if content.get("type") == "tool_calls":
print("6. Tool calls found")
extracted = json.loads(content["tool_calls"][0]["function"]["arguments"])
print("7. Extracted data:", json.dumps(extracted, indent=2))
return {
"statusCode": 200,
"body": json.dumps({
"message": "Process completed",
"raw_response": result
}, indent=2)
}
except Exception as e:
print(f"Error occurred: {str(e)}")
return {
"statusCode": 500,
"body": json.dumps({
"error": str(e),
"type": str(type(e))
})
}
extract_license_fields)[{
"name": "extract_license_fields",
"input_schema": {
"type": "object",
"properties": {
"first_name": { "type": "string" },
"last_name": { "type": "string" },
"issue_date": { "type": "string" },
"license_number": { "type": "string" },
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" },
"zip": { "type": "string" }
}
}
},
"required": ["first_name", "last_name", "issue_date", "license_number", "address"]
}
}]
"tool_choice": {
"type": "tool",
"name": "extract_license_fields"
}
Note: The tool_choice field is optional. If omitted, Claude defaults to “auto.”
invoke_drivers_license.{
"type": "tool_use",
"id": "toolu_bdrk_01Ar6UG7BcARjqAKsiSPyNdf",
"name": "extract_license_fields",
"input": {
"first_name": "JANE",
"last_name": "DOE",
"issue_date": "05/05/2025",
"license_number": "111222333",
"address": {
"street": "123 ANYWHERE STREET",
"city": "EXAMPLE CITY",
"state": "VA",
"zip": "00000"
}
}
}

tool_calls is present in the response.try:
result = json.loads(response["body"].read())
if "tool_calls" in result.get("content", [{}])[0]:
args = result["content"][0]["tool_calls"][0]["function"]["arguments"]
print("Extracted Fields:", json.dumps(json.loads(args), indent=2))
except Exception as e:
print("Error occurred:", str(e))
Claude Tool use in Amazon Bedrock provides a powerful solution for custom entity extraction, minimizing the need for complex machine learning (ML) models. This serverless architecture enables scalable, cost-effective processing of documents with minimal setup and maintenance. By leveraging the power of large language models through Amazon Bedrock, organizations can unlock new levels of efficiency, insight, and innovation in handling unstructured data.
We encourage you to explore this solution further by implementing the sample code in your environment and customizing it for your specific use cases. Join the discussion about entity extraction solutions in the AWS re:Post community, where you can share your experiences and learn from other developers.
For deeper technical insights, explore our comprehensive documentation on Amazon Bedrock, AWS Lambda, and Amazon S3. Consider enhancing your implementation by integrating with Amazon Textract for additional document processing features or Amazon Comprehend for advanced text analysis. To stay updated on similar solutions, subscribe to our AWS Machine Learning Blog and explore more examples in the AWS Samples GitHub repository. If you’re new to AWS machine learning services, check out our AWS Machine Learning University or explore our AWS Solutions Library. For enterprise solutions and support, reach out through your AWS account team.
Manuel Rioux est fièrement propulsé par WordPress