Triage et moteur de risque
Filtrage de risque à deux niveaux, routage des agents et décision finale qui envoie automatiquement ou bloque une réponse pour approbation humaine.
Chaque message entrant traverse le même pipeline de triage. L'objectif est de classer le risque, router vers le bon agent, ancrer la réponse dans les bases de connaissances, et n'envoyer automatiquement que quand le verdict est vert.
Composants
TriageOrchestrator.processIncoming(ticket)— pilote tout le flux.Router.pick(category, requiredSkills)— choisit le meilleur agent activé.AgentService.executeAgent(agent, turns, { sources })— construit le prompt et stream le brouillon.RiskAssessor— règles déterministes de niveau 1 et classifieur LLM de niveau 2.
Flux de message
IncomingMessage
→ persister le message + upsert ticket
→ TriageOrchestrator.processIncoming
├── RiskAssessor.layer1(text) → règles + niveau
├── RiskAssessor.layer2(text) → { category, risk, confidence,
│ reasoning, requiredSkills }
│ sauté si layer1 = red
├── Router.pick(category, requiredSkills) → Agent
├── si agent.knowledgeBaseIds.length > 0 :
│ RAG.search(...) → SourceSnippet[]
├── AgentService.executeAgent(agent, turns, { sources })
│ → construire prompt (system + langue + sources + tour)
│ → runner.generate(stream) → brouillon
├── sauvegarder brouillon agent + risk_assessment
└── décider par finalLevel :
├── vert → envoyer au canal, statut = auto_replied
└── jaune | rouge → statut = waiting_operator
→ Boîte de réception opérateur → approuver / modifier / rejeterNiveau 1 — règles déterministes
Le niveau 1 est un moteur de règles rapide qui s'exécute en moins de 10 ms. Chaque règle est une fonction pure qui renvoie { triggered, level, reason }. Les règles vivent dans la table risk_rules ; les règles intégrées sont chargées au démarrage et ne peuvent pas être supprimées, seulement désactivées.
Catégories intégrées :
| Catégorie | Niveau | Exemples |
|---|---|---|
pii | jaune | email, téléphone international |
credentials | rouge | sk-…, xoxb-…, JWT, PEM, carte de crédit (Luhn) |
destructive | rouge | drop table, rm -rf, « удалить всё » |
destructive | jaune | disable, « отключить », « забанить » |
financial | rouge | refund, procès, « возврат денег » |
financial | jaune | price, billing, « цена » |
access | rouge | grant access, make admin, « выдать права » |
volume | jaune | message de plus de 5000 caractères, plus de 10 URLs |
profanity | jaune | filtre de tonalité léger |
Types de règles :
regex— une chaîne RegExp.keywords— liste séparée par des virgules, insensible à la casse, correspondance par limite de mot.builtin— identifiant d'un vérificateur intégré (luhn_credit_card,oversize_message,excess_urls,profanity_lite).
Résultat du niveau 1 :
{ level: 'green' | 'yellow' | 'red', triggeredRules: [...] }Le niveau est le maximum des règles déclenchées. Pas de règles → vert, et le niveau 2 est invoqué.
Niveau 2 — classifieur LLM
Si le niveau 1 n'est pas rouge, un petit modèle classifieur (défaut qwen3-0.6b-q4) produit un verdict JSON structuré via grammaire :
type LLMRiskVerdict = {
category: 'coding' | 'business' | 'marketing' | 'seo' | 'general' | 'other'
risk: 'green' | 'yellow' | 'red'
confidence: number // 0..1
reasoning: string // audit en une ligne
}Le prompt du classifieur est stocké dans risk_rules_config.llm_prompt et peut être édité dans Paramètres → Risque & Triage.
Routage
Router.pick score les agents activés par :
agent.enabled === true.- Correspondance exacte de rôle (
agent.role === category) ouagent.role === 'general'en fallback. - Plus grande intersection de compétences avec
requiredSkills. - Tie-break par
last_used_at ASC(round-robin).
Verdict final et décision
finalLevel = max(L1.level, L2.risk)
finalCategory = L2.category ?? firstFiredRule.category ?? 'general'green— la réponse est envoyée automatiquement.yellowoured— la réponse devient un ticket dans la Boîte de réception opérateur. Un humain peut approuver, modifier ou rejeter avant qu'elle n'atteigne le canal.
Audit
Chaque verdict est sauvegardé dans risk_assessments :
layer1_result— JSON complet du niveau 1.layer2_result— JSON complet du niveau 2, ounulls'il a été sauté.final_level,final_category.created_at.
Dans l'application de bureau, ouvrez un ticket dans la Boîte de réception et dépliez la section Assessment pour inspecter le verdict brut.
Configuration
Les opérateurs gèrent le risque dans Paramètres → Risque & Triage :
- Ajouter, modifier, activer ou désactiver des règles avec un aperçu en direct.
- Modifier le prompt du classifieur de niveau 2.
- Voir les règles intégrées (désactivation autorisée, suppression bloquée).
Widget de chat web
Intégrez un widget de chat propulsé par Cradle sur n'importe quel site avec une seule balise script — historique, indicateur de saisie et réponses temps réel.
Fine-tuning de domaine
Entraînez un adaptateur LoRA sur vos propres documents pour que le modèle parle le vocabulaire et le style de raisonnement de votre domaine.