---
title: How to Build an Amazon Bedrock Agent with Tool Use (2026)
description: Amazon Bedrock Agents automate workflows by giving foundation models the ability to call tools (APIs, Lambda, databases). This guide covers building agents with tool definitions, testing in the console, handling errors, and scaling to production.
url: https://www.factualminds.com/blog/how-to-build-amazon-bedrock-agent-tool-use-2026/
datePublished: 2026-04-03T00:00:00.000Z
dateModified: 2026-04-16T00:00:00.000Z
author: Palaniappan P
category: Generative AI
tags: how-to-guide, bedrock, genai, agents, tool-use, aws
---

# How to Build an Amazon Bedrock Agent with Tool Use (2026)

> Amazon Bedrock Agents automate workflows by giving foundation models the ability to call tools (APIs, Lambda, databases). This guide covers building agents with tool definitions, testing in the console, handling errors, and scaling to production.

Amazon Bedrock Agents extend foundation models with the ability to call external tools — APIs, Lambda functions, databases, and more. Instead of returning a single response, agents reason over multiple steps, deciding which tools to call and how to use results to answer complex questions.

This guide covers building agents end-to-end: defining tools, creating the agent, testing in the console, and deploying at scale with error handling and monitoring.

> **Building Intelligent Agents on AWS?** FactualMinds helps teams implement Bedrock agents with custom tool integrations, secure API access, and production monitoring. [See our AWS Bedrock consulting services](/services/aws-bedrock/) or [talk to our team](/contact-us/).

## Step 1: Understand the Agent Architecture

Bedrock Agents operate in a continuous loop:

```
User Input
  ↓
Agent (Claude or other model)
  ↓ (model decides to call a tool)
Tool (Lambda, API Gateway, Knowledge Base)
  ↓ (tool returns result)
Agent (model processes result, decides next step)
  ↓ (repeat until done)
Response to User
```

**Key concepts:**

- **Agent Executor**: The runtime that manages the agentic loop. You invoke it once; it handles multiple tool calls internally.
- **Tool Definition**: OpenAPI spec describing what the tool does, required inputs, outputs. Agent uses this to decide _when_ to call the tool.
- **Tool Action**: When the agent decides to call a tool, Bedrock invokes it and returns the result.
- **Tool Artifacts**: Knowledge Bases or code interpreters that the agent can access directly.

**Example flow:**

User: "I need a report on my top 10 customers by revenue for Q1 2026."

Agent reasoning:

1. "I need to query the database for customer revenue data" → calls `QueryCustomerRevenue` tool
2. Receives list of customers + revenue
3. "I need to generate a formatted report" → calls `GenerateReport` tool
4. Returns formatted report to user

## Step 2: Define Your Tools

Tools are described using **OpenAPI 3.0 specifications**. Bedrock uses these specs to decide when to call tools and what parameters to pass.

### Tool Types in Bedrock Agents

1. **AWS Lambda** (most common) — synchronous functions for business logic
2. **AWS Step Functions** (for long-running workflows) — async state machines
3. **API Gateway** (for third-party APIs) — Stripe, SendGrid, external systems
4. **Knowledge Base** (built-in) — semantic search over documents
5. **Code Interpreter** (built-in) — run Python for calculations

### Define a Lambda Tool

Create a Lambda function for customer lookup:

```python
# lambda_handler.py
import json
import boto3

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Customers')

def lambda_handler(event, context):
    customer_id = event.get('customerId')
    response = table.get_item(Key={'id': customer_id})

    if 'Item' in response:
        return {
            'statusCode': 200,
            'body': json.dumps(response['Item'])
        }
    else:
        return {
            'statusCode': 404,
            'body': json.dumps({'error': 'Customer not found'})
        }
```

Define the tool in the agent using **OpenAPI spec**:

