Building Agents with Claude: When Flexibility Beats Structure

Anablock
AI Insights & Innovations
April 26, 2026

claude 4

Building Agents with Claude: When Flexibility Beats Structure

Learn when to let Claude figure out the steps instead of defining them yourself. Discover how to build powerful agents with simple, combinable tools that handle unpredictable tasks.


Agents represent a shift from the structured workflows we've been working with. While workflows are perfect when you know the exact steps needed to complete a task, agents shine when you're not sure what those steps should be. Instead of defining a rigid sequence, you give Claude a goal and a set of tools, then let it figure out how to combine those tools to achieve the objective.

This flexibility makes agents attractive for building applications that need to handle varied, unpredictable tasks. You can create an agent once, ensure it works reasonably well, and then deploy it to solve a wide range of problems. However, this flexibility comes with trade-offs in reliability and cost that we'll explore later.


How Tools Make the Agent

The real power of agents lies in their ability to combine simple tools in unexpected ways. Consider a basic set of datetime tools:

  • get_current_datetime — Gets the current date and time
  • add_duration_to_datetime — Adds time to a given date
  • set_reminder — Creates a reminder for a specific time

These tools seem simple individually, but Claude can chain them together to handle surprisingly complex requests:

Simple Request

User: "What's the time?"

Claude's approach: Call get_current_datetime

Result: "It's 2:47 PM"

Moderate Complexity

User: "What day of the week is it in 11 days?"

Claude's approach:

  1. Call get_current_datetime to get today's date
  2. Call add_duration_to_datetime with 11 days
  3. Extract the day of the week from the result

Result: "In 11 days it will be Thursday"

High Complexity

User: "Set a reminder for my gym session next Wednesday at 6 PM"

Claude's approach:

  1. Call get_current_datetime to get today's date
  2. Call add_duration_to_datetime to find next Wednesday
  3. Call set_reminder with the calculated date and time

Result: "Reminder set for Wednesday, May 3rd at 6:00 PM"

Handling Missing Information

Claude can even recognize when it needs more information. If you ask "When does my 90-day warranty expire?", it knows to ask when you purchased the item before calculating the expiration date.

Claude's response: "I'd be happy to calculate that. When did you purchase the item?"

User: "March 15th"

Claude's approach:

  1. Parse the purchase date
  2. Call add_duration_to_datetime with 90 days
  3. Return the expiration date

Result: "Your 90-day warranty expires on June 13th"


Tools Should Be Abstract

The key insight for building effective agents is providing reasonably abstract tools rather than hyper-specialized ones. Claude Code demonstrates this principle perfectly.

What Claude Code Has

Claude Code has access to generic, flexible tools like:

  • bash — Run any command
  • read — Read any file
  • write — Create any file
  • edit — Modify files
  • glob — Find files
  • grep — Search file contents

What Claude Code Doesn't Have

It notably doesn't have specialized tools like:

  • ❌ "refactor code"
  • ❌ "install dependencies"
  • ❌ "run tests"
  • ❌ "deploy to production"
  • ❌ "generate documentation"

Instead, Claude figures out how to use the basic tools to accomplish these complex tasks.

Example: Installing Dependencies

When you ask Claude Code to "install the dependencies for this project," it doesn't call an install_dependencies tool. Instead, it:

  1. Uses read to check for package.json, requirements.txt, or Gemfile
  2. Uses bash to run npm install, pip install -r requirements.txt, or bundle install
  3. Uses read to verify the installation succeeded

This abstraction allows it to handle countless programming scenarios that the developers never explicitly planned for.


Best Practice: Combinable Tools

When designing agents, provide tools that Claude can combine in creative ways. For example, a social media video agent might include:

Tool Set

  • bash — Access to FFMPEG for video processing
  • generate_image — Create images from prompts
  • text_to_speech — Convert text to audio
  • post_media — Upload content to social platforms

Simple Workflow

User: "Create and post a video about coffee brewing"

Claude's approach:

  1. Generate script
  2. Call text_to_speech to create voiceover
  3. Call generate_image for visuals
  4. Call bash with FFMPEG to combine audio and images
  5. Call post_media to upload

Interactive Workflow

User: "Create a video about coffee brewing, but show me the thumbnail first"

