bots-garden/mini-mepublic Fork
⑂ v0.6.0
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP
🛟 Updated. 5988c55 · on v0.6.0 · k33g · 6d ago
declared-tools.md · 54 lines · 7.3 KBmarkdown
Blame HistoryOpen raw

Les outils déclarés — explication

De quoi s'agit-il ?

Avant le ticket 88, mm offrait deux façons de laisser le modèle lancer l'une de vos commandes : un skill qui dit « appelle ton outil bash avec cette commande », et un serveur MCP qui expose un outil. Les outils déclarés en sont une troisième : une entrée tools: dans le fichier d'agent, qui transforme une commande en outil typé, sans serveur à écrire. Cette page explique pourquoi ils ont été ajoutés à côté des skills plutôt qu'à leur place, et pourquoi ils ont cette forme.

Pourquoi les skills ne suffisaient pas

Un skill lance une commande en deux temps. Le modèle doit d'abord trouver le skill dans le catalogue et appeler read_skill, puis composer une ligne de commande bash à partir de ce qu'il a lu. Chaque étape peut échouer, et sur un petit modèle, elle échoue :

  • Le skill n'est jamais trouvé. Le catalogue est aiguillé par le modèle, qui lit des noms, des descriptions et des mots-clés. Mesuré sur mellum2-12b, un skill status (« Report the status of one of the company's services ») n'a jamais été lu pour « What is the status of the billing service? » — 0 run sur 10, en anglais comme en français. Le modèle a improvisé curl localhost:8080/health et ps aux | grep billing, puis a répondu que le service « semble tourner ». C'est une mauvaise réponse, pas seulement un raté.
  • La commande est réécrite. Quand le skill est sauté mais que le modèle trouve quand même le script, il devine les arguments : ./pkgtest.sh greet au lieu de ./greet.
  • Le consentement est tout ou rien. Tout ce qu'un skill lance passe par bash, donc « toujours autoriser ce script » ne peut se dire que « toujours autoriser bash ».

Un outil déclaré supprime l'étape d'aiguillage : son nom, sa description et ses paramètres figurent dans chaque requête, comme ceux de bash.

Ce qui a été mesuré

Trois actions (release <version> <channel>, pkgtest <package>, status <service>), chacune demandée en anglais et en français, 5 runs chacune, mm -p, sur deux modèles. Un run réussit quand le script a vraiment tourné avec exactement les arguments attendus — vérifié dans un fichier que le script écrit, pas dans la réponse du modèle.

Modèle Skill + bash Outil typé via une doublure MCP Outil déclaré
mellum2-12b 15/30 (4,5 s en moyenne) 25/30 (2,8 s) 30/30 (1,3 s)
qwen3.5-4b 30/30 (12,7 s) 30/30 (7,7 s) 30/30 (5,8 s)

La doublure MCP a été mesurée en premier, avant d'écrire la moindre ligne : un petit serveur MCP HTTP exposant les trois mêmes outils donnait la même comparaison sans rien construire. C'est elle qui a tranché la question. Les outils déclarés ont été mesurés à nouveau une fois construits.

Deux choses ressortent. D'abord, un outil typé est plus rapide même quand le skill fonctionne : un aller-retour avec le modèle au lieu de deux. Ensuite, les cinq échecs de la doublure sur mellum2 — la demande de release en français — venaient du modèle qui tassait tous les arguments dans un seul champ : {version: "1.4.2 1.4.2, channel beta"}. Avec l'outil déclaré, la même demande a réussi 5 fois sur 5, chaque fois en un seul appel. L'outil déclaré diffère de la doublure sur plusieurs points à la fois — pas de préfixe proj_ dans le nom, pas de « MCP tool from server … » dans la description, une phrase finale « Give each parameter as its own field. » — et l'effet de chacun n'a pas été mesuré séparément.

Ces chiffres viennent d'un seul petit projet de test, de deux modèles et de cinq runs par cas. Ils répondent à « est-ce que ça vaut la peine de le construire ? », pas à « de combien est-ce mieux en général ? ».

Pourquoi c'est conçu ainsi

Pas de shell. La commande est une liste, une entrée argv par élément, et une valeur remplace son {{placeholder}} à l'intérieur d'une seule entrée. Une valeur du modèle — ou une valeur qu'une injection de prompt aurait glissée dans la conversation — ne peut ni ajouter un argument, ni enchaîner une seconde commande, ni rediriger une sortie : 1.4.2; rm -rf ~ arrive au script comme une seule chaîne de version, étrange. Un modèle de type command: "./release.sh {{version}}" exécuté par bash -c a été écarté pour exactement cette raison. Une commande qui a besoin d'un pipe va dans un script.

Le programme ne peut pas venir d'un paramètre. Sinon, un outil déclaré n'est qu'un bash avec des étapes en plus.

