|
2 | 2 | title: Tools |
3 | 3 | --- |
4 | 4 |
|
5 | | -//TODO: |
| 5 | +A 'Tool' is a general term for a function or logic that can be executed by an AI |
| 6 | +model. They can be user defined or pre-defined by the provider. Tools are provided |
| 7 | +to the AI model's context as per the developer's needs.The AI model can then use the |
| 8 | +provided tools to perform specific queries to aid in text generation or actions to |
| 9 | +be taken externally. Most common tools include the following searching the web, |
| 10 | +querying a public API, executing a shell command, and more. |
| 11 | + |
| 12 | +Here is the recommended and less verbose way to define a tool. It allows you to annotate native |
| 13 | +Rust functions with the `#[tool]` macro, which will generate a `Tool` struct for you. |
| 14 | + |
| 15 | +```rust |
| 16 | +use crate::core::{tool, Tool}; |
| 17 | + |
| 18 | +#[tool] |
| 19 | +/// Get the weather information given a location |
| 20 | +pub fn get_weather(location: String) { |
| 21 | + let weather = match location.as_str() { |
| 22 | + // Some logic to query a weather API |
| 23 | + "New York" => 75, |
| 24 | + "Tokyo" => 80, |
| 25 | + _ => 70, |
| 26 | + }; |
| 27 | + Ok(weather.to_string()) |
| 28 | +} |
| 29 | +``` |
| 30 | + |
| 31 | +A tool has 4 components: |
| 32 | + |
| 33 | +- **name**: It is used to identify the tool in the AI model. Make sure it is unique and describes |
| 34 | +what the tool does well. The name of the tool in this case is `get_weather`. |
| 35 | + |
| 36 | +- **description**: This is a brief description of what the tool does. It is used to |
| 37 | +help the AI model understand what the tool does and how to use it. The function's doc comment |
| 38 | +as the description. you can use rust style documentation with examples for few-shot prompting |
| 39 | + |
| 40 | +- **arguments**: This is the schema of the input that the AI model will use to generate |
| 41 | +inputs for the tool. It uses the [schemars](https://docs.rs/schemars/latest/schemars/) crate |
| 42 | +to define the [json schema](https://json-schema.org/) of the input. The function's arguments |
| 43 | +are serialized into json schema in which the AI model will use to generate inputs. |
| 44 | +just make sure |
| 45 | +the arguments implement the `schemars::JsonSchema` trait or are natively supported |
| 46 | +by the `schemars` crate. |
| 47 | + |
| 48 | +- **body**: This is the logic that will be called when the AI model calls the tool. it |
| 49 | +takes a single argument of type `serde_json::Value` which is the json input provided by the AI model. the function should return a `Result<String, String>` |
| 50 | +which is the output of the tool. If the tool fails, you can return an error message as `Err(String)` which can |
| 51 | +also be helpful for the AI model to understand what went wrong. |
| 52 | + |
| 53 | +You can optionally override the `name` and `description` of the tool by passing them as arguments to the `#[tool]` macro. |
| 54 | + |
| 55 | +```rust |
| 56 | +use crate::core::{tool, Tool}; |
| 57 | + |
| 58 | +#[tool(name = "get-weather", description = "Get the weather information given a location")] |
| 59 | +/// A tool that returns the weather information given a location |
| 60 | +pub fn get_weather(location: String) { |
| 61 | + let weather = match location.as_str() { |
| 62 | + // Some logic to query a weather API |
| 63 | + "New York" => 75, |
| 64 | + "Tokyo" => 80, |
| 65 | + _ => 70, |
| 66 | + }; |
| 67 | + Ok(weather.to_string()) |
| 68 | +} |
| 69 | +``` |
| 70 | + |
| 71 | +This will make the tool name and description configurable. name will be `get-weather` and description will be `Get the weather information given a location`. |
| 72 | + |
| 73 | + |
| 74 | +## Using the structs |
| 75 | + |
| 76 | +You can define your own tools in aisdk by instantiating the `Tool` and related structs and passing |
| 77 | +it to one of the AI model text generation builders. |
| 78 | + |
| 79 | +```rust |
| 80 | +use super::{Tool, ToolExecute}; |
| 81 | +use serde_json::Value; |
| 82 | + |
| 83 | +// define tool function body, should return Result<String, String> |
| 84 | +#[allow(unused_variables)] |
| 85 | +let func = ToolExecute::new(Box::new(|inp: Value| { |
| 86 | + // Ai SDK will pass in a json object with the following structure |
| 87 | + // ```json |
| 88 | + // { |
| 89 | + // "location": "New York" |
| 90 | + // } |
| 91 | + // ``` |
| 92 | + let location = inp.get("location").unwrap(); |
| 93 | + Ok(format!("Cloudy")) |
| 94 | +})); |
| 95 | + |
| 96 | +// define tool input structure |
| 97 | +#[derive(schemars::JsonSchema, Debug)] |
| 98 | +#[allow(dead_code)] |
| 99 | +struct ToolInput { |
| 100 | + location: String, |
| 101 | +} |
| 102 | + |
| 103 | +// change tool arguments to json schema |
| 104 | +// Which will be similar to the following |
| 105 | +// ```json |
| 106 | +// "properties": { |
| 107 | +// "location": { |
| 108 | +// "type": "string" |
| 109 | +// } |
| 110 | +// } |
| 111 | +let schema = schemars::schema_for!(ToolInput); |
| 112 | + |
| 113 | +// bring it all together |
| 114 | +let get_weather_tool = Tool::builder() |
| 115 | + .name("get-weather") |
| 116 | + .description("Get the weather information given a location") |
| 117 | + .input_schema(schema.clone()) |
| 118 | + .execute(func) |
| 119 | + .build() |
| 120 | + .unwrap(); |
| 121 | + |
| 122 | +``` |
| 123 | + |
| 124 | +## Registering the tool |
| 125 | + |
| 126 | +To register the tool with the AI model, you need to add it to text generation builders using the `with_tool` method. This |
| 127 | +appends the tool to the list of tools that the AI model will use to generate text. |
| 128 | + |
| 129 | +```rust |
| 130 | +// call the model with the `#[tool]` macro |
| 131 | +let result = LanguageModelRequest::builder() |
| 132 | + .model(OpenAI::new("gpt-4o")) |
| 133 | + .system("You are a helpful assistant with access to tools.") |
| 134 | + .prompt("What is the weather in New York?") |
| 135 | + .with_tool(get_weather()) |
| 136 | + .build() |
| 137 | + .generate_text() |
| 138 | + .await; |
| 139 | +``` |
| 140 | + |
| 141 | +or if you are using the structs |
| 142 | + |
| 143 | +```rust |
| 144 | +// call the model with `Tool` struct |
| 145 | +let result = LanguageModelRequest::builder() |
| 146 | + .model(OpenAI::new("gpt-4o")) |
| 147 | + .system("You are a helpful assistant with access to tools.") |
| 148 | + .prompt("What is the weather in New York?") |
| 149 | + .with_tool(get_weather_tool) // you don't need to call it if using structs. |
| 150 | + .build() |
| 151 | + .generate_text() |
| 152 | + .await; |
| 153 | +``` |
0 commit comments