AI & Agents

How to Build Custom Tools for Smolagents

Custom tools in Smolagents define functions your agents call to interact with the world. The framework includes basics like web search, but custom tools let agents use your specific APIs, databases, and file systems. This guide covers two ways to make them: the simple decorator approach and the class-based method.

Fast.io Editorial Team 8 min read
Custom tools act as the hands and eyes for your Smolagents, allowing them to manipulate data and interact with external systems.

Why You Need Custom Tools

Smolagents is popular with Python developers for its lightweight approach to building AI agents. It has less overhead than heavier frameworks. But an agent's real value comes from doing things, not just writing text.

According to Gartner, inquiries about multi-agent systems jumped 1,445% between early 2024 and mid-2025. This shift moves us from passive chatbots to active agents that run workflows. For an agent to work in an enterprise, it needs custom tools to connect its logic to your data.

If you need an agent to query a SQL database, resize an image, or fetch stock data, build a custom tool.

Neural index visualization showing data connectivity

Method 1: The @tool Decorator (The Simple Way)

For stateless functions that take simple inputs and return text or numbers, the @tool decorator is the simplest method. It parses your Python function's signature and docstring to create the tool definition that the Language Model (LLM) sees.

How to implement it:

  1. Import the tool decorator from smolagents.
  2. Write a standard Python function with strict type hints.
  3. Add a clear docstring that describes what the function does and explains each argument.
  4. Decorate the function with @tool.

Example Code:

from smolagents import tool

@tool
def fetch_customer_status(customer_id: str) -> str:
    """
    Retrieves the current subscription status of a customer.

Args:
        customer_id: The unique ID string of the customer (e.g., 'CUST-123').

Returns:
        A string indicating status: 'active', 'churned', or 'pending'.
    """
    # Logic to query your database would go here
    return "active"  # Placeholder

The agent reads the docstring to know when to call this tool and uses the type hints to know how to format the arguments. If you skip the type hints or docstring, the agent will likely fail to use the tool correctly.

Method 2: Subclassing Tool (The Advanced Way)

When you need more control, such as maintaining state between calls, handling complex initialization, or defining metadata explicitly, subclassing the Tool class is the better approach. This method handles state and metadata better, making it good for large projects.

Key components of a Tool subclass:

  • name: The unique identifier the model uses to call the tool.
  • description: A clear explanation of the tool's purpose.
  • inputs: A dictionary defining the schema for arguments.
  • output_type: The expected return type.
  • forward: The method containing the actual execution logic.

Example Code:

from smolagents import Tool

class ImageResizerTool(Tool):
    name = "image_resizer"
    description = "Resizes an image to specific dimensions."
    inputs = {
        "image_path": {"type": "string", "description": "Local path to the image file."},
        "width": {"type": "integer", "description": "Target width in pixels."}
    }
    output_type = "string"

def forward(self, image_path: str, width: int) -> str:
        # Complex logic to process image
        return f"Image at {image_path} resized to width {width}"

Integrating Tools with Your Agent

Once your tools are defined, you must register them with your agent. Whether you are using CodeAgent (which writes Python code to call tools) or ToolCallingAgent (which uses JSON-like structures), the process is similar.

Pass your tools as a list to the tools parameter during initialization. You can mix and match decorator-based tools and class-based tools in the same agent.

Integration Example:

from smolagents import CodeAgent, HfApiModel

# Initialize the agent with your custom tools
agent = CodeAgent(
    tools=[fetch_customer_status, ImageResizerTool()],
    model=HfApiModel()
)

# Run the agent
agent.run("Check the status of customer CUST-999 and resize their profile photo to 400px.")

The agent decides which tool to call based on the user's prompt and the tool descriptions you provided.

Giving Your Agents Long-Term Memory

One common challenge when building custom tools is managing state and file persistence. If your agent generates a report or processes a file, where does that data go? Local storage is ephemeral in many containerized environments.

Fast.io provides the persistent storage layer for your agentic workflows. By integrating Fast.io as a storage tool, your agents can read and write files to a secure cloud workspace that you can also access via a web UI.

Why Fast.io for Agents?

  • Persistent Storage: Files are safe, even if the agent crashes or the container restarts.
  • Zero-Config: Install via clawhub or simple API calls.
  • Concurrency: Fast.io supports file locks, allowing multiple agents to read/write to the same dataset without corruption.
  • Free Tier: 50GB of free storage for agent accounts, perfect for logging and data outputs.
Audit log of AI agent file operations
Fast.io features

Give Your Agents a Home Base

Don't let your agent's hard work disappear. Use Fast.io to store, organize, and share the files your custom tools create.

Best Practices for Tool Development

To ensure your custom tools work reliably with Smolagents, follow these optimization tips:

1. Explicit is Better Than Implicit LLMs struggle with ambiguity. If an argument is optional, state it clearly in the docstring. If a specific format is required (like "YYYY-MM-DD"), include that example in the description.

2. Handle Errors Gracefully Your tool should return informative error messages rather than crashing. If an API call fails, return a string like "Error: API timeout. Please try again," so the agent can attempt a retry or inform the user.

3. Keep Tools Atomic Avoid building "Swiss Army Knife" tools that do ten different things. Break them down into smaller, single-purpose tools. This makes it easier for the agent to reason about which tool to use for a specific step in the plan.

Frequently Asked Questions

What are smolagents?

Smolagents is a lightweight library from Hugging Face designed for building AI agents that write and execute Python code. It focuses on simplicity and minimal abstraction, making it easier for developers to create custom agentic workflows compared to heavier frameworks.

Can I use async functions with smolagents?

Currently, smolagents primarily supports synchronous execution for simplicity. If you have async code, you typically need to wrap it in a synchronous runner or use a bridge function to ensure the agent can execute it within its standard loop.

How do I debug a custom tool?

The best way to debug is to test the tool function independently before passing it to the agent. Since tools are just Python functions or classes, you can write standard unit tests for them. Additionally, you can enable verbose logging in your agent configuration to see exactly how the model is interpreting the tool's inputs.

Is Fast.io free for agent storage?

Yes, Fast.io offers a free tier specifically for agents and developers that includes 50GB of storage, 5,000 monthly operation credits, and standard support, without requiring a credit card to sign up.

Related Resources

Fast.io features

Give Your Agents a Home Base

Don't let your agent's hard work disappear. Use Fast.io to store, organize, and share the files your custom tools create.