Intégrer Jev à Hermes Agent : tutoriel MCP
Branchez Jev IA à Hermes Agent via MCP pour router les décisions, exécuter l'outil adapté et garder le LLM pour les cas complexes.
Introduction
Jev Hermes Agent, c'est l'idée de faire entrer un modèle System One dans la boucle Hermes via MCP, sans remplacer l'orchestrateur ni le LLM. Dans ce montage, Hermes reste l'orchestrateur, Jev devient un outil de décision bornée, le LLM reste réservé au raisonnement. Ce tutoriel montre comment brancher Jev IA à Hermes Agent pour reproduire le schéma « intention, agent, outil, résultat ». Il est utile dès qu'un flux répète des décisions de routage coûteuses à laisser au LLM et que vous voulez une probabilité calibrée par appel. Cette approche est inutile sans politique d'escalade, quand les décisions sont toutes ouvertes, ou si votre cas tient dans un script de 80 lignes — restez alors sur du code déterministe.
Résumé rapide
| Étape | Commande ou fichier | Ce que vous validez |
|---|---|---|
| Préparer l'environnement | uv venv .venv && source .venv/bin/activate && uv pip install fastmcp typesafe-sdk | SDK TypeSafe et FastMCP installés |
| Écrire le serveur MCP | python jev_mcp_server.py | Outil jev_decide enregistré via FastMCP |
| Connecter à Hermes | hermes mcp add jev --command "python jev_mcp_server.py" | Entrée dans mcp_servers de ~/.hermes/config.yaml |
| Vérifier la connexion | hermes mcp list puis hermes mcp test jev | Serveur actif et outil mcp_jev_jev_decide exposé |
| Router un ticket | Appel mcp_jev_jev_decide avec state + choix bornés | Décision + probabilité + escalade |
| Tester la politique | Trois scénarios : nominal, ambigu, panne | Fallback LLM/humain effectif, pas d'effet de bord |
Architecture cible : Hermes orchestre, Jev décide
L'objectif : faire entrer Jev dans la boucle Hermes, sans remplacer le routeur interne ni la mémoire. Hermes reçoit une demande — Telegram, email, ticket — et appelle l'outil MCP jev_decide pour une décision typée : un choix parmi une liste bornée, un score ou un booléen, assortis d'une probabilité calibrée. Une politique déterministe applique ensuite le résultat : outil interne, agent, LLM ou revue humaine.
canal (Telegram/email/ticket) → Hermes Agent → mcp_jev_jev_decide (FastMCP)
→ TypeSafe SDK → Jev IA → décision + probabilités + confiance
→ politique de confiance (seuils par risque)
→ outil direct | LLM Hermes | humain → action finale + logs
Limite honnête à acter : MCP expose Jev comme un outil qu'Hermes peut invoquer explicitement. Il ne remplace pas le routeur interne d'Hermes et n'intercepte pas chaque tour de boucle. Le bon comportement s'obtient via un skill ou un prompt de routage : code déterministe d'abord, Jev pour les choix bornés, LLM pour la génération, humain pour le risque élevé. Sans cette discipline, MCP reste un outil disponible mais jamais appelé.
Jev n'écrit pas la réponse finale, ne rédige pas, ne paraphrase pas. Il ne remplace pas la mémoire persistante, le contexte de session ni l'orchestration Hermes : il fournit une décision typée, l'orchestrateur agit.
Prérequis et secrets à préparer
- Hermes Agent installé : version récente avec
hermes mcp add,hermes mcp listethermes mcp test. La page Hermes Agent MCP : connecter des outils externes couvre la mécanique MCP. - Python isolé :
uv venv .venv && source .venv/bin/activate, puisuv pip install fastmcp typesafe-sdk. Vérifiez les versions contre la documentation officielle. - Clé TypeSafe : variable d'environnement, jamais dans Git. Les exemples utilisent
TYPESAFE_API_KEY=demo; remplacez par votre clé réelle dans~/.hermes/.envviaexport TYPESAFE_API_KEY="<votre-clef-reelle>". - Politique d'escalade écrite : seuils, voie LLM, voie humaine. Sans ce document, l'intégration tourne mais reste dangereuse.
Implémenter le serveur MCP Jev
L'idée est de garder le serveur minimal : un outil unique, jev_decide, qui encapsule l'appel TypeSafe et renvoie une structure contrôlée. FastMCP fournit @mcp.tool ; le SDK TypeSafe fournit l'appel au modèle.
// jev_mcp_server.py
from __future__ import annotations
import os, time
from typing import Literal
from fastmcp import FastMCP
from typesafe_sdk import TypeSafeClient, TypeSafeError
mcp = FastMCP("jev-mcp")
DecisionType = Literal["choice", "score", "noul"]
@mcp.tool
def jev_decide(state: dict, question: str, choices: list[str],
decision_type: DecisionType = "choice") -> dict:
"""Délègue une décision typée à Jev (System One TypeSafe).
Lève une exception explicite si TypeSafe est indisponible. Aucun effet de bord.
"""
if not choices or len(choices) > 16:
raise ValueError("choices doit contenir entre 1 et 16 options")
client = TypeSafeClient(api_key=os.environ["TYPESAFE_API_KEY"])
started = time.perf_counter()
try:
result = client.decide(model="jev-latest", state=state, question=question,
choices=choices, decision_type=decision_type)
except TypeSafeError as exc:
raise RuntimeError(f"TypeSafe indisponible: {exc}") from exc
p = float(result.get("probability", 0.0))
conf = "high" if p >= 0.85 else "medium" if p >= 0.6 else "low"
return {"choice": str(result["choice"]), "probability": round(p, 4),
"confidence": conf, "escalate": p < 0.6,
"latency_ms": int((time.perf_counter() - started) * 1000)}
if __name__ == "__main__":
mcp.run(transport="stdio")
Trois règles à respecter. Validation d'entrée stricte : choices borné, decision_type énuméré. Timeout explicite : 5 secondes côté client pour ne pas bloquer la boucle Hermes en cas de panne. Erreurs explicites : TypeSafeError re-levé en RuntimeError pour qu'Hermes déclenche un fallback.
Connecter le serveur Jev à Hermes
Voie CLI :
hermes mcp add jev \
--command "$(pwd)/.venv/bin/python" \
--args "$(pwd)/jev_mcp_server.py" \
--env TYPESAFE_API_KEY="${TYPESAFE_API_KEY}" \
--timeout 10
Voie déclarative dans ~/.hermes/config.yaml :
mcp_servers:
jev:
command: "/chemin/absolu/vers/.venv/bin/python"
args: ["/chemin/absolu/vers/jev_mcp_server.py"]
timeout: 10
env:
TYPESAFE_API_KEY: "${TYPESAFE_API_KEY}"
tools:
include: ["jev_decide"]
Trois points de vigilance. Chemins absolus : Hermes n'hérite pas du même répertoire qu'un shell interactif. Allowlist explicite : tools.include interdit l'ajout silencieux d'outils. Timeout aligné : 10 secondes côté Hermes doit couvrir un timeout interne plus court côté SDK.
Vérification : hermes mcp list, puis hermes mcp test jev, puis dans hermes chat : /reload-mcp. L'outil apparaît sous mcp_jev_jev_decide : préfixe mcp_jev_ pour le serveur, suffixe jev_decide pour la fonction Python. Si le nom diffère, vérifiez le filtrage et le format stdio (aucun log ne doit polluer stdout).
Définir la politique de routage dans Hermes
Le serveur MCP ne suffit pas : sans politique explicite, Hermes peut ignorer l'outil. Un skill court impose la discipline. Extrait utilisable dans un skill ~/.hermes/skills/jev-routing/SKILL.md :
// Skill : routage Jev
Tu disposes de l'outil MCP `mcp_jev_jev_decide`.
1. Si une décision est entièrement codifiable (regex, lookup, règle),
applique-la en code avant tout appel externe.
2. Sinon, si la décision est bornée et répétitive, appelle
`mcp_jev_jev_decide` avec state, question, choices.
3. Applique la politique de confiance :
- high + action réversible → exécution automatique.
- medium → LLM puis exécution.
- low ou escalate == true → revue humaine obligatoire.
4. Aucune action irréversible sans approbation humaine explicite,
quelle que soit la probabilité.
Le pseudo-code Python de la politique, testable hors Hermes, formalise les seuils par niveau de risque :
def route(jev_decision, risk: str) -> str:
"""risk ∈ {"low", "medium", "high"} : sensibilité de l'action."""
if risk == "low":
if jev_decision["confidence"] == "high": return "execute"
if jev_decision["confidence"] == "medium": return "llm_then_execute"
return "human_review"
if risk == "medium":
if jev_decision["confidence"] == "high": return "llm_then_execute"
return "human_review"
return "human_review" # risk == "high" : aucune automatisation
Une boucle entièrement pilotée par des décisions probabilistes dérive : une confiance à 0.85 sur 100 000 appels laisse 15 000 erreurs cumulées. Le seuil se fixe par décision et par niveau de risque.
Exemple concret : router un ticket de bout en bout
Cas fil rouge : une boîte de réception unifiée reçoit un ticket. L'objectif : router vers la bonne équipe sans cinq appels LLM successifs.
Étape 1 — Choix d'intention. Premier appel Jev :
{
"state": {"subject": "Commande #A-7782 non reçue"},
"question": "Quelle est l'intention principale ?",
"choices": ["commande", "facturation", "support_technique", "autre"]
}
Réponse type : {"choice": "commande", "probability": 0.91, "confidence": "high", "escalate": false}.
Étape 2 — Choix d'équipe et scoring. Deuxième appel, en parallèle pour minimiser la latence :
{
"state": {"intent": "commande", "subject": "Commande #A-7782 non reçue"},
"questions": [
{"name": "team", "question": "Quelle équipe traiter ?", "choices": ["support_client", "finance", "tech", "spam"]},
{"name": "urgency", "decision_type": "score", "scale": [0, 10]}
]
}
Réponses : team = support_client (0.87), urgency = 6 (medium).
Étape 3 — Validation. Un appel Score ou Noul évalue le résultat. Si la probabilité est élevée et l'action réversible, on continue. Sinon, on escalade.
Politique appliquée : urgency >= 7 ou confidence(team) < 0.85 → revue humaine ; urgency < 4 et confidence(intent) >= 0.85 → action automatique ; sinon → LLM léger.
Cette politique est explicite et testable. Le triplet question + answer + probability + threshold + final action doit être loggé pour chaque décision.
Tester l'intégration de bout en bout
Trois scénarios couvrent l'essentiel.
| Scénario | Entrée | Résultat attendu |
|---|---|---|
| Nominal | Ticket clair « Commande #A-7782 non reçue » | intent = commande (0.9+), team = support_client (0.85+), action automatique réversible |
| Ambigu | Deux probabilités proches (0.52 vs 0.48) | confidence = low, escalate = true, fallback LLM puis humain |
| Panne | Timeout SDK ou HTTP 429/529 | RuntimeError explicite, aucun effet de bord, fallback LLM |
Checklist d'acceptation reproductible, à dérouler après chaque changement de version du SDK ou de Hermes :
-
hermes mcp listaffichejevactif. -
hermes mcp test jevréussit sans warning. - Un appel
mcp_jev_jev_decideretourne un objet conforme au schémaDecision. - Une clé
TYPESAFE_API_KEYabsente lève une erreur explicite, aucun outil n'est appelé. - Un
timeoutcôté SDK déclenche le fallback LLM sans planter. - Les logs contiennent
run_id,question,choice,probability,threshold,final_action.
Mesurez latence, nombre d'appels et décisions avant et après l'intégration. Les gains de coût et de vitesse annoncés par les éditeurs — TypeSafe compris — restent des promesses à valider sur votre workflow réel, pas une garantie.
Bonnes pratiques
1. Allowlist d'outils MCP. N'exposez que jev_decide via tools.include. Le serveur ne fait que décider : aucun accès filesystem, aucun appel sortant non documenté. Pour un effet de bord, passez par un serveur MCP dédié. Le guide Permissions des outils pour agents IA couvre ce découpage.
2. Aucune action irréversible déclenchée par Jev seul. Paiement, suppression, e-mail sensible, rotation de credentials : approbation humaine obligatoire, quelle que soit la probabilité. Règle simple : Jev informe, l'orchestrateur agit, l'humain arbitre. Le tutoriel Human-in-the-loop pour agents IA détaille les patterns d'escalade.
3. Redaction des secrets. La clé TypeSafe vit dans ~/.hermes/.env, jamais dans config.yaml. Profils dev et prod distincts.
4. Politique de routage écrite et versionnée. Skill ou prompt : artefact de code, testé, relu, revu en PR. Le tutoriel Model routing pour agents IA complète cette vision. Mesurez la calibration avant la production.
Mini-bloc réalité production. Coût d'exploitation à surveiller : appels Jev, appels LLM évités, latence cumulée, taux d'escalade, taux d'erreur. Sans ces métriques, vous ne saurez pas si l'intégration a réduit le coût ou déplacé la complexité. Logs structurés : run_id, question, answer, probability, threshold, final_action, latency_ms. Sans ce triplet, audit et calibration deviennent impossibles.
Questions fréquentes
Jev peut-il devenir le modèle principal de Hermes ?
Non. Jev est un outil de décision bornée exposé via MCP. Il ne génère pas de texte, ne gère pas la mémoire persistante, ne pilote pas le routeur interne d'Hermes. Il intervient sur des appels explicites, là où une décision typée coûte moins cher qu'un appel LLM complet.
MCP est-il obligatoire ?
C'est la voie recommandée, parce qu'elle réutilise l'infrastructure standard d'Hermes. Une intégration directe via HTTP reste possible mais sort du cadre de cet article. Dans tous les cas, l'outil expose un schéma de sortie borné, un timeout et une gestion d'erreur explicite.
Comment gérer une décision incertaine ?
Deux sorties : escalader vers le LLM Hermes pour reformuler, ou vers un humain si l'enjeu le justifie. Si la probabilité est sous le seuil, Jev ne décide pas, il informe. Aucune action automatique sans confiance documentée, aucune action irréversible sans approbation humaine.
Peut-on utiliser Jev depuis Telegram ?
Oui : Telegram déclenche Hermes, qui appelle mcp_jev_jev_decide selon la politique de routage. La latence reste à surveiller : canal, MCP Jev, action.
Que se passe-t-il si TypeSafe est indisponible ?
Le serveur MCP lève une erreur explicite (RuntimeError) sans effet de bord. Côté Hermes, fallback : LLM léger pour les cas tolérants, escalade humaine pour les cas sensibles. Testez ce scénario avant la production.
Articles liés
Jev devient utile dès qu'une boucle Hermes répète des choix bornés à fréquence élevée, avec une politique d'escalade claire et des seuils écrits. Le bon usage : utiliser Jev là où une décision typée coûte moins cher qu'un appel LLM complet. Commencez par un seul flux en lecture seule : routez dix tickets avec Jev, comparez les décisions, puis n'automatisez une action qu'après avoir défini vos seuils et votre voie d'escalade.
Restez informé sur les agents IA
Nouveaux tutoriels, comparatifs et guides pratiques directement dans votre boîte mail.