Les appels invalides reçoivent une réponse, pas un rejet par le schéma. Le schéma que lit le modèle porte les types, mais pas required ni enum comme mots-clés — ceux-là vont dans les descriptions. Genkit valide un appel contre le schéma déclaré avant de lancer l'outil, et un appel qu'il rejette met fin au tour. mm préfère répondre en texte, en disant ce qui ne va pas, ce que le modèle a envoyé et ce que doit être chaque paramètre, pour que le modèle puisse réessayer. Le même choix a été fait pour les outils MCP. Citer l'appel compte : informé seulement que « channel is missing », mellum2 a renvoyé le même appel tassé six fois, jusqu'à ce que le détecteur de boucle arrête le tour.

Une conversion tolérante, rien de plus. Les modèles écrivent "3" pour 3 et "true" pour true assez souvent pour que ces chaînes soient acceptées. Ce qui demanderait de deviner ("yes", "three") est refusé, avec la raison.

Le consentement suit yolo. Un outil déclaré exécute quelque chose : avec yolo: false, il demande comme bash ; avec yolo: true, il ne demande pas. Demander « même en yolo » a été envisagé puis écarté : c'est l'auteur de l'agent qui a écrit la commande, ce qui engage déjà plus qu'un modèle qui compose une ligne bash.

Les noms sont réservés tôt. Un outil déclaré ne peut pas prendre le nom d'un outil intégré, même désactivé, pour que l'activer plus tard ne casse pas le fichier. Un conflit avec un outil MCP ne se voit qu'une fois le serveur interrogé : c'est donc un avertissement au démarrage, pas une erreur.

Alternatives écartées

  • Seulement des skills. Moins chers à écrire et adaptés aux procédures, mais mesurés en échec là où ça compte, sur les petits modèles que vise mm.
  • Seulement MCP. Donne déjà des outils typés, mais chacun demande un serveur à écrire, à lancer et à maintenir, en HTTP seulement (mm n'a pas de transport MCP stdio). Trop lourd pour « lancer ce script avec deux arguments ».
  • Un système de plugins Wasm (ticket 46). Des outils isolés sont une autre question ; un outil déclaré s'exécute avec les droits de l'utilisateur, comme bash.

Liens avec le reste

Les outils déclarés se rangent à côté des outils intégrés : le même détecteur de boucle, la même troncature et le même écho de la sortie, le même répertoire de travail et la même annulation que bash, les mêmes dialogues de permission (voir yolo et permissions), et les hooks preToolCall / postToolCall. Les skills restent l'endroit du savoir-faire et des procédures ; un skill peut aussi dire au modèle d'appeler un outil déclaré.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# Les outils déclarés — explication

## De quoi s'agit-il ?

Avant le ticket 88, mm offrait deux façons de laisser le modèle lancer l'une de vos commandes : un [skill](../how-to/add-a-skill.md) qui dit « appelle ton outil `bash` avec cette commande », et un serveur MCP qui expose un outil. Les outils déclarés en sont une troisième : une entrée `tools:` dans le fichier d'agent, qui transforme une commande en outil typé, sans serveur à écrire. Cette page explique pourquoi ils ont été ajoutés à côté des skills plutôt qu'à leur place, et pourquoi ils ont cette forme.

## Pourquoi les skills ne suffisaient pas

Un skill lance une commande en deux temps. Le modèle doit d'abord trouver le skill dans le catalogue et appeler `read_skill`, puis composer une ligne de commande `bash` à partir de ce qu'il a lu. Chaque étape peut échouer, et sur un petit modèle, elle échoue :

- **Le skill n'est jamais trouvé.** Le catalogue est aiguillé par le modèle, qui lit des noms, des descriptions et des mots-clés. Mesuré sur mellum2-12b, un skill `status` (« Report the status of one of the company's services ») n'a jamais été lu pour « What is the status of the billing service? » — 0 run sur 10, en anglais comme en français. Le modèle a improvisé `curl localhost:8080/health` et `ps aux | grep billing`, puis a répondu que le service « semble tourner ». C'est une mauvaise réponse, pas seulement un raté.
- **La commande est réécrite.** Quand le skill est sauté mais que le modèle trouve quand même le script, il devine les arguments : `./pkgtest.sh greet` au lieu de `./greet`.
- **Le consentement est tout ou rien.** Tout ce qu'un skill lance passe par `bash`, donc « toujours autoriser ce script » ne peut se dire que « toujours autoriser bash ».

Un outil déclaré supprime l'étape d'aiguillage : son nom, sa description et ses paramètres figurent dans chaque requête, comme ceux de `bash`.

## Ce qui a été mesuré

Trois actions (`release <version> <channel>`, `pkgtest <package>`, `status <service>`), chacune demandée en anglais et en français, 5 runs chacune, `mm -p`, sur deux modèles. Un run réussit quand le script a vraiment tourné avec exactement les arguments attendus — vérifié dans un fichier que le script écrit, pas dans la réponse du modèle.

| Modèle | Skill + `bash` | Outil typé via une doublure MCP | Outil déclaré |
|--------|----------------|----------------------------------|---------------|
| mellum2-12b | 15/30 (4,5 s en moyenne) | 25/30 (2,8 s) | 30/30 (1,3 s) |
| qwen3.5-4b | 30/30 (12,7 s) | 30/30 (7,7 s) | 30/30 (5,8 s) |

