Custom Tools
Overview
Building your own tools is easy with Griptape!
Tools are nothing more than Python classes that inherit from BaseTool. Each method in the class is decorated with an activity decorator which informs the LLM how and when it should use that Tool Activity.
Random Tool
Here is a simple Tool for performing various operations with the random
module.
import random
from schema import Literal, Optional, Schema
from griptape.artifacts import TextArtifact
from griptape.artifacts.list_artifact import ListArtifact
from griptape.structures import Agent
from griptape.tools import BaseTool
from griptape.utils.decorators import activity
class RandomTool(BaseTool):
@activity(
config={
"description": "Can be used to generate random numbers",
}
)
def generate_rand_num(self) -> TextArtifact:
"""Generate a random number between 0 and 1.
Returns:
TextArtifact: The random number as a Text Artifact.
"""
return TextArtifact(random.random())
@activity(
config={
"description": "Can be used to generate random numbers",
"schema": Schema(
{
Literal("start", description="The start of the rand range, inclusive."): int,
Literal("stop", description="The start of the rand range, exclusive."): int,
}
),
}
)
def generate_rand_range(self, start: int, stop: int) -> TextArtifact:
"""Generate a random number between start and stop.
Args:
start (int): The starting number.
stop (int): The ending number.
Returns:
TextArtifact: The random number as a Text Artifact.
"""
return TextArtifact(random.randrange(start, stop))
@activity(
config={
"description": "Can be used to select a random item from a list",
"schema": Schema(
{
"items": [str],
}
),
}
)
def select_rand_item(self, *, values: dict) -> TextArtifact:
"""Select a random item from a list.
Args:
values (dict): The values declared by the schema.
Returns:
TextArtifact: The selected item as a Text Artifact.
"""
items = values["items"]
return TextArtifact(random.choice(items))
@activity(
config={
"description": "Can be used to sample a list",
"schema": Schema(
{
"items": [str],
Optional("k"): int,
}
),
}
)
def sample_list(self, *, params: dict) -> ListArtifact[TextArtifact]:
"""Shuffle a list.
Args:
params (dict): A dictionary containing a key, `values`, which contains the values declared by the schema.
Returns:
TextArtifact: The sampled list as a List Artifact of Text Artifacts.
"""
values = params["values"]
items = values["items"]
k = values.get("k", 5)
sampled = random.sample(items, k)
return ListArtifact([TextArtifact(item) for item in sampled])
agent = Agent(tools=[RandomTool()])
agent.run("Generate a number between 5 and 10, then generate that many animals, sample 3, then randomly select one.")
Tool Activities
Activities are actions an LLM can perform with a various Tool. They pair a natural language description with some code to execute. Some examples:
- "Can be used to create a random number" ->
generate_rand_num
- "Can be used to select a random item from a list" ->
select_rand_item
Technically, each Activity is a method in the tool class that's decorated with the activity decorator.
Griptape will convert the Tool and its Activities into the appropriate format for the LLM to use. You can see the schema for a particular Activity by calling to_json_schema.
{
│ 'type': 'object',
│ 'properties': {
│ │ 'values': {
│ │ │ 'type': 'object',
│ │ │ 'properties': {
│ │ │ │ 'expression': {
│ │ │ │ │ 'description': "Arithmetic expression parsable in pure Python. Single line only. Don't use variables. Don't use any imports or external libraries",
│ │ │ │ │ 'type': 'string'
│ │ │ │ }
│ │ │ },
│ │ │ 'required': ['expression'],
│ │ │ 'additionalProperties': False
│ │ }
│ },
│ 'required': ['values'],
│ 'additionalProperties': False,
│ '$id': 'Calculate Schema',
│ '$schema': 'http://json-schema.org/draft-07/schema#'
}
Each Activity takes a config
keyword argument that contains the configuration for the Activity. The configuration can contain:
description
(str): A plain text description of the Activity. Ensure that the description is clear and concise as it will help inform the LLM of when to pick this Activity.schema
(optional): An optional instance ofSchema
that defines the input values to the Activity. This field should be omitted if the Activity does not accept any input values.
Activity Methods
Activity decorated methods should return an Artifact, though Griptape will automatically convert any other return type to an InfoArtifact.
If an Activity's config declares a schema
, the method should declare parameters using one of the following styles:
- Standard python keyword arguments. See
generate_random_number
. values
(dict): A dictionary of the input values to the Activity. Seeselect_random_item
.params
(dict): A dictionary that will contain a single key,values
. Seesample_list
. Other keys may be added in the future, though generally, you should prefer using one of the other styles.
Warning
Do not name any schema fields as values
or params
. They are reserved for the Activity method signature.
Tool Dependencies
Each Tool can also have its own dependencies. You can specify them in a requirements.txt
file in the tool directory and Griptape will install them during Tool execution.
To start, create a directory for your Tool inside your project. The directory must have the following structure:
griptape/tools/calculator/
├── __init__.py
├── requirements.txt # file with tool Python dependencies
└── tool.py # file with tool Python class
That's it! Import and use your Tool in your project as you would with any other Griptape Tool.
Check out other Griptape Tools to learn more about tool implementation details.