Expand description
Tool system for function calling.
§LLM Tool Calling Framework
Type-safe tool calling system for Large Language Models. Enables LLMs to execute external functions, access APIs, and interact with systems through well-defined interfaces.
//! ## How LLM call external tools?
TODO
§Core Components
Tool
- Trait for defining executable toolsTools
- Registry for managing multiple tools- [
ToolDefinition
] - Metadata and schema for LLM consumption
§Quick Start
use ai_types::llm::Tool;
use schemars::JsonSchema;
use serde::Deserialize;
#[derive(JsonSchema, Deserialize)]
struct MathArgs {
/// Operation: "add", "subtract", "multiply", "divide"
operation: String,
/// First number
a: f64,
/// Second number
b: f64,
}
struct Calculator;
impl Tool for Calculator {
const NAME: &str = "calculator";
const DESCRIPTION: &str = "Performs basic math operations";
type Arguments = MathArgs;
async fn call(&mut self, args: Self::Arguments) -> ai_types::Result {
let result = match args.operation.as_str() {
"add" => args.a + args.b,
"subtract" => args.a - args.b,
"multiply" => args.a * args.b,
"divide" if args.b != 0.0 => args.a / args.b,
"divide" => return Err(anyhow::Error::msg("Division by zero")),
_ => return Err(anyhow::Error::msg("Unknown operation")),
};
Ok(result.to_string())
}
}
§Schema Design Best Practices
§1. Use Clear Documentation Comments
Doc comments automatically become schema descriptions:
use schemars::JsonSchema;
use serde::Deserialize;
#[derive(JsonSchema, Deserialize)]
struct WeatherArgs {
/// City name (e.g., "London", "Tokyo", "New York")
city: String,
/// Temperature unit: "celsius" or "fahrenheit"
#[serde(default = "default_celsius")]
unit: String,
}
fn default_celsius() -> String { "celsius".to_string() }
§2. Prefer Enums Over Strings
Enums provide clear constraints for LLMs:
use schemars::JsonSchema;
use serde::Deserialize;
#[derive(JsonSchema, Deserialize)]
enum Priority { Low, Medium, High, Critical }
#[derive(JsonSchema, Deserialize)]
struct TaskArgs {
/// Task description
description: String,
/// Task priority level
priority: Priority,
}
§3. Add Validation Constraints
Use schemars attributes for validation:
use schemars::JsonSchema;
use serde::Deserialize;
#[derive(JsonSchema, Deserialize)]
struct UserArgs {
/// Valid email address
#[schemars(regex(pattern = "^[^@]+@[^@]+\\.[^@]+$"))]
email: String,
/// Age between 13 and 120
#[schemars(range(min = 13, max = 120))]
age: u8,
/// Bio text, max 500 characters
#[schemars(length(max = 500))]
bio: Option<String>,
}
§4. Structure Complex Data
Break down complex parameters into nested types:
use schemars::JsonSchema;
use serde::Deserialize;
#[derive(JsonSchema, Deserialize)]
struct Address {
street: String,
city: String,
/// Two-letter country code (e.g., "US", "GB", "JP")
country: String,
}
#[derive(JsonSchema, Deserialize)]
struct CreateUserArgs {
name: String,
address: Address,
/// List of user interests
#[schemars(length(max = 10))]
interests: Vec<String>,
}
Structs§
- Tool
Definition - Tool definition including schema for language models.
- Tools
- Tool registry for managing and calling tools by name.
Traits§
- Tool
- Tools that can be called by language models.
Functions§
- json
- Serializes a value to JSON string.
Attribute Macros§
- tool
- Converts an async function into an AI tool that can be called by language models.