Module tool

Source
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 tools
  • Tools - 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§

ToolDefinition
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.