Normalisation des schémas
ADK-Rust normalise automatiquement les schĂ©mas dâoutils de MCP pour chaque fournisseur LLM au moment de la requĂȘte. Cela signifie que les outils MCP fonctionnent de maniĂšre transparente avec Gemini, OpenAI, Anthropic et dâautres fournisseurs, sans ajustement manuel des schĂ©mas.
Fonctionnement
MCP Server â raw JSON Schema â McpToolset (stores verbatim)
â
Model.generate_content()
â
SchemaAdapter.normalize_schema()
â
Provider API (Gemini/OpenAI/Anthropic)
- McpToolset détecte les outils et stocke leur
inputSchemabrut sans modification - Lorsque le modĂšle construit une requĂȘte, il appelle
schema_adapter().normalize_schema()sur le schéma de chaque outil - Chaque fournisseur possÚde son propre adaptateur, qui applique uniquement les transformations requises par son API
- Les rĂ©sultats sont mis en cache Ă lâaide dâun hachage du contenu afin dâĂ©viter toute normalisation redondante
Comportement des fournisseurs
| Fonctionnalité | Gemini | OpenAI Strict | OpenAI | Anthropic | Générique |
|---|---|---|---|---|---|
RĂ©solution de $ref | â IntĂšgre | â PrĂ©serve | â PrĂ©serve | â PrĂ©serve | â PrĂ©serve |
anyOf/oneOf | Réduit | Préserve | Préserve | Préserve | Préserve |
allOf | Fusionne | Préserve | Préserve | Préserve | Préserve |
additionalProperties | Supprime | Définit false | Préserve | Préserve | Préserve |
| Tableaux de types | Réduit | Préserve | Préserve | Préserve | Préserve |
$schema | Supprime | Supprime | Supprime | Supprime | Supprime |
if/then/else | Supprime | Supprime | Supprime | Supprime | Supprime |
const | â enum | â enum | â enum | PrĂ©serve | â enum |
format non pris en charge | Supprime | Supprime | Supprime | Préserve | Supprime |
| Limite de profondeur d'imbrication | 5 niveaux | Aucune | Aucune | Aucune | Aucune |
exclusiveMin/Max | Supprime | Préserve | Préserve | Préserve | Préserve |
Le trait SchemaAdapter
Tous les adaptateurs implémentent ce trait de adk-core :
use serde_json::Value;
use std::borrow::Cow;
pub trait SchemaAdapter: Send + Sync + std::fmt::Debug {
/// Normalize a raw JSON Schema for this provider.
fn normalize_schema(&self, schema: Value) -> Value;
/// Normalize a tool name (default: truncate to 64 bytes at UTF-8 boundary).
fn normalize_tool_name<'a>(&self, name: &'a str) -> Cow<'a, str>;
/// Fallback schema when no parameters_schema is provided.
fn empty_schema(&self) -> Value;
}
Chaque implémentation de Llm renvoie son adaptateur via schema_adapter() :
use adk_core::Llm;
let model = GeminiModel::new(&api_key, "gemini-3.7-flash")?;
let adapter = model.schema_adapter(); // Returns &GeminiSchemaAdapter
Adaptateurs disponibles
GeminiSchemaAdapter
Lâadaptateur le plus agressif. Applique toutes les transformations destructives requises par lâAPI dâappel de fonctions de Gemini API :
use adk_gemini::schema_adapter::GeminiSchemaAdapter;
use adk_core::SchemaAdapter;
// Standard Gemini API
let adapter = GeminiSchemaAdapter::new();
// Vertex AI (sets additionalProperties: false instead of removing)
let adapter = GeminiSchemaAdapter::vertex_ai();
Pipeline de transformation :
- Résoudre
$ref(intĂ©gration depuis les dĂ©finitions, arrĂȘt des cycles Ă la profondeur 10) - Supprimer
$schema - Réduire
anyOf/oneOfâ premier sous-schĂ©ma non nul - Fusionner les sous-schĂ©mas
allOf - Réduire les tableaux de types (
["string", "null"]â"string") - Supprimer
if/then/else - Convertir
constâenumĂ un seul Ă©lĂ©ment - Supprimer null des tableaux
enum - Ajouter implicitement
type: "object" - Supprimer les mots-clés non pris en charge
- Supprimer les valeurs
formatnon prises en charge - Imposer une profondeur dâimbrication (5 niveaux)
- Supprimer
definitions/$defs
OpenAiStrictSchemaAdapter
Préserve la structure du schéma tout en ajoutant additionalProperties: false pour les sorties structurées :
use adk_model::openai::OpenAiStrictSchemaAdapter;
use adk_core::SchemaAdapter;
let adapter = OpenAiStrictSchemaAdapter;
OpenAiSchemaAdapter
Corrections minimales sûres pour le mode non strict :
use adk_model::openai::OpenAiSchemaAdapter;
let adapter = OpenAiSchemaAdapter;
AnthropicSchemaAdapter
Presque transparent â Anthropic prend en charge la plupart des fonctionnalitĂ©s de schĂ©ma JSON :
use adk_model::anthropic::AnthropicSchemaAdapter;
let adapter = AnthropicSchemaAdapter;
GenericSchemaAdapter
Valeur par défaut pour les fournisseurs inconnus (Ollama, DeepSeek, etc.) :
use adk_core::GenericSchemaAdapter;
let adapter = GenericSchemaAdapter;
Mise en cache des schémas
Les schĂ©mas normalisĂ©s sont mis en cache Ă lâaide dâun hachage du contenu afin dâĂ©viter les calculs redondants :
use adk_core::{GenericSchemaAdapter, SchemaCache};
use serde_json::json;
use std::sync::Arc;
let cache = SchemaCache::for_adapter(Arc::new(GenericSchemaAdapter));
let schema = json!({"type": "object", "properties": {"name": {"type": "string"}}});
// First call normalizes and caches
let result = cache.normalize(&schema);
// Subsequent calls return cached result (no re-normalization)
let cached = cache.normalize(&schema);
// Invalidate when tools change
cache.clear();
Chaque cache possĂšde une instance dâadaptateur, de sorte que les entrĂ©es normalisĂ©es pour diffĂ©rents
fournisseurs ou configurations dâadaptateur ne puissent pas entrer en collision. Les clients des fournisseurs utilisent automatiquement ces caches lors de generate_content().
Troncature des noms dâoutils
Tous les adaptateurs tronquent les noms dâoutils dĂ©passant 64 octets Ă des limites valides de caractĂšres UTF-8 :
use adk_core::SchemaAdapter;
use adk_gemini::schema_adapter::GeminiSchemaAdapter;
let adapter = GeminiSchemaAdapter::new();
// Short names pass through unchanged
let name = adapter.normalize_tool_name("get_weather");
assert_eq!(name, "get_weather");
// Long names are truncated to 64 bytes
let long = "mcp_server_github_com_organization_repository_pull_request_review_comments";
let truncated = adapter.normalize_tool_name(long);
assert!(truncated.len() <= 64);
// Multi-byte characters are never split
let emoji_name = "đ§_tool_ććăé·ă";
let result = adapter.normalize_tool_name(emoji_name);
assert!(std::str::from_utf8(result.as_bytes()).is_ok());
Utilitaires partagés
Le module adk_core::schema_utils fournit des fonctions de transformation composables que les adaptateurs utilisent en interne :
use adk_core::schema_utils;
use serde_json::json;
let mut schema = json!({
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"status": { "const": "active" },
"email": { "type": "string", "format": "hostname" }
},
"if": { "properties": { "x": { "type": "number" } } },
"then": { "required": ["x"] }
});
// Apply individual transforms
schema_utils::strip_schema_keyword(&mut schema);
schema_utils::strip_conditional_keywords(&mut schema);
schema_utils::convert_const_to_enum(&mut schema);
schema_utils::strip_unsupported_formats(&mut schema, &["date-time", "email", "uri"]);
Utilitaires disponibles :
strip_schema_keywordâ supprime$schemastrip_conditional_keywordsâ supprimeif/then/elseadd_implicit_object_typeâ ajoutetype: "object"lorsquepropertiesexisteconvert_const_to_enumâ convertitconstenenumĂ Ă©lĂ©ment uniquestrip_unsupported_formatsâ supprime les valeurs de format qui ne figurent pas dans la liste dâautorisationstrip_null_from_enumâ supprime null des tableaux dâĂ©numĂ©rationtruncate_tool_nameâ tronque Ă la limite UTF-8resolve_refsâ intĂšgre les rĂ©fĂ©rences$refdepuis les dĂ©finitionscollapse_combinersâ rĂ©duitanyOf/oneOfau premier Ă©lĂ©ment non nulmerge_all_ofâ fusionne les sous-schĂ©masallOfcollapse_type_arraysâ rĂ©duit["string", "null"]Ă"string"enforce_nesting_depthâ remplace les schĂ©mas profonds par{"type": "object"}
Adaptateurs personnalisés
Implémentez SchemaAdapter pour les fournisseurs personnalisés :
use adk_core::{SchemaAdapter, schema_utils};
use serde_json::Value;
use std::borrow::Cow;
#[derive(Debug)]
struct MyProviderAdapter;
impl SchemaAdapter for MyProviderAdapter {
fn normalize_schema(&self, mut schema: Value) -> Value {
// Apply only the transforms your provider needs
schema_utils::strip_schema_keyword(&mut schema);
schema_utils::strip_conditional_keywords(&mut schema);
schema_utils::add_implicit_object_type(&mut schema);
// Keep everything else as-is
schema
}
}
Exemple
Exécutez la démonstration de normalisation des schémas pour voir tous les adaptateurs en action :
cd examples/schema_normalization
cargo run
Aucune clĂ© API nâest nĂ©cessaire â cette dĂ©monstration prĂ©sente la logique de normalisation localement.
Migration depuis sanitize_schema
Si vous vous appuyiez auparavant sur McpToolset pour renvoyer des schémas pré-nettoyés :
- Aucune modification du code nâest nĂ©cessaire pour lâutilisation standard. Le trait
ToolsetAPI reste inchangĂ©. - Les schĂ©mas sont dĂ©sormais normalisĂ©s au moment de la requĂȘte par lâadaptateur de modĂšle, et non lors de lâenregistrement de lâoutil.
- Si vous appeliez
parameters_schema()en vous attendant Ă obtenir une sortie au format Gemini, le schĂ©ma brut est dĂ©sormais renvoyĂ© Ă la place. Utilisez leSchemaAdapterappropriĂ© pour le normaliser vous-mĂȘme si nĂ©cessaire.
PrĂ©cĂ©dent : â MCP Outils | Suivant : Sessions â