Defining Tools

View as MarkdownOpen in Claude

Tools are Python methods marked with @function_tool. The SDK automatically generates the schema the LLM needs based on your function’s signature and docstring.

Basic Tool

The @function_tool() decorator marks a method as callable by the LLM.

1from smallestai.atoms.agent.tools import function_tool
2
3class MyAgent(OutputAgentNode):
4 @function_tool()
5 def get_order_status(self, order_id: str):
6 """Get the current status of an order.
7
8 Args:
9 order_id: The order ID, e.g. "ORD-12345"
10 """
11 order = self.db.get_order(order_id)
12 return {"status": order.status, "eta": order.eta}

The LLM sees this as a callable function with a description and typed parameters.

How It Works

  1. @function_tool() marks the method as a tool
  2. Type hints tell the LLM what types to pass
  3. Docstring explains when and how to use the tool
  4. Return value is sent back to the LLM

Docstring Format

The LLM reads your docstring to understand when to call the tool.

1@function_tool()
2def search_products(self, query: str, category: str = None):
3 """Search the product catalog.
4
5 Use when a customer asks about products or pricing.
6
7 Args:
8 query: Search terms, e.g. "wireless headphones"
9 category: Optional filter, e.g. "electronics"
10 """
11 return self.catalog.search(query, category=category)
PartPurpose
First lineBrief description (shown to LLM)
Second paragraphWhen to use this tool
ArgsParameter descriptions

Parameter Types

Type hints define the schema the LLM uses to pass arguments.

1@function_tool()
2def example(
3 self,
4 text: str, # String
5 count: int, # Integer
6 price: float, # Decimal
7 enabled: bool, # Boolean
8 items: list, # Array
9 config: dict, # Object
10 priority: str = "normal" # Optional with default
11):
12 """Example with various types."""
13 pass

Enum Parameters

Constrain values with Literal from typing.

1from typing import Literal
2
3@function_tool()
4def set_priority(self, ticket_id: str, level: Literal["low", "medium", "high"]):
5 """Set ticket priority.
6
7 Args:
8 ticket_id: Ticket ID
9 level: Priority level
10 """
11 return self.tickets.update(ticket_id, level)

Async Tools

Prefix with async def for database calls, HTTP requests, or other I/O.

1@function_tool()
2async def search_database(self, query: str):
3 """Search the customer database.
4
5 Args:
6 query: Customer name or email
7 """
8 results = await self.db.search(query)
9 return [{"name": r.name, "email": r.email} for r in results]

Accessing Session State

Tools can read self. attributes for user data, DB connections, etc.

1class MyAgent(OutputAgentNode):
2 def __init__(self):
3 super().__init__(name="my-agent")
4 self.db = Database()
5 self.user_tier = "standard"
6
7 @function_tool()
8 def get_discount(self, product_id: str):
9 """Get available discount for a product.
10
11 Args:
12 product_id: Product ID
13 """
14 # Access agent state
15 if self.user_tier == "premium":
16 return {"discount": 20}
17 return {"discount": 0}

Error Handling

Return {"error": "message"} so the LLM can respond gracefully.

1@function_tool()
2def get_order(self, order_id: str):
3 """Get order details.
4
5 Args:
6 order_id: Order ID like "ORD-12345"
7 """
8 try:
9 order = self.db.get_order(order_id)
10 if not order:
11 return {"error": "Order not found"}
12 return order.to_dict()
13 except Exception as e:
14 return {"error": "Unable to retrieve order"}

The LLM will say something like “I couldn’t find that order” instead of the conversation breaking.


Tips

The LLM reads tool descriptions every turn. Shorter = fewer tokens = faster.

Good: get_order_status, create_appointment, search_products. Bad: order, handle_booking.

Tell the LLM when to use tools: “Use get_order_status when the user asks about an order.”