Anthropic Tool Use (Function Calling) Integration in Application
Tool Use is a mechanism that allows Claude to call functions in your application. The model does not execute code directly: it returns structured JSON with the tool name and arguments, and your code executes the tool and returns the result. This is the foundation for building agents with access to real data and actions.
Basic Tool Use Loop
import anthropic
import json
from typing import Any
client = anthropic.Anthropic()
# Tool definitions
TOOLS = [
{
"name": "search_database",
"description": "Search customers in CRM by parameters",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"},
"limit": {"type": "integer", "description": "Number of results", "default": 10},
"status": {
"type": "string",
"enum": ["active", "churned", "trial"],
"description": "Status filter"
}
},
"required": ["query"]
}
},
{
"name": "send_email",
"description": "Send email to customer",
"input_schema": {
"type": "object",
"properties": {
"to": {"type": "string"},
"subject": {"type": "string"},
"body": {"type": "string"},
},
"required": ["to", "subject", "body"]
}
}
]
# Tool dispatcher
def execute_tool(tool_name: str, tool_input: dict) -> Any:
if tool_name == "search_database":
return search_crm(**tool_input)
elif tool_name == "send_email":
return send_email_via_smtp(**tool_input)
raise ValueError(f"Unknown tool: {tool_name}")
def run_agent(user_message: str) -> str:
"""Complete agentic loop with tool use"""
messages = [{"role": "user", "content": user_message}]
while True:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
tools=TOOLS,
messages=messages,
)
# No tool calls — return final answer
if response.stop_reason == "end_turn":
for block in response.content:
if hasattr(block, "text"):
return block.text
return ""
# Process tool_use blocks
tool_results = []
for block in response.content:
if block.type == "tool_use":
print(f"Calling tool: {block.name}({block.input})")
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result, ensure_ascii=False),
})
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
Parallel Tool Calls
Claude can call multiple tools in one response. Use asyncio for parallel execution:
import asyncio
async def execute_tool_async(tool_name: str, tool_input: dict) -> tuple[str, Any]:
"""Asynchronous tool execution"""
result = await asyncio.to_thread(execute_tool, tool_name, tool_input)
return tool_name, result
async def run_agent_async(user_message: str) -> str:
messages = [{"role": "user", "content": user_message}]
while True:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
tools=TOOLS,
messages=messages,
)
if response.stop_reason == "end_turn":
return next((b.text for b in response.content if hasattr(b, "text")), "")
# Execute all tools in parallel
tool_use_blocks = [b for b in response.content if b.type == "tool_use"]
results = await asyncio.gather(*[
execute_tool_async(b.name, b.input)
for b in tool_use_blocks
])
tool_results = [
{
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result, ensure_ascii=False),
}
for block, (_, result) in zip(tool_use_blocks, results)
]
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
Force Tool Call
# tool_choice="required" — Claude must call at least one tool
# tool_choice={"type": "tool", "name": "..."} — call specific tool
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=TOOLS,
tool_choice={"type": "tool", "name": "search_database"},
messages=[{"role": "user", "content": "Find customers with trial status"}],
)
Tool Error Handling
# Pass errors back to the model — it adapts behavior
try:
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result),
})
except Exception as e:
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": f"Error: {str(e)}",
"is_error": True, # Model knows about error and can correct
})
Practical Case: CRM Assistant
Task: Sales managers spent 20–30 min preparing for meetings (CRM search, recent contacts, open tasks).
Tools: get_customer_info, get_deal_history, get_recent_activities, create_task, get_calendar.
Result: meeting preparation — 2 min via dialog with assistant.
Timeline
- Basic tool use loop with 2–3 tools: 2–3 days
- Parallel calls + error handling: 1–2 days
- Production-ready with logging and retry: 1 week







