Vous payez déjà pour de la réflexion dont vous n'avez pas besoin : le reasoning effort dans tous les sélecteurs de modèle Hermes

Il est 23 h 30 et vous demandez à Hermes de renommer formatTs en formatTimestamp dans utils/date.ts. Il termine en sept secondes — et la trace facture quelques milliers de tokens de réflexion en ultra reasoning effort. Le modèle n’est pas le problème. « Ultra » est une valeur par défaut globale que vous avez définie la semaine dernière pour une revue d’architecture, et personne n’y a touché depuis. Hermes a toujours permis de doser le reasoning effort ; les contrôles étaient simplement éparpillés entre /reasoning, config.yaml et un sous-menu de Desktop qui n’apparaissait qu’au survol. Savoir que la fonctionnalité existe et l’utiliser réellement, c’étaient deux populations distinctes.
Cela a changé avec la PR #110346 : chaque sélecteur de modèle demande maintenant le niveau d’effort juste après le choix du modèle. Ce guide passe en revue les six endroits où définir l’effort (exécution one-shot, session, le flag /model, les sélecteurs interactifs, hermes model et Desktop), ainsi que la précédence entre eux — pour que vous payiez la réflexion dont une tâche a besoin plutôt que celle que vous aviez configurée la semaine dernière.
Ce que le reasoning effort contrôle réellement
Le reasoning effort est le budget de réflexion qu’un modèle est autorisé à dépenser avant de répondre. Pour les modèles qui exposent ce contrôle, le niveau est traduit dans les paramètres thinking/reasoning de la requête ; pour ceux qui ne l’exposent pas, le réglage est simplement inerte.
Il existe exactement une source de vérité pour l’échelle, dans hermes_constants.py :
VALID_REASONING_EFFORTS = ("minimal", "low", "medium", "high", "xhigh", "max", "ultra")
Sept niveaux, du plus bas au plus haut. parse_reasoning_effort() transforme un mot saisi en dict de config : un niveau reconnu devient {"enabled": True, "effort": "<level>"}, une chaîne vide ou un mot non reconnu renvoie None (ce qui veut dire « utiliser la valeur par défaut du provider »), et none est un interrupteur d’arrêt explicite — reasoning_effort: false et none signifient tous deux « ne pas réfléchir ».
Le point important : cela s’applique par requête. Sur un même modèle, l’écart de qualité entre low et ultra est généralement bien plus petit que l’écart de latence et de coût. La vraie question n’est donc jamais « quel niveau est le meilleur », mais « combien de niveaux cette tâche vaut-elle ».
| Portée | Comment le définir | Où cela atterrit |
|---|---|---|
| Une seule exécution | hermes --reasoning low -z "..." |
ce processus, rien n’est écrit |
| Session courante (CLI classique) | /reasoning high |
surcharge de session |
| Session courante, avec changement de modèle | /model X --reasoning high |
pins de session |
| Votre valeur par défaut globale | /reasoning high --global |
agent.reasoning_effort |
| Chaque modèle que vous nommez | agent.reasoning_overrides |
par modèle, l’emporte sur la valeur globale |
| Une tâche auxiliaire | hermes model → Configure auxiliary models… |
auxiliary.vision.reasoning_effort |
| Chaque subagent | delegation.reasoning_effort |
le bloc delegation |
| Un chat Desktop | la pastille de reasoning du composer | cette session |
Le plus petit levier : les exécutions one-shot
Si vous lancez une commande unique pour un travail bien compris, vous n’avez pas besoin de toucher à la config. Le flag --reasoning de premier niveau existe exactement pour cela :
# One-shot : un renommage. Low suffit largement.
hermes --reasoning low -z "rename formatTs to formatTimestamp in utils/date.ts"
# Interactif, mais cette session nettoie des comptes rendus en désordre
hermes chat --reasoning high
L’aide précise explicitement que cela ne remplace l’effort effectif que pour cette exécution ; le niveau persistant reste dans config.yaml (ou par modèle sous agent.reasoning_overrides). Pour les scripts shell, les jobs CI et le travail par lots sur des fichiers, c’est l’option la plus propre : l’effort voyage avec la commande au lieu de devenir discrètement la valeur par défaut de demain.
Sessions : /reasoning et /model --reasoning
Dans le CLI classique, /reasoning est la commande dédiée — elle gère à la fois le niveau d’effort et la façon dont le reasoning est affiché :
/reasoning high # cette session uniquement
/reasoning high --global # écrit agent.reasoning_effort pour les exécutions futures
/reasoning # sans argument : choisir de façon interactive
/reasoning show # affiche/masque le flux de reasoning (full affiche tout)
/reasoning none # désactive le reasoning
La PR #110346 a fait du changement de modèle et du réglage d’effort un seul et même geste. Le parseur de /model accepte maintenant --reasoning <level>, si bien qu’une seule requête porte à la fois le modèle choisi et son effort :
/model openrouter/anthropic/claude-opus-4.8 --reasoning high
Trois détails qui reviennent sans cesse :
- La portée suit le changement de modèle. Session par défaut ;
--globalécritagent.reasoning_effort;--oncecapture la valeur courante, applique l’effort pour un seul tour, puis la restaure ensuite. - L’effort est appliqué après la bascule d’agent. Ce n’est pas un détail : le chemin de bascule re-résout
reasoning_configdepuisconfig.yaml, donc écrire l’effort en premier serait écrasé. L’ordre est délibéré. - Un niveau invalide produit une erreur au lieu de ne rien faire en silence.
/model --reasoning turborenvoie/model --reasoning takes none, minimal, low, medium, high, xhigh, max or ultra.
Vous pouvez aussi vous passer complètement des flags. Le sélecteur interactif /model compte désormais trois étapes — provider, modèle, puis une troisième étape intitulée Reasoning effort for <model> qui liste toute l’échelle, plus une ligne none (désactiver le reasoning) et une ligne « conserver la valeur actuelle ». Quand la carte de capacités de la route indique qu’il n’y a pas de contrôle de reasoning, cette troisième étape est masquée plutôt que d’offrir une molette qui ne fait rien.
Le TUI Ink (hermes --tui) déroule le même flux en trois étapes ; l’étape 3 est libellée Reasoning effort (step 3/3) et émet modèle, provider, effort et portée comme une seule commande gateway. Sur les plateformes de messagerie (Telegram, Slack et compagnie), /model --reasoning passe par le même applicateur que /reasoning, donc les deux ne peuvent pas diverger.
hermes model : l’étape d’effort pour le modèle principal et chaque tâche auxiliaire
hermes model est le point d’entrée que la plupart des gens utilisent en premier (voir la référence de hermes model). Avant la PR #110346, il ne posait la question de l’effort que sur les routes Copilot, et le flux auxiliaire ne la posait jamais.
Désormais :
- Une fois le modèle principal enregistré, une étape commune suit : les sept niveaux, Disable reasoning, et Skip pour conserver la valeur actuelle. Les modèles que le catalogue marque comme dépourvus de contrôle de reasoning sautent l’étape.
- La liste des providers a gagné une ligne Reasoning effort for the current model… pour quand vous voulez ne changer que l’effort.
- Configure auxiliary models… (provider → modèle) se termine par la même étape d’effort, plus une ligne Provider default qui laisse le niveau au provider. Ces valeurs sont stockées sous
auxiliary.<task>.reasoning_effort, oudelegation.reasoning_effortpour la délégation. - La liste des tâches affiche le niveau en ligne, par ex.
openrouter · model · high, et Reset all to auto efface toutes les surcharges d’un coup. - Les blocs qui n’ont délibérément pas cette clé — les slots MoA et
memory_query_rewrite— sautent l’étape. Ils ne sont pas oubliés pour autant ; leur profondeur se configure ailleurs.
Pourquoi cela compte plus qu’il n’y paraît : la compression, la génération de titres et les vérifications d’approbation tournent à chaque tour. Les faire passer de high à minimal (ou les désactiver) économise plus d’argent que n’importe quel réglage fin du niveau du modèle principal.
Desktop : la pastille du composer, et l’effort par tâche dans Settings
Le sélecteur de modèle de Desktop vit dans le composer, juste à gauche du micro. Avant la PR #109907, le seul contrôle d’effort était un sous-menu au survol à l’intérieur d’une ligne de modèle ; la pastille combinée affichait Deepseek V4 Flash · Med, les utilisateurs y lisaient « ce modèle ne fait que du medium », et le sous-menu restait introuvable.
Désormais, l’effort a sa propre affordance :
- Une pastille de reasoning à côté de la pastille de modèle affiche le niveau réellement en vigueur pour cette surface (valeur de session d’abord, sinon la valeur par défaut de la config) et ouvre directement les lignes Thinking / Fast / Effort. Elle se masque quand le catalogue signale
reasoning: falsepour le modèle actif, et reste visible tant que les capacités sont encore inconnues, pour ne jamais clignoter pendant la récupération du catalogue. - La pastille de modèle ne replie plus l’effort dans son propre libellé ; chaque contrôle dit une seule chose.
L’effort par tâche côté Desktop a demandé deux PR de plus. La #110435 a ajouté un sélecteur Reasoning à chaque ligne sous Settings → Model → Auxiliary models : inherit · main model effort (la valeur par défaut, qui supprime la surcharge de cette tâche), Off, ou un niveau — en écrivant la même clé auxiliary.<task>.reasoning_effort que hermes model. Le contrat d’API derrière mérite d’être connu : omettre le champ laisse une surcharge intacte, passer un null explicite l’efface (retour à l’héritage), passer un niveau la définit. Une valeur inconnue comme turbo renvoie un 400 qui liste tous les niveaux acceptés au lieu d’être ignorée.
La PR #110535 a bouclé la question des pins auxiliaires de Desktop : les 11 slots peuvent être épinglés, enregistrer des Settings sans rapport ne réécrit ni ne supprime plus ces pins (les écritures de config sont devenues limitées à une section, au lieu de réécrire sur disque un instantané entièrement déployé), et quand une tâche de revue est routée vers un autre modèle, son reasoning effort est honoré au lieu d’être avalé par le réglage de la session parente.
Un piège à connaître : l’application Desktop mémorise localement un preset effort/fast par modèle. C’est une commodité pour l’application et cela ne change ni les crons ni les subagents — pour ceux-là, utilisez hermes model ou le fichier de config.
Comment les couches s’empilent, et où model_overrides s’insère
Précédence, du plus fort au plus faible (c’est aussi l’ordre de résolution à l’exécution) : surcharge de session (/reasoning --session, /model --reasoning) → surcharge par modèle agent.reasoning_overrides → valeur par défaut globale agent.reasoning_effort. Un config.yaml à copier :
agent:
# La valeur par défaut globale ; c'est la ligne qu'écrit `/reasoning high --global`
reasoning_effort: medium
# Par modèle : les clés tolèrent l'orthographe (exacte, points/tirets interchangeables,
# préfixe de provider optionnel), la première correspondance gagne, et elle l'emporte sur la valeur ci-dessus.
# Pas de prise en charge de `hermes config set` pour cette clé — éditez le YAML directement.
reasoning_overrides:
"openrouter/anthropic/claude-opus-4.8": high
"deepseek/deepseek-v4-flash": low
auxiliary:
compression:
reasoning_effort: minimal # résumer l'historique n'exige pas de réflexion profonde
title_generation:
reasoning_effort: none # les titres : coupez simplement
vision:
reasoning_effort: "" # vide = valeur par défaut du provider
delegation:
reasoning_effort: low # subagents ; laisser vide pour hériter du parent
model_overrides joue ici un rôle différent (voir le guide model_overrides) : c’est là que vivent les métadonnées de modèle — context_window, supports_vision, supports_reasoning et compagnie. Il ne définit pas l’effort, mais il décide si le contrôle de l’effort existe tout court : quand la carte de capacités dit qu’une route n’a pas de contrôle de reasoning, l’étape de hermes model, la troisième étape du sélecteur /model et la pastille Desktop se masquent ensemble. Donc si vous êtes sur un modèle local ou tout nouveau dont le catalogue n’a jamais entendu parler, déclarez d’abord les capacités : les contrôles d’effort apparaîtront.
Deux exceptions à intégrer :
background_review.reasoning_effortest ignoré tant que la revue reste sur le modèle principal. Dans ce cas, le fork hérite mot pour mot de la config de reasoning de la conversation, ce qui garde les octets de sa requête sur le préfixe de cache de prompt du parent. Pour obtenir un autre modèle et un autre effort, définissez aussi le provider/modèle de la revue — sinon Hermes vous avertit une fois, volontairement.- L’effort MoA se configure par slot à l’intérieur du preset, pas sur le bloc auxiliaire :
moa.presets.<name>.reference_models[].reasoning_effortetaggregator.reasoning_effort. Chaque référence peut tourner à sa propre profondeur et l’agrégateur peut aller plus loin — d’où l’absence assumée de cléreasoning_effortdans les blocs MoA.
Une configuration de départ qui s’autofinance
Si vous préférez ne pas garder toute la chaîne de précédence en tête, faites ces cinq choses :
- Laissez le modèle principal sur
medium. Élevez-le pour une tâche ponctuelle avec/model ... --reasoning highplutôt que de modifier la valeur globale. - Lancez
hermes model→ Configure auxiliary models… et mettez compression surminimalet title_generation sur off. Ces tâches tournent à chaque tour, donc le retour sur investissement est immédiat. - Définissez
delegation.reasoning_effort: low. Les subagents exécutent en général une tâche déjà décomposée ; ils n’ont pas besoin de la replanifier. - Utilisez
hermes --reasoning low -z "..."pour les scripts et les jobs one-shot, afin qu’un besoin temporaire ne devienne jamais une valeur par défaut permanente. - Si une longue exécution cale, vérifiez le budget de tours avant de demander plus de réflexion — c’est le sujet du guide max_turns. Et sur les routes en offre gratuite, la configuration sans clé API se marie bien avec
minimal.
La version courte
Le reasoning effort n’est pas une molette de réglage où « plus haut, c’est mieux » ; c’est un problème de portée. Dans un seul config.yaml, vous avez des molettes distinctes pour la session, par modèle, par tâche auxiliaire et par subagent. La PR #110346 a déplacé ces molettes sur les sélecteurs que vous utilisez déjà — il ne reste qu’à décider combien de niveaux chaque travail mérite, pour qu’une revue du mois dernier cesse de payer le tarif ultra pour un renommage ce mois-ci.