Backend Automation with Claude: Mastering Tool Use
Most developers look at Claude and see a chatbot. I look at Claude and see a dynamic routing engine. When you stop giving Claude unstructured text and start giving it access to your exact Pydantic schemas, database connectors, and internal API routes, it transforms into an autonomous backend worker.
In this guide, I will show you how I use Claude 3.5 Sonnet's "Tool Use" (or Function Calling) protocol to build self-healing Cron jobs and route customer support requests directly into a PostgreSQL database without touching a single human.
Phase 1: Defining the Tool Schema
The concept of 'Tool Use' is simple. You define a list of JSON schemas representing your backend functions. You pass this list to Claude alongside the user's message. Claude looks at the message, realizes it cannot answer it using internal knowledge, and outputs a strict JSON payload telling you to execute one of the functions on its behalf.
Let's pretend we are building an automated customer refund system. We define a tool called process_refund.
import os
from anthropic import Anthropic
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
# Define the exact inputs our backend function requires
tools = [
{
"name": "process_refund",
"description": "Trigger a full or partial refund for a customer via Stripe.",
"input_schema": {
"type": "object",
"properties": {
"customer_email": {
"type": "string",
"description": "The email address associated with the account."
},
"amount": {
"type": "integer",
"description": "The exact refund amount in cents."
},
"reason": {
"type": "string",
"description": "Why the refund was issued (e.g., 'defective product')."
}
},
"required": ["customer_email", "amount", "reason"]
}
}
]Handling the Tool Choice
If a user emails our generic support inbox saying: "My widget broke on day 2. My email is bob@test.com. I want my $40 back.", we pass that raw email to Claude along with the tool schema.
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
tools=tools,
messages=[
{"role": "user", "content": "My widget broke on day 2. My email is bob@test.com. I want my $40 back."}
]
)
# Claude recognizes it needs to use a tool to handle this
for block in response.content:
if block.type == "tool_use":
print(f"Claude wants to use: {block.name}")
print(f"With arguments: {block.input}")
# Output:
# Claude wants to use: process_refund
# With arguments: {'customer_email': 'bob@test.com', 'amount': 4000, 'reason': 'widget broke on day 2'}
Notice how Claude automatically converted $40 into 4000 cents because our schema specified "integer... exact refund amount in cents". Sonnet 3.5's reasoning is flawless here.
At this point, Claude has NOT executed the refund. Claude cannot access Stripe. Claude simply handed you back a clean, validated JSON object that you can inject directly into your Stripe SDK logic. You execute the Stripe charge, and then return a tool_result array back to Claude so it knows the transaction succeeded.
Phase 2: The Self-Healing Server Architecture
Tool use isn't just for user inputs. I use Claude as a backend watchdog. I built a Python background script that tails my NGINX error.log every 5 minutes. If it detects a 500 internal server error spike, it pulls the exact Python traceback from the logs and passes it to Claude.
Claude has a tool called git_patch_server_config. It analyzes the specific Python exception (e.g., a missing environment variable or a malformed Pydantic schema validation error). If it's a known, trivial error, Claude automatically generates a patch file via its tool call.
- Cron job detects a
KeyError: 'user_profile'on line 144 ofapi.py. - Claude analyzes the file via the
read_filetool. - Claude realizes the upstream API changed its JSON response format overnight.
- Claude calls the
edit_filetool to safely `.get('user_profile', )` to prevent the dictionary crash. - The system restarts via Gunicorn HUP signal. The server is healed.
Security and the Human-in-the-Loop
Never allow Claude to execute arbitrary shell scripts without human approval on production. In my self-healing architecture, Claude's edit_file tool pushes the change to a new Git branch and opens a Pull Request on GitHub. My phone buzzes with a Slack notification. I review the diff on my phone, hit 'Merge', and the CI/CD pipeline deploys the fix. Claude diagnoses, I approve.
Structuring the Supervisor System Prompt
To build a backend agent capable of doing this, you need a massive system prompt that defines the boundaries of its permissions. Here is the framework I use:
const SYSTEM_PROMPT = ` <role> You are an autonomous SRE (Site Reliability Engineer) monitoring a production Python FastAPI server. </role> <directives> 1. If you encounter an error trace, first use the 'read_file' tool to inspect the active source code. 2. Formulate a hypothesis inside <scratchpad> tags. 3. If the fix modifies logic flow, STOP and use the 'escalate_to_human' tool. 4. If the fix is a simple type mismatch or missing dictionary key, use the 'create_pull_request' tool. 5. Provide a summary of the root cause in the PR description. </directives> `;
Conclusion: The LLM as the Operating Engine
LLMs are not text generators. They are incredibly advanced reasoning engines capable of executing code, executing HTTP requests, and restructuring databases. By providing Claude with strict JSON tools, you abstract away the messy natural language layer and build deterministic, highly reliable event-driven automation in your backend.