```json
{
  "toolSpec": {
    "name": "GetCustomerInfo",
    "description": "Retrieve detailed information about a customer by ID",
    "inputSchema": {
      "json": {
        "type": "object",
        "properties": {
          "customerId": {
            "type": "string",
            "description": "The unique customer ID (e.g., CUST-12345)"
          }
        },
        "required": ["customerId"]
      }
    }
  },
  "toolInputType": "LAMBDA",
  "toolInputReference": "arn:aws:lambda:us-east-1:123456789012:function:GetCustomerInfo"
}
```

Key fields:

- `name`: Tool identifier (used by agent in reasoning)
- `description`: What the tool does (agent reads this to decide when to call it)
- `inputSchema`: Parameters the tool accepts (JSON schema)
- `toolInputType`: Type of tool (LAMBDA, API_GATEWAY, STEP_FUNCTIONS, KNOWLEDGE_BASE)
- `toolInputReference`: ARN or URL of the actual tool

### Define an API Gateway Tool

For third-party APIs:

```json
{
  "toolSpec": {
    "name": "SendEmail",
    "description": "Send an email using SendGrid API",
    "inputSchema": {
      "json": {
        "type": "object",
        "properties": {
          "to": {
            "type": "string",
            "description": "Recipient email address"
          },
          "subject": {
            "type": "string",
            "description": "Email subject"
          },
          "body": {
            "type": "string",
            "description": "Email body (HTML or plain text)"
          }
        },
        "required": ["to", "subject", "body"]
      }
    }
  },
  "toolInputType": "API_GATEWAY",
  "toolInputReference": "https://api.sendgrid.com/v3/mail/send",
  "toolAuthConfig": {
    "authorizationType": "BEARER_TOKEN",
    "apiKeyAuthConfig": {
      "apiKeyName": "Authorization",
      "secretsManagerArn": "arn:aws:secretsmanager:us-east-1:123456789012:secret:sendgrid-api-key"
    }
  }
}
```

Bedrock:

1. Reads the SendGrid API spec
2. When the agent decides to call SendEmail, Bedrock constructs the API request
3. Retrieves the API key from Secrets Manager
4. Calls SendGrid and returns the response

## Step 3: Create an Agent in the AWS Console

Navigate to **Amazon Bedrock** → **Agents**:

1. Click **Create agent**
2. **Agent name**: `customer-service-agent` (lowercase, descriptive)
3. **Agent description**: "Helps customers with account queries, orders, and support"
4. **Model**: Select **Claude 3.5 Sonnet** (or preferred model)
5. **Agent role**: Create or select an IAM role with permissions for:
   - `lambda:InvokeFunction` (for Lambda tools)
   - `secretsmanager:GetSecretValue` (for API authentication)
   - `bedrock:InvokeModel` (for Knowledge Base access)

6. **Instructions** (system prompt for the agent):

```
You are a customer service representative for [Company]. Your job is:
1. Answer customer questions about their account, orders, and billing
2. Help resolve support issues by gathering information and escalating if needed
3. Always be polite and professional

Tools available:
- GetCustomerInfo: Retrieve customer account details
- GetOrderHistory: Retrieve past orders
- SendEmail: Send follow-up emails to customers

When a customer asks a question:
1. Use GetCustomerInfo to load their account
2. Use GetOrderHistory if they ask about orders
3. Answer their question based on the data
4. If the issue can't be resolved, offer to escalate

Never make assumptions. Always retrieve data before answering.
```

7. Click **Create**

## Step 4: Add Tools to the Agent

In the agent detail page, go to **Tools**:

1. Click **Add tool**
2. Choose tool type (Lambda, API Gateway, Knowledge Base, etc.)
3. For Lambda: Select function from dropdown
4. For API: Paste OpenAPI spec URL or raw JSON
5. Click **Add tool**

Repeat for all tools (customer lookup, order history, email, etc.).

## Step 5: Test the Agent in the Playground

**Bedrock Console** → **Agents** → **[Your Agent]** → **Test**:

1. Enter a test prompt:

```
I need information about customer CUST-54321
```

2. Watch the agent reasoning:

```
Thinking... I should call GetCustomerInfo with customerId=CUST-54321

Tool: GetCustomerInfo
Input: {"customerId": "CUST-54321"}
Result: {"id": "CUST-54321", "name": "Alice", "email": "alice@example.com", "plan": "Pro"}

I have the customer information. Let me provide a response...
```

3. Agent responds:

```
I found the customer Alice (CUST-54321). They're on the Pro plan and can be reached at alice@example.com. Is there anything specific I can help with?
```

4. Test error handling:

```
I need information about a non-existent customer
```

Verify the agent:

- Calls the tool even when the customer doesn't exist
- Handles the error gracefully (instead of crashing)
- Informs the user that the customer wasn't found

## Step 6: Integrate the Agent into Your Application

Use the **Bedrock Agent Runtime API** to invoke agents from code:

```python
import boto3
import json

bedrock_agent_runtime = boto3.client('bedrock-agent-runtime', region_name='us-east-1')

agent_id = 'your-agent-id'
agent_alias_id = 'LFSSTCWOOY'  # Default alias

response = bedrock_agent_runtime.invoke_agent(
    agentId=agent_id,
    agentAliasId=agent_alias_id,
    sessionId='session-123',  # Unique per conversation
    inputText='I need information about customer CUST-54321'
)

# Stream results (agents return responses as events)
result_text = ''
for event in response.get('completion', []):
    if 'chunk' in event:
        chunk_data = event['chunk'].get('bytes', b'').decode('utf-8')
        result_text += chunk_data
        print(chunk_data, end='', flush=True)

print(f"\nFinal response: {result_text}")
```

### Handling Agent Errors

Agents can fail if tools error out or the model gets stuck. Handle gracefully:

```python
try:
    response = bedrock_agent_runtime.invoke_agent(
        agentId=agent_id,
        agentAliasId=agent_alias_id,
        sessionId=session_id,
        inputText=user_input
    )

    result = ''.join([
        event['chunk']['bytes'].decode('utf-8')
        for event in response.get('completion', [])
        if 'chunk' in event
    ])

    return {'response': result, 'status': 'success'}

except bedrock_agent_runtime.exceptions.AccessDeniedException as e:
    return {'error': 'Permission denied. Check agent permissions.', 'status': 'error'}

except bedrock_agent_runtime.exceptions.ValidationException as e:
    return {'error': 'Invalid agent configuration.', 'status': 'error'}

except Exception as e:
    return {'error': f'Agent error: {str(e)}', 'status': 'error'}
```

## Step 7: Monitor and Optimize

### CloudWatch Metrics

Enable **Agent Execution Metrics**:

```
bedrock:agent:InvocationCount
bedrock:agent:ToolUseCount
bedrock:agent:ToolErrorCount
bedrock:agent:ExecutionTimeMs
```

Set up alarms:

- If `ToolErrorCount` spikes → review tool implementations
- If `ExecutionTimeMs` > 10s → agent is looping; refine tool definitions or instructions

### Optimize Tool Use

1. **Reduce tool calls**: Refine agent instructions to avoid unnecessary calls
   - Instead of "call GetCustomerInfo and GetOrderHistory separately", say "retrieve complete customer profile (info + orders)"

2. **Cache results**: Store frequently-accessed data (customer profiles, inventory) in the agent's session context to avoid repeated tool calls

3. **Prioritize tools**: Order tools in the agent's tool list by likelihood of use (most-used first)

## Step 8: Production Patterns

### Pattern 1: Multi-Tool Reasoning

For complex workflows, give agents multiple tools and let them chain operations:

```
Agent Tools:
- QueryDatabase (customer data)
- GenerateReport (formatting)
- SendEmail (delivery)

User: "Send my quarterly revenue report to alice@example.com"

Agent:
1. Calls QueryDatabase → retrieves Q1-Q3 revenue data
2. Calls GenerateReport → formats as PDF
3. Calls SendEmail → sends to alice@example.com
```

### Pattern 2: Graceful Degradation

If a tool fails, the agent should fall back to a simpler response:

```python
# Tool definition with fallback
{
  "toolSpec": {
    "name": "GetInventory",
    "description": "Check product inventory (may fail; agent should handle gracefully)"
  },
  # If tool fails 3x, agent responds: "I couldn't check inventory, but here's what I know..."
}
```

### Pattern 3: Audit Logging

Log all agent invocations for compliance and debugging:

```python
import logging

logger = logging.getLogger('agents')

def invoke_agent_with_logging(user_id, input_text):
    logger.info(
        'Agent invoked',
        extra={
            'user_id': user_id,
            'input': input_text,
            'timestamp': datetime.now().isoformat()
        }
    )

    response = bedrock_agent_runtime.invoke_agent(
        agentId=agent_id,
        sessionId=user_id,
        inputText=input_text
    )

    logger.info(
        'Agent completed',
        extra={
            'user_id': user_id,
            'tool_calls': count_tool_calls(response),
            'status': 'success'
        }
    )

    return response
```

## Common Mistakes to Avoid

1. **Tool definitions too vague**
   - ❌ Description: "Get data"
   - ✓ Description: "Retrieve customer billing history for a given customer ID, including invoices and payment status"

2. **Not handling tool errors**
   - Agent gets stuck if a tool returns an error
   - Design tools to return empty results instead of errors

3. **Too many tools**
   - Agents get confused with >10 tools
   - Start with 3-5 core tools, add more only if needed

4. **Insufficient context in instructions**
   - Don't just say "use tools to help the customer"
   - Specify _which_ tools for _what_ scenarios

5. **Not testing error paths**
   - Test what happens when a tool fails, returns empty, or returns unexpected data
   - Agent should degrade gracefully

## Next Steps

1. Define your first 3 tools (start simple)
2. Create an agent in the console and test with sample inputs
3. Integrate into a test application with error handling
4. Monitor tool usage and refine agent instructions
5. Deploy to production with audit logging
6. [Talk to FactualMinds](/contact-us/) if you need help designing agent workflows for complex business processes

## FAQ

### What is the difference between an Agent and a regular Bedrock model invocation?
A regular invocation returns one response from the model. An Agent runs a loop: (1) model decides what tool to call, (2) tool is executed, (3) result is fed back to the model, (4) model decides next action. This agentic loop enables multi-step reasoning — e.g., "get customer data" → "check inventory" → "calculate shipping" → "generate quote" in one conversation. Regular invocations require you to orchestrate these steps in application code. Agents do it inside the model loop.

### How much latency does an agentic loop add?
Each loop iteration (model invocation + tool call) adds 500ms–2s depending on model latency and tool execution time. A 3-step agent = 1.5–6s total. For interactive applications (customer chat), this is acceptable. For sub-100ms SLAs, agents are too slow — use regular model invocations with application-orchestrated tool calls instead.

### What happens if a tool call fails or returns an error?
Bedrock Agents catch tool errors and feed the error message back to the model, which can retry or choose a different tool. If a tool fails 3+ times in sequence, the agent stops and returns an error to the caller. Best practice: design tools with graceful degradation (return empty results instead of errors) so the agent can continue reasoning.

### Can I use third-party APIs as tools?
Yes. Define tools via OpenAPI specs (e.g., Stripe API, SendGrid API, custom APIs). Bedrock translates your tool definitions into API calls, handles authentication (API keys via Secrets Manager), and parses responses. For security, use AWS Secrets Manager to store API keys — never hardcode them in tool definitions.

### How much does a Bedrock Agent cost?
Bedrock Agents are charged per invocation (model tokens) + per tool call. Tool call costs vary by tool type: Lambda = AWS Lambda pricing, API Gateway = $0.35 per 1M API calls, databases = query charges. For a conversation with 5 turns and 2 tool calls per turn = 10 tool invocations. With Claude 3.5 Sonnet at $3 per 1M input tokens (~$0.009 per chat), agent overhead = ~$0.09 per conversation (tool calls) + $0.009 (model). Most cost is in tool invocations, not the model itself.

---

*Source: https://www.factualminds.com/blog/how-to-build-amazon-bedrock-agent-tool-use-2026/*