Claude's approach:

  1. Generate script
  2. Call generate_image for thumbnail
  3. Show thumbnail to user and wait for approval
  4. If approved, proceed with text_to_speech and video creation
  5. Call post_media to upload

The agent can adapt its approach based on user feedback and preferences, something that would be difficult to achieve with a rigid workflow. This flexibility is what makes agents powerful for building dynamic, user-responsive applications.


Real-World Example: Research Agent

Let's build a research agent with these tools:

Tool Set

  • web_search — Search the web for information
  • read_url — Fetch and parse a webpage
  • save_note — Save information to a note
  • ask_user — Request clarification from the user

User Request

"Research the latest developments in quantum computing and summarize the key breakthroughs"

Agent's Approach (Emergent, Not Scripted)

  1. Initial search:

    • Call web_search("latest quantum computing breakthroughs 2026")
    • Get list of relevant URLs
  2. Evaluate sources:

    • Call read_url on the top 3 results
    • Identify which sources are most authoritative
  3. Deep dive:

    • Call web_search for specific topics mentioned (e.g., "quantum error correction 2026")
    • Call read_url on additional sources
  4. Clarify scope:

    • Call ask_user("I found breakthroughs in error correction, quantum networking, and new qubit designs. Which areas interest you most?")
    • Adjust research based on response
  5. Synthesize findings:

    • Call save_note with organized summary
    • Present findings to user

The key: You didn't script these exact steps. Claude figured out this approach based on the goal and available tools.


Designing Effective Agent Tools

✅ Good Tool Design

Abstract and composable:

@tool
def execute_sql(query: str) -> str:
    """Execute a SQL query and return results"""
    # Implementation

This single tool can:

  • Fetch data
  • Update records
  • Create tables
  • Analyze data
  • Generate reports

Why it works: Claude can construct any SQL query needed for the task.

❌ Poor Tool Design

Too specific:

@tool
def get_user_by_email(email: str) -> dict:
    """Get user record by email"""
    # Implementation

@tool
def get_user_by_id(user_id: int) -> dict:
    """Get user record by ID"""
    # Implementation

@tool
def get_users_by_signup_date(date: str) -> list:
    """Get users who signed up on a specific date"""
    # Implementation

Why it's problematic:

  • You need a new tool for every query pattern
  • Claude can't handle unexpected queries
  • Maintenance nightmare as requirements grow

Better approach: One execute_sql tool that handles all cases.


Tool Design Principles

1. Favor Primitives Over Composites

Primitive (good):

  • read_file
  • write_file
  • list_directory

Composite (avoid):

  • backup_and_restore_files
  • sync_directories

Claude can build composites from primitives, but not vice versa.

2. Make Tools Stateless

Stateless (good):

@tool
def search_products(query: str, filters: dict) -> list:
    """Search products with filters"""
    # Implementation

Stateful (avoid):

@tool
def set_search_filter(key: str, value: str):
    """Set a search filter for subsequent searches"""
    # Stores state between calls

Stateless tools are easier to reason about and combine.

3. Provide Clear Error Messages

@tool
def send_email(to: str, subject: str, body: str) -> dict:
    """Send an email
    
    Returns:
        {"status": "sent", "message_id": "..."}
        
    Raises:
        ValueError: If email address is invalid
        PermissionError: If sender is not authorized
        RateLimitError: If rate limit exceeded
    """
    # Implementation

Claude uses error messages to adjust its approach.

4. Include Usage Examples

@tool
def format_date(date_string: str, format: str) -> str:
    """Format a date string
    
    Args:
        date_string: Date in ISO format (e.g., "2026-04-26")
        format: Output format (e.g., "%B %d, %Y" for "April 26, 2026")
        
    Examples:
        format_date("2026-04-26", "%B %d, %Y") -> "April 26, 2026"
        format_date("2026-04-26", "%m/%d/%y") -> "04/26/26"
    """
    # Implementation

Examples help Claude understand how to use the tool correctly.


Agent vs. Workflow: A Side-by-Side Comparison

Scenario: Generate a Blog Post

Workflow Approach:

Step 1: Research topic (web_search)
Step 2: Create outline (call Claude)
Step 3: Write draft (call Claude)
Step 4: Add images (generate_image)
Step 5: Format for CMS (call Claude)
Step 6: Publish (post_to_cms)

Pros:

  • Predictable
  • Easy to debug
  • Consistent output

