Last updated on

J’ai ajusté chaque ligne de config.yaml Hermes — 3 paramètres qui empêchent les tâches longues de se bloquer


Ce qu’il y a de plus frustrant avec Hermes Agent sur des tâches complexes, ce n’est pas d’obtenir une mauvaise réponse — c’est de voir le travail se figer à mi-parcours : les appels API restent en suspens, la taille du contexte explose après de nombreux tours, ou un outil en échec reste coincé dans une boucle de réessais sans fin. La plupart du temps, ce ne sont pas des problèmes de modèle. Ce sont des valeurs par défaut dans ~/.hermes/config.yaml qui n’ont pas été ajustées pour les travaux longs.

Après avoir exécuté des centaines de tâches longues, j’ai passé ma configuration ligne par ligne et j’ai découvert que seuls trois paramètres déterminent vraiment si une tâche longue se termine en douceur. Réglez-les en fonction de votre charge de travail, et la plupart des tâches complexes se termineront sans intervention manuelle.

Ci-dessous, chaque section suit le schéma : symptôme → cause → correction → valeurs recommandées, avec des extraits YAML prêts à copier-coller.


Paramètre 1 : Mettre un harnais serré aux appels API — Délais d’attente des fournisseurs

Les symptômes

  • La tâche atteint 50 %, le terminal devient silencieux, et après trente secondes s’affiche « Connection timed out. »
  • Un travail en arrière-plan ou un cron affiche running, mais le journal n’a pas bougé depuis plusieurs minutes.
  • Après avoir changé de fournisseur OpenRouter, les réponses deviennent erratiques et s’interrompent parfois complètement.

La cause

Par défaut, les appels API d’Hermes se basent sur deux variables d’environnement : HERMES_API_TIMEOUT (1800 s) et HERMES_API_CALL_STALE_TIMEOUT (90 s). Cependant, les clés request_timeout_seconds et stale_timeout_seconds sous le bloc providers dans config.yaml sont prioritaires ; les variables d’environnement ne sont utilisées que lorsque aucune configuration n’est définie.

Sans ajustement par fournisseur :

  • Les modèles cloud avec réflexion longue (Claude Opus, o1, deep-research) peuvent être interrompus avant d’avoir fini.
  • Les points de terminaison locaux (LM Studio, Ollama, vLLM) peuvent mettre plusieurs dizaines de secondes à démarrer à froid, mais les délais d’attente par défaut sont beaucoup plus courts.
  • Un seul fournisseur défaillant peut bloquer toute l’exécution car il n’y a pas de délai d’attente explicite.

La correction

Ajoutez un bloc providers en haut de config.yaml et ajustez-le par fournisseur :

providers:
  anthropic:
    request_timeout_seconds: 600      # tolérer 10 min pour une réflexion lente
    stale_timeout_seconds: 300      # appels non-streaming uniquement
  openrouter:
    request_timeout_seconds: 300
    stale_timeout_seconds: 120
  lmstudio:
    request_timeout_seconds: 300      # le démarrage à froid local est lent
    stale_timeout_seconds: 900        # réactiver explicitement la détection de stale
  ollama-local:
    request_timeout_seconds: 300
    stale_timeout_seconds: 900

Si vous utilisez principalement un seul fournisseur, configurer uniquement ce fournisseur suffit. request_timeout_seconds est passé directement au SDK sous la forme timeout=, écrasant la variable d’environnement héritée.

Valeurs recommandées

Scénario request_timeout_seconds stale_timeout_seconds
Modèles cloud rapides (Claude 3.5 Sonnet, GPT-4o mini) 60–120 60–90
Modèles à réflexion longue (Claude Opus, o1, deep-research) 300–600 120–300
Modèles locaux (LM Studio / Ollama / vLLM) 180–300 600–900
Travaux en arrière-plan / cron 300–600 120–300

Note : stale_timeout_seconds ne s’applique qu’aux appels non-streaming. Les appels en streaming sont considérés comme vivants tant que les tokens continuent d’arriver.


