> ## Documentation Index
> Fetch the complete documentation index at: https://agency-swarm.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Step-by-Step Guide

> Learn how to create custom tools in Agency Swarm framework.

In Agency Swarm, tools enable agents to perform specific actions and interact with external systems. The framework supports two approaches for creating custom tools depending on the version you're using.

Framework supports 2 methods of creating tools:

1. Using agency-swarm's `BaseTool` class.
2. Using openai's `@function_tool` decorator with async functions.

Explore the sections below to find a method that suits your approach the best.

<Tabs defaultValue="BaseTool">
  <Tab title="BaseTool">
    In Agency Swarm’s approach, tools are Python classes that inherit from `BaseTool`. They are defined using [Pydantic](https://docs.pydantic.dev/latest/), a data validation library. Each BaseTool must implement the `run` method, which is the main method that will be called when the tool is invoked by an agent.

    ## Step-by-step Guide

    To create a custom tool, typically you need to follow these steps:

    <Steps>
      <Step title="Add Import Statements">
        On top of your tool file, import the necessary modules and classes.

        ```python theme={null}
        from agency_swarm.tools import BaseTool
        from pydantic import Field, model_validator
        # ... other imports
        ```
      </Step>

      <Step title="Define the Tool Class and Docstring">
        Create a new class that inherits from `BaseTool`. Write a clear docstring describing the tool's purpose. **This docstring is crucial as it helps agents understand how to use the tool.**

        ```python theme={null}
        class Calculator(BaseTool):
            """
            A simple calculator tool that evaluates mathematical expressions.
            """
        ```
      </Step>

      <Step title="Define Input Fields">
        Use Pydantic fields to define the inputs your tool will accept.

        ```python theme={null}
        expression: str = Field(..., description="The mathematical expression to evaluate.")
        ```

        <Accordion title="Custom Validation Logic (Optional)" icon="hammer">
          You can use [Pydantic's validators](https://docs.pydantic.dev/latest/concepts/validators/) to verify the inputs. This can be extremely effective to avoid hallucinations or other errors in production.

          ```python theme={null}
          @model_validator(mode="after")
          def validate_expression(self):
              if self.expression.endswith("/0"):
                  raise ValueError("Division by zero is not permitted")
          ```
        </Accordion>
      </Step>

      <Step title="Implement the run Method">
        Add the functionality that will be executed when the tool is called.

        ```python theme={null}
        async def run(self):
            # Implement the tool's functionality
            result = eval(self.expression)
            return str(result)
        ```

        The `run` method should return a string, which is the tool's output that the agent will see and use in its response.
      </Step>

      <Step title="Test the Tool Independently">
        Test the tool independently to ensure it behaves as expected. We recommend adding a `if __name__ == "__main__":` block at the end of the tool file:

        ```python theme={null}
        import asyncio

        if __name__ == "__main__":
            calc = Calculator(expression="2 + 2 * 3")
            print(asyncio.run(calc.run()))  # Output should be '8'
        ```
      </Step>

      <Step title="Add the Tool to an Agent">
        After your tool works as expected, simply add it to an agent's list of `tools`.

        ```python theme={null}
        from agency_swarm import Agent
        from .tools.calculator import Calculator

        agent = Agent(
            name="MathAgent",
            tools=[Calculator],
            # Other agent parameters
        )
        ```

        <Accordion title="Using tools folder" icon="folder">
          Alternatively, you can simply place the tool file in the `tools_folder` directory and it will be automatically added to the agent.

          ```python theme={null}
          from agency_swarm import Agent
          agent = Agent(
              name="MathAgent",
              tools_folder="./tools",
              # Other agent parameters
          )
          ```

          <Note>
            Each file in the `tools_folder` should contain a class that is named exactly the same as the file name. For example, `Calculator.py` should contain a `Calculator` class.
          </Note>
        </Accordion>
      </Step>
    </Steps>

    ## Full Code Example

    Below is the full code example for a calculator tool above.

    ```python theme={null}
    # calculator.py
    from agency_swarm.tools import BaseTool
    from pydantic import Field, model_validator

    class Calculator(BaseTool):
        """
        A simple calculator tool that evaluates mathematical expressions.
        """
        expression: str = Field(..., description="The mathematical expression to evaluate.")

        @model_validator(mode="after")
        def validate_expression(self):
            if self.expression.endswith("/0"):
                raise ValueError("Division by zero is not permitted")

        async def run(self):
            result = eval(self.expression)
            return str(result)

    if __name__ == "__main__":
        import asyncio

        calc = Calculator(expression="2 + 2 * 3")
        print(asyncio.run(calc.run()))  # Output should be '8'
    ```
  </Tab>

  <Tab title="FunctionTool">
    ## Step-by-step Guide

    <Steps>
      <Step title="Add Import Statements">
        Import the necessary modules for the new function-based approach.

        ```python theme={null}
        from agency_swarm import function_tool, RunContextWrapper
        from pydantic import BaseModel, Field, field_validator
        from agency_swarm import MasterContext
        ```
      </Step>

      <Step title="Define Args Schema">
        Create a Pydantic model to define your tool's input parameters.

        ```python theme={null}
        class CalculatorArgs(BaseModel):
            expression: str = Field(..., description="The mathematical expression to evaluate")

            @field_validator("expression")
            @classmethod
            def validate_expression(cls, v):
                if "/0" in v:
                    raise ValueError("Division by zero is not permitted")
                return v
        ```
      </Step>

      <Step title="Create the Tool Function">
        Define an async function with the `@function_tool` decorator.

        ```python theme={null}
        @function_tool
        async def calculator_tool(ctx: RunContextWrapper[MasterContext], args: CalculatorArgs) -> str:
            """
            A calculator tool that evaluates mathematical expressions.
            Use this when you need to perform mathematical calculations.
            """
            # Access shared context if needed
            calculation_count = ctx.context.get("calculations", 0)
            ctx.context.set("calculations", calculation_count + 1)

            # Perform the calculation
            result = eval(args.expression)
            return f"Result: {result}"
        ```

        <Note>
          All parameters of the function tool, except for `ctx`, are treated as input parameters and included in the tool’s schema.

          For example, in the tool above, the input model `CalculatorArgs` is passed as the `args` parameter, so the input JSON would look like:

          ```
          {"args": {"expression": "input_expression"}}
          ```

          `args` is an example name, you can name your input parameters however you like, and you may define more than one input parameter if needed.
        </Note>

        <Note>
          This example mentions tool context, which can be used as a shared storage for all agents and tools.
          For more info on agent context, refer to [this page](/additional-features/agency-context)
        </Note>
      </Step>

      <Step title="Test the Tool">
        Test your tool function independently.

        ```python theme={null}
        if __name__ == "__main__":
            import asyncio
            import json

            async def test_tool():
                ctx = MasterContext(user_context={"calculations": 1}, thread_manager=None, agents={})
                run_ctx = RunContextWrapper(context=ctx)

                args = CalculatorArgs(expression="2 + 2 * 3")
                # Wrap in args to comply with oai expected inputs
                args_json = {"args": args.model_dump()}

                result = await calculator_tool.on_invoke_tool(run_ctx, json.dumps(args_json))
                print(result)

            asyncio.run(test_tool())
        ```
      </Step>

      <Step title="Add Tool to Agent">
        Pass the function directly to the agent's tools list.

        ```python theme={null}
        from agency_swarm import Agent

        agent = Agent(
            name="MathAgent",
            instructions="You are a helpful math assistant",
            tools=[calculator_tool],  # Pass function directly
            model="gpt-5.4-mini"
        )
        ```
      </Step>
    </Steps>

    ## Full Code Example

    ```python theme={null}
    # calculator_tool.py
    from agency_swarm import function_tool, RunContextWrapper
    from pydantic import BaseModel, Field, field_validator
    from agency_swarm import MasterContext

    class CalculatorArgs(BaseModel):
        expression: str = Field(..., description="The mathematical expression to evaluate")

        @field_validator("expression")
        @classmethod
        def validate_expression(cls, v):
            if "/0" in v:
                raise ValueError("Division by zero is not permitted")
            return v

    @function_tool
    async def calculator_tool(ctx: RunContextWrapper[MasterContext], args: CalculatorArgs) -> str:
        """
        A calculator tool that evaluates mathematical expressions.
        Use this when you need to perform mathematical calculations.
        """
        # Access shared context if needed
        calculation_count = ctx.context.get("calculations", 0)
        ctx.context.set("calculations", calculation_count + 1)

        # Perform the calculation
        result = eval(args.expression)
        return f"Result: {result} (Calculation #{calculation_count + 1})"

    if __name__ == "__main__":
        import asyncio
        import json

        async def test_tool():
            ctx = MasterContext(user_context={"calculations": 1}, thread_manager=None, agents={})
            run_ctx = RunContextWrapper(context=ctx)
            args = CalculatorArgs(expression="2 + 2 * 3")
            args_json = {"args": args.model_dump()}
            result = await calculator_tool.on_invoke_tool(run_ctx, json.dumps(args_json))
            print(result)

        asyncio.run(test_tool())
    ```
  </Tab>
</Tabs>

## Next Steps

* Checkout [Best Practices & Tips](/core-framework/tools/custom-tools/best-practices)
* Learn why [PyDantic is all you need](/core-framework/tools/custom-tools/pydantic-is-all-you-need)
* Learn how to [stream events from tools](/additional-features/streaming#streaming-from-tools)
