bots-garden/mini-mepublic Fork
⑂ v0.2.6
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. 015bd7a · on v0.2.6 · k33g · 23d ago
verify-tool-order.md · 131 lines · 6.9 KBmarkdown
Blame HistoryOpen raw

Vérifier que les outils partent dans un ordre stable

Depuis le ticket 53, mm envoie les outils de chaque requête triés par nom, pour qu'un serveur llama.cpp puisse réutiliser le prompt qu'il a mis en cache à la question précédente. Ce guide montre comment vérifier cette modification : rien n'a régressé, l'ordre est stable, et combien de lecture de prompt elle économise sur votre serveur et votre modèle.

Il suppose un clone de mm, la chaîne d'outils Go, python3, et un Docker Model Runner ou un llama-server lancé avec un modèle qui sait appeler des outils.

1. Lancer la suite de tests

Depuis la racine du dépôt :

go test ./...

Chaque paquet doit répondre ok. Lancez ensuite les tests de cette modification seuls, plusieurs fois — le bug était aléatoire, un seul passage au vert ne prouve pas grand-chose :

go test ./internal/engine -run 'TestToolsGoOut|TestStableTools' -count=10 -v
Test Ce qu'il vérifie
TestToolsGoOutInTheSameOrderOnEveryQuestion Douze questions à travers le vrai fournisseur llamacpp, face à un faux serveur qui enregistre les requêtes : chacune porte les sept outils triés par nom.
TestStableToolsSortsByName La liste sort triée.
TestStableToolsLeavesTheOriginalAlone La tranche qui appartient à Genkit n'est pas réordonnée sur place.
TestStableToolsIgnoresTheIncomingOrder Toutes les rotations des mêmes outils donnent la même liste.
TestStableToolsWithNoneOrOne Une requête sans outils (la requête de résumé de /compact) n'est pas modifiée.

Pour voir le premier test attraper le bug, retirez la ligne params.Request.Tools = stableTools(params.Request.Tools) de internal/engine/engine.go et relancez-le : il échoue avec des lignes comme question 2 sent the tools as [plan fetch_content bash …], want [bash edit_file …]. Remettez la ligne.

2. Construire le binaire d'avant et celui d'après

go build -o /tmp/mm-after .
git worktree add /tmp/mm-before-src 1fa0c42
(cd /tmp/mm-before-src && go build -o /tmp/mm-before .)
git worktree remove /tmp/mm-before-src

1fa0c42 est le dernier commit sans le correctif ; n'importe quel commit plus ancien convient aussi.

3. Lancer le proxy d'enregistrement

Dans un second terminal, lancez tests/tool-order/proxy.py devant le serveur de modèles :

python3 tests/tool-order/proxy.py --port 18770 --upstream http://localhost:12434

Il affiche proxy on http://127.0.0.1:18770 -> http://localhost:12434, puis une ligne par requête dès que mm interroge le modèle.

4. Préparer une configuration qui passe par le proxy

sed -e 's#^baseUrl:.*#baseUrl: http://127.0.0.1:18770/engines/v1#' \
    -e 's#^fallback:.*#fallback: ""#' \
    -e "s#^skillsDir:.*#skillsDir: $PWD/skills#" \
    agent.dmr.yaml > /tmp/agent.proxy.yaml

fallback: "" garde mm sur le proxy même si la sonde est lente. Le dossier des skills est rendu absolu parce qu'en mode éditeur un chemin relatif est lu depuis le dossier du fichier de configuration : sans cela, read_skill manquerait et la requête ne serait pas celle de tous les jours.

5. Poser les mêmes questions avec chaque binaire

tests/tool-order/session.py pose plusieurs questions dans une même session, par le protocole des éditeurs (mm -acp) :

python3 tests/tool-order/session.py /tmp/mm-before /tmp/agent.proxy.yaml \
  "Answer in one short sentence: what is Go?" \
  "Answer in one short sentence: what is Rust?" \
  "Answer in one short sentence: what is Zig?" \
  "Answer in one short sentence: what is Odin?"

Chaque question affiche question N: {'stopReason': 'end_turn', …}. Relancez la même commande avec /tmp/mm-after.

Gardez des questions courtes, qui ne modifient aucun fichier : une question qui fait écrire un fichier au modèle demande une autorisation à l'éditeur, et le script n'a personne pour la donner.

6. Lire les lignes du proxy

Chaque ligne correspond à une requête :

#6 tools=f2f7a1fa ['bash', 'edit_file', 'fetch_content', …] cache_n=3381 prompt_n=20 prompt_ms=253
Champ Signification
tools= Une empreinte du bloc des outils, tel qu'il a été envoyé.
[…] Les noms des outils, dans l'ordre d'envoi.
cache_n Les tokens du prompt repris du cache du serveur.
prompt_n Les tokens du prompt qu'il a dû relire.
prompt_ms Le temps passé à les relire.

