AI Agent Tool Use Patterns: 7 Architectures That Actually Work in Production
Every AI agent needs tools. Without them, your agent is just a chatbot โ eloquent but powerless. The difference between a demo and a product is how well your agent uses its tools.
After working with hundreds of agent developers, we've identified seven tool use patterns that consistently work in production. Each solves a different problem, and knowing when to use which pattern is the difference between an agent that works and one that frustrates users.
Pattern 1: Single-Shot Tool Call
When to use: Simple, deterministic tasks. One input โ one tool โ one output.
Example: "What's on this webpage?"
import openai
client = openai.OpenAI()
tools = [
{
"type": "function",
"function": {
"name": "scrape_url",
"description": "Scrape a webpage and return its content",
"parameters": {
"type": "object",
"properties": {
"url": {"type": "string", "description": "URL to scrape"},
"format": {"type": "string", "enum": ["text", "markdown"]}
},
"required": ["url"]
}
}
}
]
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Summarize https://example.com/blog/post"}],
tools=tools,
)
Pros: Simple, fast, predictable cost.
Cons: Can't handle multi-step tasks.
Pattern 2: ReAct Loop (Reason + Act)
When to use: Tasks that require multiple steps, where each step depends on previous results.
def react_loop(agent, task, max_steps=10):
messages = [{"role": "user", "content": task}]
for step in range(max_steps):
response = agent.chat(messages, tools=TOOLS)
if response.finish_reason == "stop":
return response.content # Agent is done
# Agent wants to use a tool
tool_call = response.tool_calls[0]
result = execute_tool(tool_call)
messages.append(response.message)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
return "Max steps reached"
The agent reasons about what to do, acts (calls a tool), observes the result, then reasons again. This is the most common pattern in production agents.
Pros: Flexible, handles complex tasks.
Cons: Unpredictable number of steps (and cost). Can loop.
Pattern 3: Parallel Tool Calls
When to use: Independent data gathering from multiple sources.
# Modern LLMs support parallel tool calls natively
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": "Compare pricing: ScrapingBee vs Bright Data vs WebPerception"
}],
tools=tools,
parallel_tool_calls=True,
)
# Agent returns 3 tool calls simultaneously โ execute in parallel
import asyncio
async def execute_parallel(tool_calls):
tasks = [execute_tool_async(tc) for tc in tool_calls]
return await asyncio.gather(*tasks)
Pros: 3x faster than sequential. Same cost.
Cons: Only works for independent operations.
Pattern 4: Tool Chaining (Pipeline)
When to use: Multi-stage data processing where each stage transforms the output.
# Stage 1: Search
search_results = scrape_url("https://news.ycombinator.com/item?id=hiring")
# Stage 2: Extract structured data
companies = extract_data(
url="https://news.ycombinator.com/item?id=hiring",
prompt="Extract company names, roles, locations, and salary ranges"
)
# Stage 3: Enrich each company
for company in companies:
details = scrape_url(company["website"])
company["about"] = extract_data(
url=company["website"],
prompt="Extract company size, funding, tech stack"
)
# Stage 4: Score and rank
ranked = score_companies(companies, criteria=user_preferences)
Pros: Clear data flow, each stage is testable.
Cons: Brittle โ if stage 2 fails, everything downstream fails.
Pattern 5: Fallback Chain
When to use: When primary tools might fail and you need alternatives.
async def get_stock_price(symbol: str) -> dict:
# Try primary source
try:
price = await extract_data(
url=f"https://finance.yahoo.com/quote/{symbol}",
prompt=f"Extract current stock price for {symbol}"
)
if price:
return {"source": "yahoo", "price": price}
except Exception:
pass
# Fallback to alternative
try:
price = await extract_data(
url=f"https://www.google.com/finance/quote/{symbol}:NASDAQ",
prompt=f"Extract current stock price for {symbol}"
)
if price:
return {"source": "google", "price": price}
except Exception:
pass
return {"error": "All sources failed"}
Pros: Resilient. Production-ready.
Cons: More API calls on failure.
Pattern 6: Human-in-the-Loop
When to use: High-stakes actions where the agent should confirm before proceeding.
class MonitoringAgent:
async def check_prices(self):
price_data = await extract_data(
url="https://competitor.com/pricing",
prompt="Extract the base plan monthly price"
)
price = float(price_data["price"])
if price < self.alert_threshold:
screenshot = await screenshot_url("https://competitor.com/pricing")
# Human-in-the-loop: alert, don't act
await notify_human(
f"โ ๏ธ Competitor dropped to ${price}!",
screenshot=screenshot
)
# Agent STOPS here โ human decides
Pros: Safety for high-stakes decisions. Builds trust.
Cons: Latency โ human needs to respond.
Pattern 7: Multi-Agent Delegation
When to use: Complex tasks that benefit from specialized agents working together.
from crewai import Agent, Task, Crew
researcher = Agent(
role="Research Analyst",
tools=[scrape_url, extract_data],
goal="Gather comprehensive data on target companies"
)
analyst = Agent(
role="Market Analyst",
tools=[extract_data],
goal="Analyze market positioning and competitive dynamics"
)
writer = Agent(
role="Report Writer",
tools=[screenshot_url],
goal="Produce a clear, data-backed market report"
)
crew = Crew(
agents=[researcher, analyst, writer],
tasks=[
Task(description="Research top 5 AI startups", agent=researcher),
Task(description="Analyze competitive positioning", agent=analyst),
Task(description="Write market report with screenshots", agent=writer),
],
)
report = crew.kickoff()
Pros: Separation of concerns. Each agent is focused and testable.
Cons: Complex orchestration. Higher cost. Debugging is harder.
Choosing the Right Pattern
| Pattern | Best For | Complexity | Cost |
|---|---|---|---|
| Single-Shot | Simple lookups | Low | $ |
| ReAct Loop | Multi-step research | Medium | $$ |
| Parallel | Independent data gathering | Medium | $ |
| Pipeline | Data processing workflows | Medium | $$ |
| Fallback | Production reliability | Medium | $-$$ |
| Human-in-Loop | High-stakes decisions | High | $$ |
| Multi-Agent | Complex analysis | High | $$$ |
Key Takeaways
- Start with Pattern 1 (single-shot) and add complexity only when needed
- Pattern 2 (ReAct) is your default for most production agents
- Always implement Pattern 5 (fallback) in production โ sites go down
- Pattern 6 (human-in-loop) for anything involving money or public communication
- Pattern 7 (multi-agent) only when you genuinely need specialization
The best agents aren't the most complex โ they're the ones that use the right pattern for the job.
Give Your Agent Eyes on the Web
Scrape, screenshot, and extract structured data from any URL. 100 free calls/month.
Get Your API Key โ