Cons:

  • Can't adapt to unexpected needs
  • Requires manual updates for new scenarios

Agent Approach:

Goal: "Create and publish a blog post about serverless architecture"

Tools:
- web_search
- generate_image
- call_claude (for writing)
- post_to_cms
- ask_user (for clarification)

Pros:

  • Adapts to user feedback
  • Handles edge cases gracefully
  • Can ask clarifying questions

Cons:

  • Less predictable
  • Harder to debug
  • May take unexpected paths

Trade-offs: When Agents Cost More

Agents are powerful, but they come with costs:

1. Token Usage

Workflow: Fixed token count per execution

Agent: Variable token count based on:

  • How many tools it tries
  • How many iterations it takes
  • How much context it needs

Example:

  • Workflow: 5,000 tokens every time
  • Agent: 3,000 tokens (simple task) to 50,000 tokens (complex task)

2. Latency

Workflow: Predictable execution time

Agent: Variable latency based on:

  • Number of tool calls
  • Sequential vs. parallel execution
  • User interaction requirements

3. Reliability

Workflow: Fails in predictable ways

Agent: Can fail in unexpected ways:

  • Gets stuck in loops
  • Calls wrong tools
  • Misinterprets user intent

Making Agents More Reliable

1. Set Clear Boundaries

system_prompt = """
You are a customer support agent with access to billing and account tools.

Rules:
- Never access user data without explicit permission
- Always confirm before making changes to accounts
- Escalate to human if user is frustrated or issue is complex
- Maximum 5 tool calls per request (ask user if you need more)
"""

2. Implement Safety Checks

def execute_tool(tool_name: str, args: dict):
    # Check if tool is allowed
    if tool_name in RESTRICTED_TOOLS:
        if not user_has_permission(current_user, tool_name):
            raise PermissionError(f"Not authorized to use {tool_name}")
    
    # Execute with timeout
    result = run_with_timeout(tool_name, args, timeout=30)
    
    # Log for audit
    log_tool_execution(tool_name, args, result)
    
    return result

3. Add Guardrails

# Limit iterations
max_iterations = 10
for i in range(max_iterations):
    action = agent.next_action()
    if action.type == "finish":
        break
    execute_action(action)
else:
    raise RuntimeError("Agent exceeded maximum iterations")

4. Monitor and Alert

# Track agent behavior
metrics = {
    "tool_calls": count_tool_calls(),
    "tokens_used": count_tokens(),
    "execution_time": measure_time(),
    "success_rate": calculate_success_rate()
}

# Alert if anomalies detected
if metrics["tool_calls"] > 20:
    alert("Agent making excessive tool calls")

When to Use Agents

Use agents when:

The task is open-ended — "Research this topic" vs. "Fetch these 3 specific data points"

User needs vary widely — Customer support, personal assistants, research tools

You want to handle edge cases gracefully — Agent can adapt instead of failing

Interactive refinement is valuable — Agent can ask clarifying questions

You have good tools — Abstract, composable tools that Claude can combine creatively


When to Use Workflows

Use workflows when:

The task is well-defined — You know exactly what needs to happen

Consistency is critical — Same input should always produce same output

Cost control matters — Predictable token usage and latency

Debugging is important — Easier to trace through fixed steps

Compliance is required — Auditable, deterministic processes


Conclusion

Agents are powerful when you need flexibility and can tolerate some unpredictability. The key to building effective agents is providing simple, abstract, combinable tools that Claude can use creatively to solve problems you never explicitly planned for.

The agent mindset:

  • Give Claude a goal, not a script
  • Provide primitives, not composites
  • Let Claude figure out the steps
  • Add guardrails to prevent runaway behavior
  • Monitor and iterate based on real usage

Start with a small set of well-designed tools. Test your agent with diverse requests. Add safety checks. Monitor its behavior. Over time, you'll develop intuition for when agents shine and when workflows are the better choice.


What agents are you building with Claude? Share your tool designs and lessons learned in the comments or join the discussion on the Anablock community forum.

Want to dive deeper into Claude development patterns? Check out our other guides:

Share this article:
View all articles

Related Articles

Unlock the Full Power of AI-Driven Transformation

Schedule Demo

See how Anablock can automate and scale your business with AI.

Book Demo

Start a Support Agent

Talk directly with our AI experts and get real-time guidance.

Call Now

Send us a Message

Summarize this page content with AI