La doublure MCP a été mesurée en premier, avant d'écrire la moindre ligne : un petit serveur MCP HTTP exposant les trois mêmes outils donnait la même comparaison sans rien construire. C'est elle qui a tranché la question. Les outils déclarés ont été mesurés à nouveau une fois construits.

Deux choses ressortent. D'abord, un outil typé est plus rapide même quand le skill fonctionne : un aller-retour avec le modèle au lieu de deux. Ensuite, les cinq échecs de la doublure sur mellum2 — la demande de release en français — venaient du modèle qui tassait tous les arguments dans un seul champ : `{version: "1.4.2 1.4.2, channel beta"}`. Avec l'outil déclaré, la même demande a réussi 5 fois sur 5, chaque fois en un seul appel. L'outil déclaré diffère de la doublure sur plusieurs points à la fois — pas de préfixe `proj_` dans le nom, pas de « MCP tool from server … » dans la description, une phrase finale « Give each parameter as its own field. » — et l'effet de chacun n'a pas été mesuré séparément.

Ces chiffres viennent d'un seul petit projet de test, de deux modèles et de cinq runs par cas. Ils répondent à « est-ce que ça vaut la peine de le construire ? », pas à « de combien est-ce mieux en général ? ».

## Pourquoi c'est conçu ainsi

**Pas de shell.** La commande est une liste, une entrée argv par élément, et une valeur remplace son `{{placeholder}}` à l'intérieur d'une seule entrée. Une valeur du modèle — ou une valeur qu'une injection de prompt aurait glissée dans la conversation — ne peut ni ajouter un argument, ni enchaîner une seconde commande, ni rediriger une sortie : `1.4.2; rm -rf ~` arrive au script comme une seule chaîne de version, étrange. Un modèle de type `command: "./release.sh {{version}}"` exécuté par `bash -c` a été écarté pour exactement cette raison. Une commande qui a besoin d'un pipe va dans un script.

**Le programme ne peut pas venir d'un paramètre.** Sinon, un outil déclaré n'est qu'un `bash` avec des étapes en plus.

**Les appels invalides reçoivent une réponse, pas un rejet par le schéma.** Le schéma que lit le modèle porte les types, mais pas `required` ni `enum` comme mots-clés — ceux-là vont dans les descriptions. Genkit valide un appel contre le schéma déclaré avant de lancer l'outil, et un appel qu'il rejette met fin au tour. mm préfère répondre en texte, en disant ce qui ne va pas, ce que le modèle a envoyé et ce que doit être chaque paramètre, pour que le modèle puisse réessayer. Le même choix a été fait pour les outils MCP. Citer l'appel compte : informé seulement que « channel is missing », mellum2 a renvoyé le même appel tassé six fois, jusqu'à ce que le [détecteur de boucle](../reference/tools.md#détection-de-boucle) arrête le tour.

**Une conversion tolérante, rien de plus.** Les modèles écrivent `"3"` pour 3 et `"true"` pour true assez souvent pour que ces chaînes soient acceptées. Ce qui demanderait de deviner (`"yes"`, `"three"`) est refusé, avec la raison.

**Le consentement suit `yolo`.** Un outil déclaré exécute quelque chose : avec `yolo: false`, il demande comme `bash` ; avec `yolo: true`, il ne demande pas. Demander « même en yolo » a été envisagé puis écarté : c'est l'auteur de l'agent qui a écrit la commande, ce qui engage déjà plus qu'un modèle qui compose une ligne `bash`.

**Les noms sont réservés tôt.** Un outil déclaré ne peut pas prendre le nom d'un outil intégré, même désactivé, pour que l'activer plus tard ne casse pas le fichier. Un conflit avec un outil MCP ne se voit qu'une fois le serveur interrogé : c'est donc un avertissement au démarrage, pas une erreur.

## Alternatives écartées

- **Seulement des skills.** Moins chers à écrire et adaptés aux procédures, mais mesurés en échec là où ça compte, sur les petits modèles que vise mm.
- **Seulement MCP.** Donne déjà des outils typés, mais chacun demande un serveur à écrire, à lancer et à maintenir, en HTTP seulement (mm n'a pas de transport MCP stdio). Trop lourd pour « lancer ce script avec deux arguments ».
- **Un système de plugins Wasm** (ticket 46). Des outils isolés sont une autre question ; un outil déclaré s'exécute avec les droits de l'utilisateur, comme `bash`.

## Liens avec le reste

Les outils déclarés se rangent à côté des outils intégrés : le même détecteur de boucle, la même troncature et le même écho de la sortie, le même répertoire de travail et la même annulation que [`bash`](../reference/tools.md#bash), les mêmes dialogues de permission (voir [yolo et permissions](yolo-and-permissions.md)), et les [hooks](hooks.md) `preToolCall` / `postToolCall`. Les skills restent l'endroit du savoir-faire et des procédures ; un skill peut aussi dire au modèle d'appeler un outil déclaré.