10.2 Rust 类型到 JSON Schema 映射
`#[tool]` 宏在编译期自动将 Rust 函数参数类型转换为 OpenAI/JSON Schema 兼容的参数定义。本章提供完整的类型映射参考和属性使用指南。
类型映射表
基本类型映射
| Rust 类型 | JSON Schema type | 说明 | |-----------|-----------------|------| | `String` | `"string"` | UTF-8 字符串 | | `&str` | `"string"` | 字符串切片(参数场景少见) | | `i8` | `"integer"` | 8 位有符号整数 | | `i16` | `"integer"` | 16 位有符号整数 | | `i32` | `"integer"` | 32 位有符号整数 | | `i64` | `"integer"` | 64 位有符号整数(推荐) | | `i128` | `"integer"` | 128 位有符号整数 | | `isize` | `"integer"` | 平台相关有符号整数 | | `u8` | `"integer"` | 8 位无符号整数 | | `u16` | `"integer"` | 16 位无符号整数 | | `u32` | `"integer"` | 32 位无符号整数 | | `u64` | `"integer"` | 64 位无符号整数 | | `u128` | `"integer"` | 128 位无符号整数 | | `usize` | `"integer"` | 平台相关无符号整数 | | `f32` | `"number"` | 32 位浮点数 | | `f64` | `"number"` | 64 位浮点数(推荐) | | `bool` | `"boolean"` | 布尔值 |
泛型容器类型映射
| Rust 类型 | JSON Schema | 说明 | |-----------|------------|------| | `Option<T>` | 基本类型 schema(不进入 required) | 可选参数,`is_option_type` 返回 `true` | | `Vec<T>` | `{"type": "array", "items": <T>}` | 动态数组 | | `HashMap<String, T>` | `{"type": "string"}` (回退) | 目前回退为字符串类型 |
解析逻辑
生成的代码在编译期执行以下匹配:
match type_str {
"String" | "&str" | "str" => json!({"type": "string"}),
"i8" | "i16" | "i32" | "i64" | "i128" | "isize" |
"u8" | "u16" | "u32" | "u64" | "u128" | "usize" => json!({"type": "integer"}),
"f32" | "f64" => json!({"type": "number"}),
"bool" => json!({"type": "boolean"}),
_ => json!({"type": "string"}), // 未知类型回退
}
`#[param]` 属性
`#[param]` 属性用于为函数参数添加元数据,最主要的用途是设置参数描述(`desc`)。
语法
#[param(desc = "参数的描述文本")]
#[param(description = "参数的描述文本")] // desc 的完整形式别名
`desc` 和 `description` 是等价的,`desc` 只是更简洁的简写。
示例
#[tool(description = "在数据库中搜索记录")]
async fn db_search(
#[param(desc = "搜索关键词")] query: String,
#[param(desc = "每页结果数量,默认 20")] limit: Option<i64>,
#[param(desc = "结果偏移量")] offset: Option<i64>,
#[param(desc = "是否包含已删除记录")] include_deleted: Option<bool>,
) -> rust_agent_core::ToolResult {
// ...
}
生成的 JSON Schema:
{
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词"
},
"limit": {
"type": "integer",
"description": "每页结果数量,默认 20"
},
"offset": {
"type": "integer",
"description": "结果偏移量"
},
"include_deleted": {
"type": "boolean",
"description": "是否包含已删除记录"
}
},
"required": ["query"]
}
只有 `query` 出现在 `required` 中,因为其余参数都是 `Option<T>` 类型。
`is_option_type` 检测机制
`is_option_type` 函数通过 `syn` 的类型路径分析来判断参数是否为 `Option<T>`:
fn is_option_type(ty: &syn::Type) -> bool {
if let syn::Type::Path(type_path) = ty {
type_path.path.segments.last()
.map(|s| s.ident == "Option")
.unwrap_or(false)
} else {
false
}
}
**关键行为**:
- `Option<i64>` → `true`(参数标记为可选,不进入 required) - `Option<String>` → `true`(同上) - `Vec<String>` → `false`(Vec 不走 Option 检测逻辑) - `i64` → `false`(必需参数,进入 required)
检测为 `true` 的参数: - 不会出现在 `required` 数组中 - 生成的 Schema 类型按内部 `T` 的实际类型映射(不是 `Option`) - 反序列化时 `None` 值正常工作
`Option<T>` 的类型处理
当参数类型为 `Option<T>` 时,Schema 生成使用 `T` 的原始类型而非 `Option`:
// Option<T> 的处理
if type_str.starts_with("Option<") {
let inner = extract_inner_type(&type_str);
return rust_type_str_to_tokens(&inner);
}
`Vec<T>` 的数组映射
`Vec<T>` 生成标准的 JSON Schema 数组定义:
// Vec<T> 的处理
if type_str.starts_with("Vec<") {
let inner = extract_inner_type(&type_str);
let inner_schema = rust_type_str_to_tokens(&inner);
return quote! {
serde_json::json!({
"type": "array",
"items": #inner_schema
})
};
}
示例映射:
| Rust 类型 | 生成的 JSON Schema | |-----------|-------------------| | `Vec<String>` | `{"type": "array", "items": {"type": "string"}}` | | `Vec<i64>` | `{"type": "array", "items": {"type": "integer"}}` | | `Vec<f64>` | `{"type": "array", "items": {"type": "number"}}` | | `Vec<bool>` | `{"type": "array", "items": {"type": "boolean"}}` |
`extract_inner_type` — 泛型参数提取
从 `Type<T>` 形式的字符串中提取内部类型 `T`:
fn extract_inner_type(type_str: &str) -> String {
let start = type_str.find('<').map(|i| i + 1).unwrap_or(0);
let end = type_str.rfind('>').unwrap_or(type_str.len());
type_str[start..end].to_string()
}
该函数仅处理单层泛型嵌套(如 `Option<String>`、`Vec<i64>`),不支持 `HashMap<String, Vec<i64>>` 等深层嵌套。
完整示例:复杂工具参数
#[tool(description = "执行高级搜索操作")]
async fn advanced_search(
#[param(desc = "搜索查询字符串")] query: String,
#[param(desc = "搜索分类过滤器")] categories: Vec<String>,
#[param(desc = "最低评分阈值")] min_rating: Option<f64>,
#[param(desc = "最大结果数")] max_results: Option<i64>,
#[param(desc = "是否仅搜索已验证内容")] verified_only: Option<bool>,
#[param(desc = "排序字段")] sort_by: Option<String>,
) -> rust_agent_core::ToolResult {
// ...
}
生成的 JSON Schema:
{
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索查询字符串"
},
"categories": {
"type": "array",
"items": {"type": "string"},
"description": "搜索分类过滤器"
},
"min_rating": {
"type": "number",
"description": "最低评分阈值"
},
"max_results": {
"type": "integer",
"description": "最大结果数"
},
"verified_only": {
"type": "boolean",
"description": "是否仅搜索已验证内容"
},
"sort_by": {
"type": "string",
"description": "排序字段"
}
},
"required": ["query", "categories"]
}
注意事项
1. **不支持深层嵌套泛型**:如 `HashMap<String, Vec<Option<i64>>>` 会因 `extract_inner_type` 的简单实现而产生不正确的结果 2. **自定义类型回退为 string**:不在内置映射表中的 Rust 类型(如自定义结构体、枚举)会回退到 `{"type": "string"}` 3. **`#[param]` 属性位置**:必须直接放在参数声明之前,不支持其他位置 4. **`#[tool]` 仅支持 async fn 和 struct**:不支持普通 fn、trait 方法或其他项目类型