functiongemma.fine-tuning.function.calling
FunctionGemma 270M : comment tester, comprendre et dompter un SLM spécialisé dans le Function Calling
Les grands modèles de langage savent faire beaucoup de choses.
Mais pour certaines applications, beaucoup de choses est justement le problème.
Si mon besoin est simplement de transformer :
« Allume la lampe de mon téléphone »
en :
call:turn_on_flashlight{}
je n’ai peut-être pas besoin d’un modèle de plusieurs dizaines de milliards de paramètres.
C’est précisément là que les Small Language Models (SLM) deviennent intéressants.
Et un cas particulièrement intéressant est FunctionGemma 270M, le modèle de Google DeepMind spécialisé dans le function calling. Il est construit à partir de Gemma 3 270M et conçu pour transformer des instructions en appels de fonctions, notamment dans des environnements contraints ou on-device. Hugging Face
L’idée de cet article est donc simple :
ne pas seulement tester FunctionGemma… mais chercher à comprendre comment il fonctionne, où il échoue, quelles sont ses “astuces” et comment construire une véritable batterie de tests à partir des datasets disponibles sur Hugging Face.
1. FunctionGemma 270M : ce n’est pas un “petit ChatGPT”
C’est probablement le premier point à comprendre.
La fiche officielle du modèle indique explicitement que FunctionGemma n’est pas destiné à être utilisé comme modèle de dialogue généraliste.
Son objectif est plutôt de servir de base à des modèles spécialisés dans le function calling. Hugging Face
Son fonctionnement peut être résumé ainsi :
Utilisateur
│
▼
"Réserve-moi un taxi pour 18h"
│
▼
FunctionGemma
│
├── choisir l'outil
├── identifier les paramètres
└── générer l'appel
│
▼
book_taxi(
time="18:00"
)
│
▼
Application
C’est donc moins :
“Que dois-je répondre ?”
que :
“Quelle action dois-je déclencher et avec quels paramètres ?”
Et cette nuance change complètement la manière de tester le modèle.
2. Ce que 270M paramètres peut réellement faire
Il serait tentant de demander à FunctionGemma :
“Explique-moi la théorie de la relativité.”
Ce n’est pas le meilleur test.
En revanche, on peut lui donner des outils comme :
[
{
"name": "get_weather",
"description": "Get current weather",
"parameters": {
"location": "string"
}
},
{
"name": "send_email",
"description": "Send an email",
"parameters": {
"to": "string",
"subject": "string",
"body": "string"
}
}
]
et tester :
"Quel temps fait-il à Rennes ?"
pour obtenir quelque chose du genre :
get_weather(location="Rennes")
La documentation officielle montre justement ce mécanisme avec un schéma JSON, un message developer indiquant que le modèle peut appeler des fonctions, puis une génération de l’appel correspondant. Hugging Face
Cela permet d’imaginer beaucoup de micro-agents :
- assistant domotique ;
- contrôle d’un smartphone ;
- automatisation locale ;
- recherche dans une base documentaire ;
- API internes d’entreprise ;
- commandes d’une application ;
- agent embarqué dans un véhicule ;
- assistants offline ;
- automatisation industrielle ;
- jeux et interfaces interactives.
Google présente notamment Mobile Actions, où le modèle traduit des instructions naturelles en appels à des fonctions Android, ainsi que Tiny Garden, où il pilote les actions d’un petit jeu. Hugging Face+1
3. Le vrai sujet : comment tester un SLM ?
Pour moi, il faut éviter le classique :
Prompt A → réponse
Prompt B → réponse
Prompt C → réponse
et passer à une logique de laboratoire expérimental.
Je proposerais 7 familles de tests.
Test 1 — Tool selection
Le modèle choisit-il le bon outil ?
"Quel est le temps à Paris ?"
avec :
get_weather()
search_web()
send_email()
On mesure :
✓ bon outil
✗ mauvais outil
✗ aucune fonction
✗ hallucination
Test 2 — Argument extraction
Le bon outil est-il sélectionné avec les bons paramètres ?
"Envoie un mail à paul@example.com
avec comme sujet 'Réunion'
et dis-lui que je serai en retard."
On vérifie :
{
"to": "paul@example.com",
"subject": "Réunion",
"body": "Je serai en retard."
}
Ici, il faut séparer :
tool accuracy
et
argument accuracy.
Un modèle peut parfaitement choisir send_email tout en remplissant mal les arguments.
4. Le test qui devient vraiment intéressant : l’ambiguïté
C’est probablement l’une des meilleures façons de comprendre un SLM.
Imaginons :
search_internal_docs()
search_web()
Prompt :
“Quelle est notre politique de remboursement des repas ?”
Le modèle doit comprendre que la bonne source est probablement la documentation interne.
Mais :
“Quelle est la politique de remboursement des repas chez Air France ?”
change complètement le contexte.
C’est exactement le type de problème étudié dans le guide officiel de fine-tuning de FunctionGemma : apprendre au modèle à distinguer des outils proches selon le contexte métier. Google Developers Blog
On découvre alors quelque chose d’important :
un petit modèle peut être extrêmement efficace lorsqu’on réduit son espace de décision.
5. Le test le plus révélateur : “No Tool”
Il ne faut surtout pas tester uniquement les cas où une fonction doit être appelée.
Il faut également tester :
“Est-ce que le modèle sait ne rien appeler ?”
Exemple :
Tools:
- get_weather()
- send_email()
- create_calendar_event()
Prompt :
“Explique-moi ce qu’est Python.”
Le résultat attendu :
NO TOOL
et surtout pas :
search_web()
ou une fonction inventée.
C’est un excellent test de relevance / irrelevance.
Le benchmark publié avec FunctionGemma contient justement des catégories BFCL de relevance et d’irrelevance, en plus des scénarios de function calling simple, multiple et parallèle. Hugging Face
6. Tester les limites : les prompts “pièges”
C’est ici que l’on commence réellement à découvrir les caractéristiques du modèle.
Je créerais volontairement des prompts comme :
"Allume la lumière... enfin non, laisse tomber."
ou :
"Envoie un email à Paul si tu trouves son adresse."
ou :
"Réserve-moi quelque chose demain."
ou :
"Supprime le fichier rapport.pdf"
avec deux outils :
delete_file()
archive_file()
L’objectif n’est pas seulement de mesurer la réussite.
Il faut identifier les frontières comportementales du modèle.
7. Construire une matrice de tests
Une approche très efficace consiste à transformer chaque fonction en matrice.
Par exemple :
| Catégorie | Exemple | Résultat attendu |
|---|---|---|
| Happy path | “Allume la lumière” | turn_on_light |
| Paramètre simple | “Lumière du salon” | room=salon |
| Paramètre absent | “Allume la lumière” | demander précision |
| Ambiguïté | “Allume celle du salon” | clarification |
| Négation | “N’allume pas la lumière” | aucun appel |
| Hors sujet | “Quel temps fait-il ?” | aucun appel |
| Outil similaire | turn_on vs set_brightness |
bon outil |
| Valeur invalide | luminosité 200% | rejet/correction |
| Multi-tool | lumière + chauffage | deux appels |
| Séquence | ouvrir → modifier → fermer | ordre correct |
On passe ainsi d’un simple test de LLM à un test fonctionnel d’agent.
8. Hugging Face devient alors notre laboratoire
Et c’est là que cela devient particulièrement intéressant.
Le dataset officiel Google Mobile Actions est disponible sur Hugging Face. Il contient environ 9 650 exemples, avec des conversations et des définitions d’outils, et est spécifiquement destiné à l’entraînement de modèles légers comme FunctionGemma pour le function calling on-device. Hugging Face
Dataset Google Mobile Actions sur Hugging Face
On peut donc commencer par :
from datasets import load_dataset
dataset = load_dataset(
"google/mobile-actions",
split="train"
)
print(dataset)
print(dataset[0])
Puis observer :
sample = dataset[0]
print(sample.keys())
print(sample["messages"])
print(sample["tools"])
Et surtout :
ne pas simplement utiliser le dataset pour entraîner.
Utilisons-le pour comprendre comment les données enseignent au modèle à agir.
9. Transformer un dataset en générateur de tests
C’est probablement l’une des idées les plus intéressantes de cette approche.
Prenons un exemple du dataset :
User:
"Turn on the flashlight"
Expected:
turn_on_flashlight()
On peut automatiquement générer plusieurs variantes :
"Allume la lampe torche"
"Tu peux activer le flash ?"
"Active la flashlight"
"J'ai besoin de lumière"
"Peux-tu allumer le flash du téléphone ?"
Puis comparer les résultats.
On passe alors de :
1 exemple → 1 test
à :
1 exemple
↓
20 variantes
↓
20 tests
Et là, on commence à construire un fuzzing sémantique pour LLM.
10. Encore mieux : créer des tests négatifs
Le dataset contient ce que le modèle doit faire.
Nous pouvons créer artificiellement ce qu’il ne doit pas faire.
Exemple :
TRAIN
"Turn on flashlight"
→ turn_on_flashlight()
Créer :
NEGATIVE TEST
"Do not turn on the flashlight"
→ NO TOOL
Puis :
"Is the flashlight currently on?"
→ get_flashlight_status()
Puis :
"Turn on the flashlight and set brightness to 50%"
→ turn_on_flashlight()
→ set_brightness(50)
Puis :
"Turn on the flashlight if the battery is above 30%"
On commence à tester :
- négation ;
- condition ;
- dépendance ;
- multi-tool ;
- paramètres ;
- ambiguïté ;
- contexte.
11. Et maintenant : découvrir les “astuces” de FunctionGemma
C’est là que l’expérimentation devient vraiment intéressante.
Au lieu de demander :
“Quel prompt marche le mieux ?”
je construirais une Prompt Mutation Matrix.
Par exemple :
Variante A
You can call functions.
Variante B
You are an assistant capable of calling tools.
Variante C
Use the available functions whenever appropriate.
Variante D
Le format attendu est explicitement décrit.
Puis :
100 prompts
×
4 system prompts
×
5 températures
On obtient :
2 000 expériences
et on mesure :
tool_accuracy
argument_accuracy
no_tool_accuracy
format_accuracy
latency
tokens
On commence alors à construire une véritable carte comportementale du SLM.
12. Une métrique très importante : exact match vs semantic match
Attention ici.
Si le modèle produit :
{
"location": "Rennes"
}
et que la vérité est :
{
"location": "Rennes, France"
}
un simple exact_match dira :
FAIL
alors que fonctionnellement le résultat peut être acceptable.
Il faut donc plusieurs métriques :
Exact Match
↓
JSON validity
↓
Tool correctness
↓
Argument correctness
↓
Semantic correctness
Exemple :
def evaluate(prediction, expected):
return {
"tool_ok": ...,
"arguments_ok": ...,
"json_valid": ...,
"semantic_ok": ...
}
C’est beaucoup plus intéressant qu’un unique score.
13. Le dataset officiel donne aussi une piste essentielle
Le modèle de base obtient des résultats sensiblement différents selon le type de function calling évalué.
Dans les résultats publiés par Google, FunctionGemma 270M obtient notamment :
- BFCL Simple : 61,6
- BFCL Multiple : 63,5
- BFCL Parallel : 39
- BFCL Parallel Multiple : 29,5
- BFCL Relevance : 61,1
- BFCL Irrelevance : 73,7
Ces chiffres sont ceux rapportés par la model card et doivent être lus comme des résultats de benchmark, pas comme une garantie de performance sur votre propre application. Hugging Face
Cela donne une indication intéressante :
“faire un function call” et “orchestrer plusieurs function calls” sont deux problèmes très différents.
14. Le vrai potentiel apparaît avec le fine-tuning
Google montre justement l’intérêt de spécialiser FunctionGemma.
Sur son cas d’usage Mobile Actions, l’évaluation publiée passe de 58 % pour le modèle de base à 85 % après fine-tuning sur ce workflow spécifique. Hugging Face
Le message est important :
270M paramètres ne signifie pas nécessairement “faible capacité”.
Cela peut signifier :
capacité concentrée sur un problème bien défini.
C’est une philosophie très différente du :
“prenons le plus gros modèle possible.”
15. Et si on construisait notre propre dataset ?
Imaginons une entreprise qui possède :
create_ticket()
update_ticket()
close_ticket()
search_ticket()
assign_ticket()
On peut créer :
{
"user": "Ferme le ticket 1234",
"expected_tool": "close_ticket",
"arguments": {
"ticket_id": "1234"
}
}
Puis générer :
"Tu peux clôturer le ticket 1234 ?"
"Ferme-moi le ticket numéro 1234"
"Le ticket 1234 peut être clôturé"
"Je veux clôturer 1234"
Mais surtout :
"Montre-moi le ticket 1234"
→ search_ticket
et :
"Ferme le ticket 1234"
→ close_ticket
Le dataset devient alors une spécification comportementale.
16. Attention au piège du train/test split
C’est un détail qui peut complètement fausser les résultats.
Le guide Google consacré au fine-tuning de FunctionGemma montre justement l’importance de la distribution des données lors du découpage train/test. Si les exemples sont organisés par catégorie et que l’on découpe sans mélanger, on peut finir avec une catégorie presque exclusivement dans le train et une autre dans le test. Google Developers Blog
Donc :
dataset.train_test_split(
test_size=0.2,
shuffle=True
)
est souvent préférable lorsque l’ordre initial du dataset n’est pas garanti comme étant correctement mélangé.
Mais surtout :
il faut penser au split en fonction du problème.
Pour un agent réel, je testerais également :
Train :
formulations connues
Test :
formulations inédites
et même :
Test OOD :
nouveaux outils
nouveaux paramètres
nouvelles formulations
C’est beaucoup plus révélateur de la capacité de généralisation.
17. Une architecture de test que j’utiliserais
Je construirais un petit framework :
┌─────────────────┐
│ Hugging Face │
│ datasets │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Test Generator │
└────────┬────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
Normal Ambiguous Negative
│ │ │
└────────────┼────────────┘
▼
┌─────────────────┐
│ FunctionGemma │
│ 270M │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Evaluator │
└────────┬────────┘
│
┌───────────────┼────────────────┐
▼ ▼ ▼
Tool Acc. Arg Acc. No-Tool Acc.
Et conserver chaque expérience :
{
"prompt": "...",
"tools": [...],
"expected": {...},
"actual": {...},
"tool_accuracy": true,
"argument_accuracy": false,
"latency_ms": 37,
"tokens": 18
}
18. Le graal : tester le SLM comme du logiciel
C’est probablement la conclusion la plus importante.
On ne devrait plus traiter un SLM uniquement comme :
prompt → réponse
mais comme un composant logiciel :
INPUT
↓
MODEL
↓
STRUCTURED OUTPUT
↓
VALIDATOR
↓
ACTION
Avec des tests automatisés :
assert result.tool == "get_weather"
assert result.arguments["location"] == "Rennes"
assert result.is_valid_json
assert result.confidence_policy_ok
Et surtout :
CI/CD
↓
1000 prompts
↓
FunctionGemma
↓
Evaluation
↓
Regression detected
On peut alors détecter qu’un fine-tuning ou une modification du prompt a fait passer :
Tool accuracy
92% → 88%
avant de déployer le modèle.
19. Ce que je testerais en premier avec FunctionGemma 270M
Mon parcours expérimental serait :
Étape 1 — Baseline
Tester le modèle officiel sans modification.
Étape 2 — Single tool
1 prompt
1 tool
Étape 3 — Multiple tools
1 prompt
5 tools
Étape 4 — Similar tools
search_web()
search_docs()
search_database()
Étape 5 — No-tool
Tester explicitement les requêtes qui ne doivent déclencher aucune action.
Étape 6 — Ambiguity
Créer volontairement des cas ambigus.
Étape 7 — Multi-turn
User → demande
Model → clarification
User → précision
Model → function call
Étape 8 — Dataset Hugging Face
Utiliser google/mobile-actions comme matière première pour construire les tests. Hugging Face
Étape 9 — Mutation
Générer automatiquement des variantes linguistiques.
Étape 10 — Fine-tuning
Spécialiser le modèle sur son propre domaine.
Étape 11 — Regression suite
Conserver tous les cas qui ont déjà cassé le modèle.
20. Le changement de perspective
C’est finalement ce que je trouve le plus intéressant avec FunctionGemma.
Le sujet n’est pas seulement :
“Que peut faire un modèle de 270M ?”
La vraie question est :
“Que peut-on obtenir lorsqu’on transforme un petit modèle généraliste en composant extrêmement spécialisé, puis qu’on mesure précisément son comportement ?”
Avec les grands modèles, on a tendance à chercher toujours plus de capacités.
Avec les SLM, on peut chercher autre chose :
moins de paramètres, moins de latence, moins de coût, plus de contrôle et une spécialisation beaucoup plus forte.
FunctionGemma est particulièrement intéressant pour explorer cette approche parce que Google fournit à la fois le modèle, des exemples de function calling, le dataset Mobile Actions, des recettes de fine-tuning et même un FunctionGemma Tuning Lab. Google Developers Blog+1
FunctionGemma 270M sur Hugging Face
FunctionGemma Tuning Lab
En résumé
Pour explorer sérieusement un SLM comme FunctionGemma, je partirais de cette boucle :
DATASETS
↓
OBSERVATION
↓
TEST GENERATION
↓
FUNCTIONGEMMA
↓
EVALUATION
↓
ERROR ANALYSIS
↓
DATASET AMÉLIORÉ
↓
FINE-TUNING
↓
REGRESSION TESTS
↺
Le dataset devient le laboratoire.
Le prompt devient une variable expérimentale.
Le modèle devient un composant testable.
Et les erreurs deviennent de nouvelles données d’apprentissage.
C’est peut-être là que les SLM deviennent vraiment intéressants : non pas lorsqu’on essaie de leur faire faire tout ce qu’un LLM sait faire, mais lorsqu’on leur donne une mission très précise et qu’on apprend à mesurer, comprendre et maîtriser leurs frontières.
#AI #SLM #FunctionCalling #FunctionGemma #GoogleDeepMind #HuggingFace #LLM #GenAI #EdgeAI #OnDeviceAI #MachineLearning #AIEngineering #AgenticAI #MLOps #Testing #FineTuning