Introduction to tools
Understand tools at Portia and add your own.
TL;DR
- Tools are used by LLMs as part of their response to indicate that a particular software service or data store is required to fulfil a user's query.
- We represent a tool with the
Tool
class (SDK reference ↗). The LLM parses the tool properties, namely its name, description, input and output schemas to determine whether the tool is relevant to its response and how to invoke it.
Tools at Portia
A tool is a natural language wrapper around a data source or software service that the LLM can point to in order to accomplish tasks beyond its inherent capabilities. As a simple example, an LLM could respond to the user query email avrana@kern.ai and tell her that spiders are now sentient
by suggesting a call to the email sending service wrapped in the send_email
tool.
We represent a tool with the Tool
class (SDK reference ↗). Let's look at the weather_tool
provided with our SDK as an example:
weather_tool.py
"""Tool to get the weather from openweathermap."""
import os
import httpx
from pydantic import BaseModel, Field
from portia.errors import ToolHardError, ToolSoftError
from portia.tool import Tool, ToolRunContext
class WeatherToolSchema(BaseModel):
"""Input for WeatherTool."""
city: str = Field(..., description="The city to get the weather for")
class WeatherTool(Tool[str]):
"""Get the weather for a given city."""
id: str = "weather_tool"
name: str = "Weather Tool"
description: str = "Get the weather for a given city"
args_schema: type[BaseModel] = WeatherToolSchema
output_schema: tuple[str, str] = ("str", "String output of the weather with temp and city")
def run(self, _: ToolRunContext, city: str) -> str:
"""Run the WeatherTool."""
api_key = os.getenv("OPENWEATHERMAP_API_KEY")
if not api_key or api_key == "":
raise ToolHardError("OPENWEATHERMAP_API_KEY is required")
url = (
f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units=metric"
)
response = httpx.get(url)
response.raise_for_status()
data = response.json()
if "weather" not in data:
raise ToolSoftError(f"No data found for: {city}")
weather = data["weather"][0]["description"]
if "main" not in data:
raise ToolSoftError(f"No main data found for city: {city}")
temp = data["main"]["temp"]
return f"The current weather in {city} is {weather} with a temperature of {temp}°C."
Here are the key points to look out for:
- All properties of a tool are parsed by the LLM to determine whether that tool is salient to a user's query and should therefore be invoked in response to it.
- The
args_schema
property describes the tool inputs. This is important to help the LLM understand what parameters it can invoke a tool with. - The
output_schema
property describes the expected output of the tool. This helps the LLM know what to expect from the tool and informs its sequencing decisions for tool calls as well. - Every tool has a
run
function which is the actual tool implementation. The method always takesToolRunContext
which is contextual information implicitly passed by Portia. We will look into this more deeply in a future section (Manage execution context ↗). The only thing to note now is that you have to include this argument and always import the underlying dependency.
Track tool calls in logs
You can track tool calls live as they occur through the logs by setting default_log_level
to DEBUG in the Config
of your Portia
instance (Manage logging ↗).