Afficher le résumé Masquer le résumé
- Pourquoi louer un GPU pour Hermes ?
- Le GPU, le modèle et les versions utilisés
- La commande vLLM validée à 128K
- Premier démarrage : conserver les caches et lire les logs
- Les performances : 51 tokens/s sur les prompts variés
- Ce que nous avons vérifié à 128K
- Brancher Hermes et vérifier les appels d’outils
- Erreur Hermes : « key_cmd exited 1 »
- Refaire les mesures avec le kit
- Arrêter le GPU pour maîtriser les coûts
Avant d’acheter un GPU pour faire tourner un LLM avec Hermes Agent, nous avons loué une carte sur RunPod. Hermes reste installé sur un Mac mini et communique avec le modèle par une API compatible OpenAI. Telegram sert d’interface.
La configuration finale sert une fenêtre de 131 072 tokens sur un seul GPU de 32 Go. Nous avons mesuré 51,41 tokens/s de médiane sur trois prompts courts variés, après optimisation. Voici les réglages, les résultats et un kit téléchargeable pour refaire les tests.
Expérience du 8 octobre 2026. Mesures réalisées sur une RTX 5000 Ada Generation, pas une RTX 5090. Les prix correspondent au tarif du pod pendant le test, hors stockage.
Télécharger le kit de démarrage et de benchmarks — ZIP. Aucun secret ni identifiant de notre pod n’y figure. Le README précise les adaptations nécessaires au premier lancement.
Pourquoi louer un GPU pour Hermes ?
Le montage est simple : Telegram → Hermes sur le Mac → API vLLM sur RunPod. Le GPU génère les réponses ; Hermes garde la gestion des outils, de l’historique et des actions. Cela permet d’évaluer un modèle avant d’investir dans une machine locale.
Notre contrainte était de réserver Qwen au seul topic « Runpod » du groupe Telegram. Déclarer un fournisseur nommé permet de préparer cette séparation sans modifier le modèle global. Le routage effectif doit ensuite être vérifié sur la version Hermes installée ; nous n’avons pas modifié à distance la configuration du Mac depuis le poste de test.
À lire URGENT : Anthropic Interdit OpenClaw dès Demain (4 avril 2026)
Le GPU, le modèle et les versions utilisés
| Élément | Configuration observée |
|---|---|
| GPU | 1 × NVIDIA RTX 5000 Ada Generation, 32 Go |
| Location | Pod Community Cloud à la demande, 0,49 USD/h de GPU |
| Stockage | 30 Go de disque conteneur ; 40 Go de volume local sur /workspace |
| API | Port 8000/http, protocole Chat Completions compatible OpenAI |
| Logiciels | vLLM 0.28.0 ; PyTorch 2.13.0+cu130 ; Transformers 5.16.1 |
| CUDA | 13.0.2 dans l’image ; hôte annonçant 13.1 |
| Quantification et mémoire | AWQ Marlin ; BF16 ; cache KV non quantifié ; aucun offload CPU |
Le checkpoint communautaire est shawnw3i/Huihui-Qwen3.8-27B-abliterated-AWQ-MTP. Il s’agit d’une version « abliterated », quantifiée en AWQ 4 bits avec prise en charge MTP. Ce qualificatif décrit une modification du comportement de refus ; il ne prouve pas la fiabilité des réponses.
Nous avons fixé la révision 2ed4fd44ddc181a74659737e6189cc95bd7945c9. Les fichiers de poids représentent environ 20 Go sur disque. Avec MTP, les poids chargés occupaient 18,13 Gio de VRAM. Fixer l’image Docker et la révision du modèle permet de conserver les versions lors d’une reprise.
Image exacte utilisée :
vllm/vllm-openai@sha256:2286e8533ca8b6bc777594bae30524f1426ba46ca21797524e06df6a94b06635
La commande vLLM validée à 128K
La commande suivante est celle du service final. Définissez une clé longue et aléatoire dans la variable VLLM_API_KEY du pod. Elle doit rester hors du code public. L’image doit démarrer le script avec Bash, plutôt qu’ajouter les commandes shell aux arguments de son entrypoint vLLM par défaut.
vllm serve shawnw3i/Huihui-Qwen3.8-27B-abliterated-AWQ-MTP \
--revision 2ed4fd44ddc181a74659737e6189cc95bd7945c9 \
--served-model-name qwen3.8-27b-abliterated-awq \
--host 0.0.0.0 --port 8000 \
--tensor-parallel-size 1 \
--quantization awq_marlin \
--dtype bfloat16 --kv-cache-dtype auto \
--max-model-len 131072 --gpu-memory-utilization 0.94 \
--max-num-seqs 1 --max-num-batched-tokens 2048 \
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY","cudagraph_capture_sizes":[1,4]}' --language-model-only \
--speculative-config '{"method":"mtp","num_speculative_tokens":3}' \
--cpu-offload-gb 0 \
--enable-auto-tool-choice --tool-call-parser qwen3_coder \
--reasoning-parser qwen3 \
--api-key "$VLLM_API_KEY"
max-num-seqs=1 privilégie une requête à la fois. language-model-only réserve cette expérience au texte. Les CUDA Graphs réduisent les surcoûts d’exécution ; MTP propose plusieurs tokens, puis le modèle les vérifie. Le gain dépend du contenu et des paramètres de génération : voir la documentation vLLM sur le décodage spéculatif.
Premier démarrage : conserver les caches et lire les logs
La configuration finale a été validée avec des caches de compilation préparés. Sur un volume vierge, nous ne garantissons pas que le lancement direct en 128K réussira. Le kit commence donc à 32 768 tokens, installe Transformers en ligne et permet de demander ensuite MAX_MODEL_LEN=131072. Cette adaptation de premier lancement n’a pas été déployée pendant l’expérience.
Nous avons conservé les caches Hugging Face, vLLM, Triton et uv sous /workspace. Au premier profilage MTP, le service annonçait 9,29 Gio nécessaires pour le cache, contre seulement 8,65 Gio disponibles. Le lancement suivant, avec les compilations réutilisées, disposait de 10,9 Gio de cache KV. Un redémarrage explicite a confirmé le résultat.
À lire Les agents IA embauchent maintenant des humains : OpenClaw 2026 révolutionne le travail
Une erreur de mémoire demande de consulter les journaux avant de retenter. Le réglage gpu-memory-utilization=0.94 laisse peu de marge : il faut le réévaluer sur une autre carte ou avec d’autres services utilisant le GPU.
Les performances : 51 tokens/s sur les prompts variés
| Configuration | Test synthétique | Prompts courts variés |
|---|---|---|
| Initiale : eager, sans MTP, 32K | 10,58 tok/s — une mesure | Non mesuré dans cette comparaison |
| Compilation + CUDA Graphs, 128K | 31,05 tok/s — médiane de 3 mesures | 31,16 tok/s — médiane de 3 prompts |
| Ajout MTP à 3 tokens, 128K | 72,83 tok/s — médiane de 3 mesures | 51,41 tok/s — médiane de 3 prompts |
Les trois prompts variés donnaient 56,69 tok/s pour le code, 48,25 pour un plan de migration et 51,41 pour une explication. Les sorties étaient fixées à 512 tokens, à température zéro, avec ignore_eos=true pour mesurer une génération de longueur constante.
Les 73 tok/s du test répétitif ne représentent pas toutes les conversations Hermes. Ce texte favorise les prédictions MTP. Nous n’avons pas mesuré un taux de réussite complet sur des tâches autonomes ; le benchmark de génération ne remplace pas cette évaluation.
Ce que nous avons vérifié à 128K
- 65 535 tokens d’entrée + 1 token de sortie : réussi.
- 131 071 tokens d’entrée + 1 token de sortie : réussi.
- 130 944 tokens d’entrée + 128 tokens de sortie : réussi.
Sur trois mesures avec 20 000 tokens d’entrée, le temps médian avant le premier token était de 10,13 secondes. Près de 128K, il atteignait environ 82 secondes. Le test avec 128 tokens de sortie donnait environ 31,27 tok/s en génération.
Les requêtes ont terminé sans erreur mémoire. Cela valide le chargement et la génération, pas la qualité de rappel de toutes les informations d’un document. Le maximum physique au-delà de 131 072 tokens n’a pas été recherché. Entrée et sortie partagent le même budget : réservez de la place pour la réponse.
Brancher Hermes et vérifier les appels d’outils
L’URL du proxy est https://VOTRE-POD-ID-8000.proxy.runpod.net/v1. Elle est publique : l’option api-key du serveur est indispensable pour ce montage. Nos contrôles sans clé ont reçu HTTP 401 sur les routes modèles et chat.
Fusionnez ce fournisseur dans la configuration existante, en remplaçant uniquement l’identifiant du pod :
providers:
runpod-qwen:
api: https://VOTRE-POD-ID-8000.proxy.runpod.net/v1
key_env: HERMES_RUNPOD_API_KEY
transport: chat_completions
extra_body:
chat_template_kwargs:
enable_thinking: false
models:
qwen3.8-27b-abliterated-awq:
context_length: 131072
La variable HERMES_RUNPOD_API_KEY doit être disponible dans le processus gateway réel. La définir dans un terminal séparé ne modifie pas un gateway déjà actif. Notre clé a été conservée dans 1Password. Le montage séparé ~/.hermes/runpod.env évite de remplacer le fichier global ~/.hermes/.env.
Pour un seul topic Telegram, identifiez le couple exact groupe et topic et vérifiez le résolveur de la version locale avant d’ajouter une règle. Ne supposez pas qu’une règle visant tout le groupe isole un topic. Vérifiez également la compression : un plafond absolu à 22K peut continuer à limiter l’historique malgré une fenêtre serveur de 128K.
Le test d’outil du kit réalise le cycle complet : Qwen demande addition(17,25), le client exécute l’addition, renvoie le résultat et Qwen répond 42. Déclarer un parser ne suffit pas ; cet aller-retour confirme que le client peut réellement utiliser les appels d’outils.
Erreur Hermes : « key_cmd exited 1 »
Nous avons rencontré cette erreur alors que le serveur répondait encore HTTP 200 et générait « OK ». Le problème affiché concernait la commande locale de récupération de clé. Dans Hermes, key_cmd prend priorité sur key_env : il faut réparer la commande ou assurer l’injection de la variable avant de remplacer ce mécanisme. La cause précise côté Mac n’était pas encore déterminée à la publication. La documentation des fournisseurs Hermes décrit ces mécanismes.
Refaire les mesures avec le kit
Le ZIP contient le script serveur, les benchmarks Python et un test d’outil. Les scripts client nécessitent Python 3.10 ou plus, sans dépendance tierce. Lancez-les depuis le dossier décompressé, avec votre propre URL :
export API_BASE_URL="https://VOTRE-POD-ID-8000.proxy.runpod.net/v1"
python3 with-runpod-env.py --prompt-key python3 smoke-test.py
python3 with-runpod-env.py --prompt-key python3 optimize-benchmark.py
python3 with-runpod-env.py --prompt-key python3 measure.py ttft --runs 3
python3 with-runpod-env.py --prompt-key python3 measure.py context --ceiling 131072
Le lanceur demande la clé en saisie masquée, la transmet au processus enfant et ne la sauvegarde pas. Répétez les tests au calme, sans requête Hermes concurrente. Les grands tests consomment du temps GPU facturé. Le script de contexte s’arrête au premier échec et rapporte le plus grand palier réussi jusqu’au plafond demandé.
Le débit est estimé depuis les blocs SSE côté client, en séparant la phase de génération du premier bloc. MTP peut regrouper plusieurs tokens dans un bloc. Le temps avant le premier token inclut réseau, proxy, attente éventuelle et préremplissage. Un préfixe inédit est ajouté à chaque mesure pour limiter les effets d’un prompt déjà en cache.
À lire Google transforme le terminal en développeur IA avec le nouveau Gemini CLI
Pour évaluer Hermes, ajoutez une liste de tâches identiques et comptez les succès sans intervention humaine. Le coût par tâche réussie est plus utile que le seul nombre de tokens par seconde.
Arrêter le GPU pour maîtriser les coûts
Stop libère le GPU et conserve le volume local. Le GPU n’est plus facturé, mais le stockage reste payant. Au tarif arrêté de 0,20 USD/Go/mois, nos 40 Go représentent environ 8 USD/mois. Gardez assez de crédit : RunPod indique qu’un solde nul peut entraîner la suppression des pods sans volume réseau. Voir les tarifs officiels RunPod.
Start permet de reprendre le même pod, son URL, ses paramètres et les caches conservés, si le GPU est disponible. L’arrêt libère la carte : une reprise immédiate n’est donc pas garantie. Le redémarrage du service a été testé ; le cycle Stop → Start n’a pas encore été testé dans cette expérience. Voir la documentation sur la disponibilité à la reprise.
Terminate/Delete supprime ce pod et son volume local. Il faudra télécharger et préparer à nouveau les fichiers sur un nouveau pod, puis mettre à jour l’URL côté client. Conservez l’image, la révision du modèle et les paramètres pour reconstruire le service.
Notre expérience montre l’intérêt de mesurer et d’optimiser le pod existant avant de louer plus cher. Une RTX 5090 reste une candidate pour la prochaine comparaison, mais aucun chiffre de cet article ne mesure ses performances avec ce checkpoint.