Paramètre 2 : Ne laissez pas le contexte exploser en premier — Stratégie de compression

Les symptômes

  • Après de nombreux tours d’outils, le modèle commence à répondre hors sujet ou renvoie « context length exceeded. »
  • La compression se déclenche trop tard, à 80 % de la fenêtre, et compresse déjà des résultats intermédiaires importants.
  • Après compression, l’agent « oublie » des éléments que vous venez de confirmer : clés API, chemins de fichiers, contraintes.

La cause

Le bloc compression d’Hermes se déclenche lorsque l’utilisation des tokens atteint threshold × context_length. Les valeurs par défaut peuvent ne pas convenir à votre charge de travail :

  • threshold: 0.50 est agressif pour un contexte de 200K mais trop tardif pour un contexte de 32K.
  • protect_last_n: 20 ne conserve que les 20 derniers messages, ce qui ne couvre peut-être que 2 à 3 tours critiques dans une tâche longue.
  • target_ratio: 0.20 détermine la quantité de queue récente à conserver ; trop petit perd des détails, trop grand gaspille de l’espace.

Il existe aussi une règle cachée dans le code : pour les modèles dont les fenêtres de contexte sont inférieures à 512K, le seuil est plafonné à 0,75. Ainsi, les modèles à petite fenêtre ne se déclenchent pas du tout à 50 % — ils se déclenchent à 75 %. Savoir cela vous aide à estimer le point de compression réel.

La correction

compression:
  enabled: true
  threshold: 0.65           # se déclencher plus tôt que la valeur par défaut
  target_ratio: 0.25        # conserver 25 % de la queue récente
  protect_last_n: 30        # ~15 tours complets
  protect_first_n: 1        # uniquement le prompt système + premier message utilisateur
  codex_app_server_auto: native

Si votre tâche nécessite un contexte précoce fréquent (par exemple, « utilisez toujours Python 3.11 », « ce projet utilise pnpm »), augmentez protect_first_n à 3. Sinon, gardez-le à 1 pour économiser de l’espace.

Valeurs recommandées

Contexte du modèle threshold target_ratio protect_last_n
≤ 32K (Claude 3.5 Sonnet, GPT-4o) 0.75 (plancher par défaut) 0.25 30–40
128K–200K 0.60–0.65 0.20–0.25 20–30
≥ 1M (Gemini, Kimi k1.5) 0.50–0.55 0.15–0.20 20

Astuce : le résumé de compression utilise par défaut Gemini Flash, qui est rapide et bon marché. Pour les tâches très orientées code, vous pouvez fixer un autre modèle sous auxiliary.compression, mais la valeur par défaut est généralement suffisante.


Paramètre 3 : Verrouiller la boucle d’outils — agent.max_turns

Les symptômes

  • Une tâche simple invoque 50 tours d’outils et l’agent répète encore « laissez-moi vérifier. »
  • Un petit accroc réseau fait qu’un outil échoue plusieurs fois, plongeant l’agent dans une spirale de réessais et faisant grimper votre facture.
  • Un travail en arrière-plan tourne pendant une demi-heure et s’avère coincé dans une boucle.

La cause

agent.max_turns limite le nombre d’itérations d’appels d’outils que l’agent peut effectuer dans une seule requête utilisateur. La valeur par défaut de 60 suffit pour des questions-réponses occasionnelles, mais elle est rapidement épuisée par le débogage complexe, le traitement par lots ou les confirmations itératives. Sans limite, un outil en échec peut réessayer indéfiniment.

Associer max_turns avec tool_loop_guardrails.hard_stop_enabled crée un disjoncteur pour les boucles anormales.

La correction

agent:
  max_turns: 100              # marge pour les tâches complexes
  api_max_retries: 2          # échouer vite et laisser le fallback prendre le relais
  reasoning_effort: medium

tool_loop_guardrails:
  warnings_enabled: true
  hard_stop_enabled: true     # disjoncteur pour les boucles anormales
  warn_after:
    exact_failure: 2
    same_tool_failure: 3
    idempotent_no_progress: 2
  hard_stop_after:
    exact_failure: 5
    same_tool_failure: 8
    idempotent_no_progress: 5