Ce qu'il faut regarder :

  • Après la modification, tools= a la même valeur sur toutes les lignes, et à partir de la deuxième question prompt_n reste petit (la nouvelle question et la réponse précédente) pendant que cache_n couvre le reste du prompt.
  • Avant la modification, tools= change d'une question à l'autre, et à chaque changement prompt_n remonte à la taille du prompt entier.

La première question d'une session lit le prompt entier dans les deux cas, sauf si le serveur garde encore le même préfixe d'une session précédente.

Mesuré le 30/09/2026 avec Mellum 12B sur Docker Model Runner, quatre questions, agent.dmr.yaml (six outils, skills non chargés) :

Question Avant : prompt_n / prompt_ms Après : prompt_n / prompt_ms
1 3355 / 6776 3355 / 7141
2 3401 / 7186 20 / 253
3 107 / 713 (l'ordre coïncidait par hasard avec la question 1) 20 / 257
4 110 / 707 20 / 252

Le gain grandit avec la session : avant la modification, une question dont l'ordre des outils change relit tout l'historique, pas seulement les outils.

7. Vérifier le reste à la main

La modification touche toutes les requêtes : vérifiez une fois que l'usage ordinaire fonctionne toujours avec le nouveau binaire et votre configuration habituelle.

  • Une question qui demande un outil : /tmp/mm-after -config agent.dmr.yaml -p "list the files of this directory" lance bash et répond.
  • Une longue session qui se compresse : /compact écrit toujours un résumé (sa requête n'a pas d'outils et n'est pas touchée).
  • Un serveur MCP, si vous en utilisez un : ses outils sont triés avec les outils intégrés et toujours appelés par leur nom.

Variantes

  • llama-server : lancez le proxy avec --upstream http://localhost:8080, et partez de agent.llamacpp.yaml avec baseUrl: http://127.0.0.1:18770/v1.
  • mm ou le serveur dans un conteneur : utilisez --upstream http://host.docker.internal:12434 pour un Docker Model Runner sur l'hôte.
  • Un autre modèle : la taille des prompts change, pas le schéma. Les chiffres ci-dessus sont un exemple, pas un objectif.

Voir aussi

  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
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# Vérifier que les outils partent dans un ordre stable

Depuis le ticket 53, `mm` envoie les outils de chaque requête triés par nom, pour qu'un serveur llama.cpp puisse réutiliser le prompt qu'il a mis en cache à la question précédente. Ce guide montre comment vérifier cette modification : rien n'a régressé, l'ordre est stable, et combien de lecture de prompt elle économise sur votre serveur et votre modèle.

Il suppose un clone de `mm`, la chaîne d'outils Go, `python3`, et un Docker Model Runner ou un `llama-server` lancé avec un modèle qui sait appeler des outils.

## 1. Lancer la suite de tests

Depuis la racine du dépôt :

```bash
go test ./...
```

Chaque paquet doit répondre `ok`. Lancez ensuite les tests de cette modification seuls, plusieurs fois — le bug était aléatoire, un seul passage au vert ne prouve pas grand-chose :

```bash
go test ./internal/engine -run 'TestToolsGoOut|TestStableTools' -count=10 -v
```

| Test | Ce qu'il vérifie |
|------|------------------|
| `TestToolsGoOutInTheSameOrderOnEveryQuestion` | Douze questions à travers le vrai fournisseur `llamacpp`, face à un faux serveur qui enregistre les requêtes : chacune porte les sept outils triés par nom. |
| `TestStableToolsSortsByName` | La liste sort triée. |
| `TestStableToolsLeavesTheOriginalAlone` | La tranche qui appartient à Genkit n'est pas réordonnée sur place. |
| `TestStableToolsIgnoresTheIncomingOrder` | Toutes les rotations des mêmes outils donnent la même liste. |
| `TestStableToolsWithNoneOrOne` | Une requête sans outils (la requête de résumé de `/compact`) n'est pas modifiée. |

Pour voir le premier test attraper le bug, retirez la ligne `params.Request.Tools = stableTools(params.Request.Tools)` de `internal/engine/engine.go` et relancez-le : il échoue avec des lignes comme `question 2 sent the tools as [plan fetch_content bash …], want [bash edit_file …]`. Remettez la ligne.

## 2. Construire le binaire d'avant et celui d'après

```bash
go build -o /tmp/mm-after .
git worktree add /tmp/mm-before-src 1fa0c42
(cd /tmp/mm-before-src && go build -o /tmp/mm-before .)
git worktree remove /tmp/mm-before-src
```

`1fa0c42` est le dernier commit sans le correctif ; n'importe quel commit plus ancien convient aussi.

## 3. Lancer le proxy d'enregistrement

Dans un second terminal, lancez `tests/tool-order/proxy.py` devant le serveur de modèles :

```bash
python3 tests/tool-order/proxy.py --port 18770 --upstream http://localhost:12434
```

Il affiche `proxy on http://127.0.0.1:18770 -> http://localhost:12434`, puis une ligne par requête dès que `mm` interroge le modèle.

## 4. Préparer une configuration qui passe par le proxy

```bash
sed -e 's#^baseUrl:.*#baseUrl: http://127.0.0.1:18770/engines/v1#' \
    -e 's#^fallback:.*#fallback: ""#' \
    -e "s#^skillsDir:.*#skillsDir: $PWD/skills#" \
    agent.dmr.yaml > /tmp/agent.proxy.yaml
```

`fallback: ""` garde `mm` sur le proxy même si la sonde est lente. Le dossier des skills est rendu absolu parce qu'en mode éditeur un chemin relatif est lu depuis le dossier du fichier de configuration : sans cela, `read_skill` manquerait et la requête ne serait pas celle de tous les jours.

## 5. Poser les mêmes questions avec chaque binaire

`tests/tool-order/session.py` pose plusieurs questions dans une même session, par le protocole des éditeurs (`mm -acp`) :

```bash
python3 tests/tool-order/session.py /tmp/mm-before /tmp/agent.proxy.yaml \
  "Answer in one short sentence: what is Go?" \
  "Answer in one short sentence: what is Rust?" \
  "Answer in one short sentence: what is Zig?" \
  "Answer in one short sentence: what is Odin?"
```

Chaque question affiche `question N: {'stopReason': 'end_turn', …}`. Relancez la même commande avec `/tmp/mm-after`.

Gardez des questions courtes, qui ne modifient aucun fichier : une question qui fait écrire un fichier au modèle demande une autorisation à l'éditeur, et le script n'a personne pour la donner.

## 6. Lire les lignes du proxy

Chaque ligne correspond à une requête :

```
#6 tools=f2f7a1fa ['bash', 'edit_file', 'fetch_content', …] cache_n=3381 prompt_n=20 prompt_ms=253
```

| Champ | Signification |
|-------|---------------|
| `tools=` | Une empreinte du bloc des outils, tel qu'il a été envoyé. |
| `[…]` | Les noms des outils, dans l'ordre d'envoi. |
| `cache_n` | Les tokens du prompt repris du cache du serveur. |
| `prompt_n` | Les tokens du prompt qu'il a dû relire. |
| `prompt_ms` | Le temps passé à les relire. |

Ce qu'il faut regarder :

- **Après la modification**, `tools=` a la même valeur sur toutes les lignes, et à partir de la deuxième question `prompt_n` reste petit (la nouvelle question et la réponse précédente) pendant que `cache_n` couvre le reste du prompt.
- **Avant la modification**, `tools=` change d'une question à l'autre, et à chaque changement `prompt_n` remonte à la taille du prompt entier.

La première question d'une session lit le prompt entier dans les deux cas, sauf si le serveur garde encore le même préfixe d'une session précédente.

Mesuré le 30/09/2026 avec Mellum 12B sur Docker Model Runner, quatre questions, `agent.dmr.yaml` (six outils, skills non chargés) :

| Question | Avant : `prompt_n` / `prompt_ms` | Après : `prompt_n` / `prompt_ms` |
|----------|------------------|------------------|
| 1 | 3355 / 6776 | 3355 / 7141 |
| 2 | 3401 / 7186 | 20 / 253 |
| 3 | 107 / 713 (l'ordre coïncidait par hasard avec la question 1) | 20 / 257 |
| 4 | 110 / 707 | 20 / 252 |

Le gain grandit avec la session : avant la modification, une question dont l'ordre des outils change relit tout l'historique, pas seulement les outils.

## 7. Vérifier le reste à la main

La modification touche toutes les requêtes : vérifiez une fois que l'usage ordinaire fonctionne toujours avec le nouveau binaire et votre configuration habituelle.

- Une question qui demande un outil : `/tmp/mm-after -config agent.dmr.yaml -p "list the files of this directory"` lance `bash` et répond.
- Une longue session qui se compresse : `/compact` écrit toujours un résumé (sa requête n'a pas d'outils et n'est pas touchée).
- Un serveur MCP, si vous en utilisez un : ses outils sont triés avec les outils intégrés et toujours appelés par leur nom.

## Variantes

- **llama-server** : lancez le proxy avec `--upstream http://localhost:8080`, et partez de `agent.llamacpp.yaml` avec `baseUrl: http://127.0.0.1:18770/v1`.
- **`mm` ou le serveur dans un conteneur** : utilisez `--upstream http://host.docker.internal:12434` pour un Docker Model Runner sur l'hôte.
- **Un autre modèle** : la taille des prompts change, pas le schéma. Les chiffres ci-dessus sont un exemple, pas un objectif.

## Voir aussi

- Pourquoi l'ordre compte : [fournisseurs — explication](../explanation/providers.md)
- Les clés de configuration utilisées ici : [référence de la configuration](../reference/configuration.md)
- Poser une seule question : [exécuter une invite unique](executer-une-invite-unique.md)