Skip to content

Tool calling (function calling) with manual tool definitions

Tool calling (function calling) with manual tool definitions.

Run with: cargo run --release --example tools -p mistralrs

//! Tool calling (function calling) with manual tool definitions.
//!
//! Run with: `cargo run --release --example tools -p mistralrs`
use std::collections::HashMap;
use anyhow::Result;
use mistralrs::{
Function, IsqBits, ModelBuilder, RequestBuilder, TextMessageRole, Tool, ToolChoice, ToolType,
};
use serde_json::{json, Value};
#[derive(serde::Deserialize, Debug, Clone)]
struct GetWeatherInput {
place: String,
}
fn get_weather(input: GetWeatherInput) -> String {
format!("Weather in {}: Temperature: 25C. Wind: calm. Dew point: 10C. Precipitiation: 5cm of rain expected.", input.place)
}
#[tokio::main]
async fn main() -> Result<()> {
let model = ModelBuilder::new("Qwen/Qwen3-4B")
.with_logging()
.with_auto_isq(IsqBits::Eight)
.build()
.await?;
let parameters: HashMap<String, Value> = serde_json::from_value(json!({
"type": "object",
"properties": {
"place": {
"type": "string",
"description": "The place to get the weather for.",
},
},
"required": ["place"],
}))?;
let tools = vec![Tool {
tp: ToolType::Function,
function: Function {
description: Some("Get the weather for a certain city.".to_string()),
name: "get_weather".to_string(),
parameters: Some(parameters),
strict: Some(true),
},
}];
// We will keep all the messages here
let mut messages = RequestBuilder::new()
.add_message(TextMessageRole::User, "What is the weather in Boston?")
.set_tools(tools)
.set_tool_choice(ToolChoice::Auto);
let response = model.send_chat_request(messages.clone()).await?;
let message = &response.choices[0].message;
if let Some(tool_calls) = &message.tool_calls {
let called = &tool_calls[0];
if called.function.name == "get_weather" {
let input: GetWeatherInput = serde_json::from_str(&called.function.arguments)?;
println!("Called tool `get_weather` with arguments {input:?}");
let result = get_weather(input);
println!("Output of tool call: {result}");
// Add tool call message from assistant so it knows what it called
// Then, add message from the tool
messages = messages
.add_message_with_tool_call(
TextMessageRole::Assistant,
String::new(),
vec![called.clone()],
)
.add_tool_message(result, called.id.clone())
.set_tool_choice(ToolChoice::None);
let response = model.send_chat_request(messages.clone()).await?;
let message = &response.choices[0].message;
println!("Output of model: {:?}", message.content);
}
}
Ok(())
}

Source: mistralrs/examples/advanced/tools/main.rs