Valeurs recommandées

Type de tâche max_turns hard_stop_enabled
Questions-réponses simples / requêtes en une étape 30–40 false
Débogage de code / complexité moyenne 60–80 true
Traitement par lots / travaux longs en arrière-plan 100–150 true
Recherche exploratoire / refactoring multi-fichiers 100–200 true

Note : max_turns est la limite d’itérations d’outils par requête, et non la limite de messages sur toute la durée de vie de la session. Vous pouvez réinitialiser le contexte à tout moment avec /new ou d’autres commandes de gestion de session présentées dans notre panorama des commandes Hermes v0.18.


Référence complète : Un extrait de config.yaml prêt à l’emploi

Voici un extrait consolidé pour la configuration courante : OpenRouter comme fournisseur principal + modèles locaux occasionnels + tâches longues fréquentes :

model:
  default: "anthropic/claude-opus-4.6"
  provider: "auto"
  base_url: "https://openrouter.ai/api/v1"

providers:
  anthropic:
    request_timeout_seconds: 600
    stale_timeout_seconds: 300
  openrouter:
    request_timeout_seconds: 300
    stale_timeout_seconds: 120
  lmstudio:
    request_timeout_seconds: 300
    stale_timeout_seconds: 900

compression:
  enabled: true
  threshold: 0.65
  target_ratio: 0.25
  protect_last_n: 30
  protect_first_n: 1
  codex_app_server_auto: native
  codex_gpt55_autoraise: true

agent:
  max_turns: 100
  api_max_retries: 2
  reasoning_effort: medium

tool_loop_guardrails:
  warnings_enabled: true
  hard_stop_enabled: true
  warn_after:
    exact_failure: 2
    same_tool_failure: 3
    idempotent_no_progress: 2
  hard_stop_after:
    exact_failure: 5
    same_tool_failure: 8
    idempotent_no_progress: 5

Enregistrez dans ~/.hermes/config.yaml. Les nouvelles sessions le prennent en compte immédiatement ; les sessions déjà en cours nécessitent /new pour le recharger.


Vérification : Est-ce que ça a vraiment aidé ?

Trois vérifications rapides :

  1. Déclenchez délibérément une longue réflexion. Demandez à l’agent de traiter un fichier journal de 500 lignes ou de lire dix fichiers source à la fois. Vous ne devriez plus rencontrer context length exceeded.
  2. Simulez des à-coups API. Bloquez brièvement l’IP du fournisseur avec timeout ou iptables et confirmez que l’agent échoue dans le délai configuré et tente le fallback, au lieu de rester bloqué indéfiniment.
  3. Inspectez la compression. Pendant une tâche longue, exécutez /compress ou attendez la compression automatique, puis vérifiez que les ~30 derniers messages et le prompt système sont toujours présents.

Pour les modes de défaillance plus complexes, consultez notre approfondissement sur la gestion des erreurs et la récupération d’Hermes, qui combine délais d’attente, fallbacks et réessais en une seule stratégie de résilience.


Résumé

Les tâches longues se bloquent généralement non pas parce que le modèle est devenu plus stupide, mais parce que les délais d’attente API, la compression du contexte et les limites de boucle d’outils ne sont pas alignés. Après avoir réglé ces trois paramètres :

  • Les appels API expirent proprement et passent à un autre fournisseur au lieu de rester en suspens.
  • Le contexte se compresse au bon moment, préservant les détails récents sans atteindre la limite de la fenêtre.
  • Les appels d’outils ont un plafond dur, empêchant les spirales de réessais et les factures incontrôlables.

Si vous débutez, lisez d’abord le guide d’installation pour vous assurer que votre environnement est solide, puis conservez cet extrait comme un « modèle de tâche longue » à copier pour les travaux exigeants.


Références : cet article est basé sur l’exemple officiel Hermes Agent cli-config.yaml.example et la documentation officielle.