Overview

2 Working with Tools

This chapter introduces the infrastructure needed to make tools a reliable part of an LLM agent framework. It explains why tools must be described in a way the model can understand, and why the tool-calling flow should be standardized so requests, executions, and returned results all follow the same pattern. To support that goal, the chapter builds a small framework around a base tool interface and a pair of data models that represent tool-call inputs and outputs.

The core abstraction is an abstract base class that every tool must follow, with standard attributes for the tool’s name, description, and parameter schema, plus a callable execution method. The chapter also adds structured objects for tool requests and tool results, using Pydantic models to keep data validated and easy to pass around. A concrete Hailstone example shows how a tool can be implemented directly, including a JSON Schema describing its input and a callable method that performs the computation and returns a result object.

From there, the chapter expands the design in two directions. First, it adds an asynchronous version of the base tool for workflows that wait on external services without blocking the rest of the application. Second, it introduces wrapper classes that turn ordinary Python functions into tools automatically: one version builds schemas from function signatures and validates arguments before execution, while another uses Pydantic for stronger schema generation and validation. Overall, the chapter focuses on making tools consistent, reusable, and easy for LLMs and agents to invoke safely.

The focus of the current chapter, through the lens of our build plan introduced in Chapter 1. Before we can build an LLM agent, we first need to properly define tools and how they can be used within our framework.
Each tool inherits from the BaseTool class, allowing the LLM agent to access the textual descriptions and execute the logic of each tool in the same manner.
Incorporating our new classes—BaseTool, ToolCall, and ToolCallResult—into the tool-calling process, first shown in Chapter 1.
The UML class diagrams for BaseTool, ToolCall and ToolCallResult.
Creating a ToolCall object from an LLM’s natural language tool-call request. Since the web-search tool is a BaseTool, we must first convert the request into a ToolCall object before invoking it.
Creating a ToolCallResult object from the selected tool’s execution, handling both successful and failed executions.
Revisiting the tool-equipping process. With a BaseTool, we can use its attributes to fill in the values required for textual descriptions that are passed to the LLM.
The Hailstone tool performs a Hailstone step on a given positive integer. By implementing the Hailstone tool as a subclass of BaseTool, we can use it within the tool-call process for LLMs.
Comparing synchronous and asynchronous tool executions.
The UML class diagram for AsyncBaseTool, which shows a nearly identical structure to the BaseTool class.
Wrapping Python functions with SimpleFunctionTool so that they can be used as tools for LLMs and LLM agents.
UML class diagrams for SimpleFunctionTool and AsyncSimpleFunctionTool.
A visual breakdown of the three steps involved in the implementation of the helper function_signature_to_json_schema.
Executing a SimpleFunctionTool involves validating the parameter data of the ToolCall object and subsequently delegating to the wrapped function.
Wrapping an asynchronous Python function to create an AsyncBaseTool object automatically.

Summary

  • To build an LLM agent, we need to build the required infrastructure, including abstractions representing tools that they work with to perform tasks.
  • LLMs require the following information to be able to make a tool call request for a given tool: its name, a description of its functionality, and a JSON Schema of its input parameters.
  • A BaseTool object executes a single ToolCall and returns a single ToolCallResult object.
  • The AsyncBaseTool class is designed for tools that execute their logic asynchronously.
  • The SimpleFunctionTool is a wrapper class for turning Python functions into a BaseTool objects.
  • The AsyncSimpleFunctionTool is a wrapper class for turning async Python functions into a AsyncBaseTool objects.
  • The PydanticFunctionTool is similar to the SimpleFunctionTool, but wraps a special function we called PydanticFunction instead. These functions get passed their input parameters for logic execution through a ~pydantic.BaseModel.

FAQ

What is the main goal of Chapter 2, “Working with Tools”?The chapter focuses on building the tool infrastructure needed for an LLM agent framework. It introduces a standard base class for tools, the data structures needed to represent tool calls and results, and helpers for turning Python functions into tools that LLMs can use.
Why do LLM agents need tools?Tools expand what LLM agents can do by letting them perform actions such as web searches, plotting data, or executing code. They make agents more capable and useful for tasks that require external functionality beyond text generation.
What problem does a standard tool interface solve?A standard tool interface makes tools easier to use consistently, even when they perform very different tasks. It reduces confusion for the LLM, simplifies execution, and helps the framework handle all tools in a uniform way.
What is the purpose of the BaseTool class?BaseTool acts as a blueprint for all tools in the framework. It requires common attributes like name, description, and parameters_json_schema, plus a __call__() method for executing the tool.
What are ToolCall and ToolCallResult used for?ToolCall represents the input to a tool execution, including the tool name and its arguments. ToolCallResult represents the output, including the result content, a link back to the original call, and an error flag.
Why does ToolCall include an automatically generated id_ field?The id_ field uniquely identifies each tool call so the result can be matched back to the correct request. It is generated automatically, so callers do not need to provide it manually.
What is the difference between BaseTool and AsyncBaseTool?BaseTool is synchronous, so its __call__() method runs in a blocking way. AsyncBaseTool is designed for asynchronous execution, allowing tools to wait on external operations without blocking the rest of the application.
What does SimpleFunctionTool do?SimpleFunctionTool wraps a normal Python function and turns it into a tool. It automatically derives the tool name, description, JSON schema for parameters, and execution behavior from the function.
How does SimpleFunctionTool generate a JSON Schema from a function?It inspects the function signature, maps Python types to JSON Schema types, and marks parameters as required when they have no default values. The resulting schema describes the tool’s expected arguments for the LLM.
Why use PydanticFunctionTool instead of SimpleFunctionTool?PydanticFunctionTool uses Pydantic’s built-in schema generation and validation, which is more robust than a custom from-scratch approach. It is useful when you want stronger data validation and easier JSON Schema support for function-based tools.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Build a Multi-Agent System (from Scratch) ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Build a Multi-Agent System (from Scratch) ebook for free