Skip to content

Commit 980d5ab

Browse files
committed
docs(custom-tools): improve docs for creating custom tools
1 parent f6e919c commit 980d5ab

File tree

5 files changed

+135
-57
lines changed

5 files changed

+135
-57
lines changed

docs/griptape-framework/tools/custom-tools/index.md

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ Building your own tools is easy with Griptape!
55
Tools are nothing more than Python classes that inherit from [BaseTool](../../../reference/griptape/tools/base_tool.md).
66
Each method in the class is decorated with an [activity](../../../reference/griptape/utils/decorators.md#griptape.utils.decorators.activity) decorator which informs the LLM how and when it should use that Tool Activity.
77

8-
## Random Number Generator Tool
8+
## Random Tool
99

10-
Here is a simple random number generator Tool:
10+
Here is a simple Tool for performing various operations with the `random` module.
1111

1212
=== "Code"
1313

@@ -21,14 +21,52 @@ Here is a simple random number generator Tool:
2121
--8<-- "docs/griptape-framework/tools/custom-tools/logs/index_2.txt"
2222
```
2323

24-
Check out other [Griptape Tools](https://github.com/griptape-ai/griptape/tree/main/griptape/tools) to learn more about tool implementation details.
24+
### Tool Activities
25+
26+
Activities are actions an LLM can perform with a various Tool. They pair a natural language description with some code to execute. Some examples:
27+
28+
- "Can be used to create a random number" -> `generate_rand_num`
29+
- "Can be used to select a random item from a list" -> `select_rand_item`
30+
31+
Technically, each Activity is a method in the tool class that's decorated with the [activity](../../../reference/griptape/utils/decorators.md#griptape.utils.decorators.activity) decorator.
32+
33+
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](../../../reference/griptape/mixins/activity_mixin.md#griptape.mixins.activity_mixin.ActivityMixin.to_activity_json_schema).
34+
35+
```python
36+
--8<-- "docs/griptape-framework/tools/custom-tools/src/to_json_schema.py"
37+
```
38+
39+
Each Activity takes a `config` keyword argument that contains the configuration for the Activity. The configuration can contain:
40+
41+
- `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.
42+
- `schema` (optional): An optional instance of `Schema` that defines the input values to the Activity. This field should be omitted if the Activity does not accept any input values.
43+
44+
### Activity Methods
45+
46+
Activity decorated methods should return an [Artifact](../../data/artifacts.md), though Griptape will automatically convert any other return type to an [InfoArtifact](../../data/artifacts.md#info).
47+
48+
If an Activity's config declares a `schema`, the method should declare parameters using one of the following styles:
49+
50+
- Standard python keyword arguments. See `generate_random_number`.
51+
- `values` (dict): A dictionary of the input values to the Activity. See `select_random_item`.
52+
- `params` (dict): A dictionary that will contain a single key, `values`. See `sample_list`. Other keys may be added in the future, though generally, you should prefer using one of the other styles.
53+
54+
!!! warning
55+
56+
Do not name any schema fields as `values` or `params`. They are reserved for the Activity method signature.
2557

2658
## Tool Dependencies
2759

2860
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.
2961
To start, create a directory for your Tool inside your project. The directory must have the following structure:
3062

31-
- `tool.py` file with a tool Python class.
32-
- `requirements.txt` file with tool Python dependencies.
63+
```
64+
griptape/tools/calculator/
65+
├── __init__.py
66+
├── requirements.txt # file with tool Python dependencies
67+
└── tool.py # file with tool Python class
68+
```
3369

3470
That's it! Import and use your Tool in your project as you would with any other Griptape Tool.
71+
72+
Check out other [Griptape Tools](https://github.com/griptape-ai/griptape/tree/main/griptape/tools) to learn more about tool implementation details.

docs/griptape-framework/tools/custom-tools/src/index_1.py

Lines changed: 0 additions & 20 deletions
This file was deleted.

docs/griptape-framework/tools/custom-tools/src/index_2.py

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,102 @@
33
from schema import Literal, Optional, Schema
44

55
from griptape.artifacts import TextArtifact
6+
from griptape.artifacts.list_artifact import ListArtifact
67
from griptape.structures import Agent
78
from griptape.tools import BaseTool
89
from griptape.utils.decorators import activity
910

1011

11-
class RandomNumberGenerator(BaseTool):
12+
class RandomTool(BaseTool):
1213
@activity(
1314
config={
1415
"description": "Can be used to generate random numbers",
16+
}
17+
)
18+
def generate_rand_num(self) -> TextArtifact:
19+
"""Generate a random number between 0 and 1.
20+
21+
Returns:
22+
TextArtifact: The random number as a Text Artifact.
23+
"""
24+
return TextArtifact(random.random())
25+
26+
@activity(
27+
config={
28+
"description": "Can be used to generate random numbers",
29+
"schema": Schema(
30+
{
31+
Literal("start", description="The start of the rand range, inclusive."): int,
32+
Literal("stop", description="The start of the rand range, exclusive."): int,
33+
}
34+
),
35+
}
36+
)
37+
def generate_rand_range(self, start: int, stop: int) -> TextArtifact:
38+
"""Generate a random number between start and stop.
39+
40+
Args:
41+
start (int): The starting number.
42+
stop (int): The ending number.
43+
44+
Returns:
45+
TextArtifact: The random number as a Text Artifact.
46+
"""
47+
return TextArtifact(random.randrange(start, stop))
48+
49+
@activity(
50+
config={
51+
"description": "Can be used to select a random item from a list",
1552
"schema": Schema(
16-
{Optional(Literal("decimals", description="Number of decimals to round the random number to")): int}
53+
{
54+
"items": [str],
55+
}
1756
),
1857
}
1958
)
20-
def generate(self, params: dict) -> TextArtifact:
21-
return TextArtifact(str(round(random.random(), params["values"].get("decimals"))))
59+
def select_rand_item(self, *, values: dict) -> TextArtifact:
60+
"""Select a random item from a list.
61+
62+
Args:
63+
values (dict): The values declared by the schema.
64+
65+
Returns:
66+
TextArtifact: The selected item as a Text Artifact.
67+
"""
68+
items = values["items"]
69+
70+
return TextArtifact(random.choice(items))
71+
72+
@activity(
73+
config={
74+
"description": "Can be used to sample a list",
75+
"schema": Schema(
76+
{
77+
"items": [str],
78+
Optional("k"): int,
79+
}
80+
),
81+
}
82+
)
83+
def sample_list(self, *, params: dict) -> ListArtifact[TextArtifact]:
84+
"""Shuffle a list.
85+
86+
Args:
87+
params (dict): A dictionary containing a key, `values`, which contains the values declared by the schema.
88+
89+
Returns:
90+
TextArtifact: The sampled list as a List Artifact of Text Artifacts.
91+
"""
92+
values = params["values"]
93+
94+
items = values["items"]
95+
k = values.get("k", 5)
96+
97+
sampled = random.sample(items, k)
2298

99+
return ListArtifact([TextArtifact(item) for item in sampled])
23100

24-
rng_tool = RandomNumberGenerator()
25101

26-
agent = Agent(tools=[rng_tool])
102+
agent = Agent(tools=[RandomTool()])
27103

28-
agent.run("generate a random number rounded to 5 decimal places")
104+
agent.run("Generate a number between 5 and 10, then generate that many animals, sample 3, then randomly select one.")
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from rich.pretty import pprint
2+
3+
from griptape.tools import CalculatorTool
4+
5+
tool = CalculatorTool()
6+
7+
pprint(tool.to_activity_json_schema(tool.calculate, "Calculate Schema"))

docs/griptape-framework/tools/index.md

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,9 @@ Many of our [Prompt Drivers](../drivers/prompt-drivers.md) leverage the native f
88

99
You can switch between these strategies by setting `use_native_tools` to `True` (LLM-native tool calling) or `False` (Griptape tool calling) on your [Prompt Driver](../drivers/prompt-drivers.md).
1010

11-
## Griptape Tools
11+
## Custom Tools
1212

13-
Griptape tools are special Python classes that LLMs can use to accomplish specific goals. A tool consists of multiple "activities," each represented by a function decorated with `@activity`. This decorator provides context to the LLM through descriptions and defines the input schema that the LLM must follow.
14-
15-
When a function is decorated with `@activity`, the decorator injects keyword arguments into the function according to the schema. Additionally, Griptape provides two special keyword arguments:
16-
17-
- `params: dict`
18-
- `values: dict`
19-
20-
!!! info
21-
22-
If your schema defines any parameters named `params` or `values`, they will be overwritten by the Griptape-provided arguments.
23-
24-
Here is an example of a custom tool for generating a random number:
25-
26-
=== "Code"
27-
28-
```python
29-
--8<-- "docs/griptape-framework/tools/src/index_1.py"
30-
```
31-
32-
=== "Logs"
33-
34-
```text
35-
--8<-- "docs/griptape-framework/tools/logs/index_1.txt"
36-
```
13+
See [Custom Tools](./custom-tools/index.md) for more information on building your own tools.
3714

3815
## Tool Output and Task Memory
3916

0 commit comments

Comments
 (0)