# Creating a Customer Service Agent with Claude Tool Use Integration: A Complete Implementation Guide

> Build a customer service agent with Claude tool use integration. Follow this guide to define tools, implement dispatchers, and run a conversation loop for production-ready applications from anthropics/claude-cookbooks.

- Repository: [Anthropic/claude-cookbooks](https://github.com/anthropics/claude-cookbooks)
- Tags: how-to-guide
- Published: 2026-04-14

---

**You can build a production-ready customer service agent by defining JSON-schema tools, implementing a dispatcher function, and running a conversation loop that handles Claude's `tool_use` requests until the model returns a final answer.**

The **anthropics/claude-cookbooks** repository provides a reference implementation in `tool_use/customer_service_agent.ipynb` that demonstrates how to expose backend functions—like retrieving customer records or canceling orders—to Claude's reasoning engine. This pattern lets the model decide when to fetch data or perform actions during a conversation, making it ideal for support chatbots that need to interact with existing business systems.

## What You'll Build

The agent you'll create follows a standard **ReAct-like pattern**: Claude receives a user query, decides whether it needs external data, calls the appropriate function via a structured `tool_use` block, waits for your code to return the result, and then formulates a natural language response. The example in the cookbook implements three specific capabilities:

- **Customer lookup**: Retrieve email, phone, and name by customer ID
- **Order inquiry**: Fetch order status and details using an order ID  
- **Order cancellation**: Process cancellation requests through a protected function

All logic resides in pure Python within the notebook, with simulated data that you can replace with actual database queries or API calls.

## Prerequisites and Client Setup

To begin, install the Anthropic SDK and initialize the client. The cookbook uses model aliases rather than pinned dates to ensure you automatically receive the latest improvements.

```python
import anthropic

client = anthropic.Client()
MODEL_NAME = "claude-opus-4-1"

```

This client instance is reused across all interactions in the conversation loop (lines 36–40 in `customer_service_agent.ipynb`).

## Defining Tools for Your Customer Service Agent

Tools are declared as a list of dictionaries containing a name, description, and strict JSON Schema for the input. These definitions tell Claude not just what functions exist, but when to use them and what parameters to extract from the conversation.

```python
tools = [
    {
        "name": "get_customer_info",
        "description": "Retrieves customer information based on their customer ID.",
        "input_schema": {
            "type": "object",
            "properties": {
                "customer_id": {
                    "type": "string",
                    "description": "The unique identifier for the customer."
                }
            },
            "required": ["customer_id"],
        },
    },
    {
        "name": "get_order_details",
        "description": "Retrieves the details of a specific order based on the order ID.",
        "input_schema": {
            "type": "object",
            "properties": {
                "order_id": {
                    "type": "string",
                    "description": "The unique identifier for the order."
                }
            },
            "required": ["order_id"],
        },
    },
    {
        "name": "cancel_order",
        "description": "Cancels an order based on the provided order ID.",
        "input_schema": {
            "type": "object",
            "properties": {
                "order_id": {
                    "type": "string",
                    "description": "The unique identifier for the order to cancel."
                }
            },
            "required": ["order_id"],
        },
    },
]

```

This schema definition spans lines 57–100 in the source notebook. The `description` fields are critical—they guide Claude's reasoning when deciding which tool to invoke.

## Implementing the Backend Functions

For demonstration purposes, the cookbook uses static dictionaries, but these functions serve as drop-in templates for real database queries.

```python
def get_customer_info(customer_id):
    customers = {
        "C1": {"name": "John Doe", "email": "john@example.com", "phone": "123-456-7890"},
        "C2": {"name": "Jane Smith", "email": "jane@example.com", "phone": "987-654-3210"},
    }
    return customers.get(customer_id, "Customer not found")

def get_order_details(order_id):
    orders = {
        "O1": {"status": "Shipped", "items": ["Widget A"], "total": 25.00},
        "O2": {"status": "Processing", "items": ["Widget B", "Widget C"], "total": 45.00},
    }
    return orders.get(order_id, "Order not found")

def cancel_order(order_id):
    orders = {
        "O1": {"status": "Cancelled"},
        "O2": {"status": "Processing"},
    }
    if order_id in orders:
        orders[order_id]["status"] = "Cancelled"
        return f"Order {order_id} has been cancelled."
    return "Order not found"

```

These implementations appear at lines 118–148 in `customer_service_agent.ipynb`. Replace the dictionary lookups with your actual CRM or order management API calls.

## Building the Tool Call Dispatcher

When Claude decides a tool is needed, it returns a `tool_use` content block containing the tool name and parsed arguments. Your code must route this to the correct Python function.

```python
def process_tool_call(tool_name, tool_input):
    if tool_name == "get_customer_info":
        return get_customer_info(tool_input["customer_id"])
    elif tool_name == "get_order_details":
        return get_order_details(tool_input["order_id"])
    elif tool_name == "cancel_order":
        return cancel_order(tool_input["order_id"])
    else:
        return "Unknown tool"

```

This dispatcher logic appears at lines 71–78 in the notebook. It acts as the bridge between Claude's structured output and your business logic.

## The Conversation Loop: Handling Claude's Tool Use Requests

The core of the agent is a `while` loop that continues until Claude no longer requests tools (`stop_reason == "end_turn"`). When `stop_reason` equals `"tool_use"`, your code extracts the tool call, executes it, and appends a `tool_result` block to the message history before sending the updated conversation back to the API.

```python
def chatbot_interaction(user_message):
    messages = [{"role": "user", "content": user_message}]
    response = client.messages.create(
        model=MODEL_NAME,
        max_tokens=4096,
        tools=tools,
        messages=messages
    )

    while response.stop_reason == "tool_use":
        # Extract the tool_use block from the response

        tool_use = next(block for block in response.content if block.type == "tool_use")
        tool_result = process_tool_call(tool_use.name, tool_use.input)

        # Reconstruct the conversation with the tool result

        messages = [
            {"role": "user", "content": user_message},
            {"role": "assistant", "content": response.content},
            {"role": "user", "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use.id,
                "content": str(tool_result)
            }]},
        ]
        
        response = client.messages.create(
            model=MODEL_NAME,
            max_tokens=4096,
            tools=tools,
            messages=messages
        )

    final_response = next(
        (block.text for block in response.content if hasattr(block, "text")), 
        None
    )
    return final_response

```

This interaction loop runs from lines 95–107 in `customer_service_agent.ipynb`. Note that each `tool_use` block has a unique `tool_use_id` that you must echo back in the `tool_result` to maintain the conversation state.

## Putting It All Together

With all components defined, you can run end-to-end interactions. The notebook demonstrates several scenarios at lines 774–553:

```python
print(chatbot_interaction("Can you tell me the email address for customer C1?"))

# Claude calls get_customer_info → returns john@example.com

print(chatbot_interaction("What is the status of order O2?"))

# Claude calls get_order_details → returns Processing status

print(chatbot_interaction("Please cancel order O1 for me."))

# Claude calls cancel_order → confirms cancellation

```

In each case, Claude autonomously selects the correct tool, waits for your function to return data, and then composes a helpful response for the user.

## Summary

- **Tool definitions** use JSON Schema to constrain Claude's output and guide its reasoning about which function to call.
- **Backend implementations** in `customer_service_agent.ipynb` demonstrate the pattern using static data, ready for replacement with real API calls.
- **The dispatcher function** (`process_tool_call`) routes Claude's structured requests to your business logic.
- **The conversation loop** handles multi-turn tool use by checking `stop_reason`, executing tools, and feeding results back via `tool_result` blocks until Claude reaches `end_turn`.
- This architecture, as implemented in the `anthropics/claude-cookbooks` repository, creates an extensible customer service agent that can integrate with any backend system.

## Frequently Asked Questions

### How does Claude decide which tool to use during a conversation?

Claude examines the `description` field in each tool definition alongside the current conversation context. When it determines that retrieving customer data, order details, or performing a cancellation would help answer the user's query, it constructs a `tool_use` block with the appropriate `name` and extracted parameters. The decision logic is internal to the model, guided by your schema descriptions.

### Can I connect these tools to a real database instead of static dictionaries?

Yes. Replace the dictionary lookups in `get_customer_info`, `get_order_details`, and `cancel_order` with actual database queries, REST API calls, or SDK invocations. The notebook uses static data purely for demonstration purposes, but the `process_tool_call` dispatcher works identically with any Python function that returns serializable data.

### What happens if Claude requests a tool with invalid parameters?

The `input_schema` you provide in the tool definition constrains Claude to generate valid JSON structures. However, you should still implement validation in your backend functions. If a required parameter is missing or malformed, raise an exception or return an error string, which Claude will receive as the `tool_result` content and can use to ask the user for clarification.

### How do I handle multiple tool calls in a single response?

While the basic implementation in the cookbook processes one tool at a time, the API supports parallel tool calls. If `response.content` contains multiple `tool_use` blocks, iterate over all of them, execute each function, and return a list of `tool_result` blocks in your next message. Ensure each result references its corresponding `tool_use_id`.