KLA Digital Logo
KLA Digital
Guides

Ajouter une porte d'approbation humaine

Mettre en pause un appel d'outil à haut risque pour obtenir la validation d'un humain grâce au modèle de checkpoint du SDK KLA, acheminé vers le Decision Desk.

4 min de lecture905 mots

Certaines actions d'agent sont trop lourdes de conséquences pour s'exécuter sans supervision : supprimer un compte, traiter un paiement, publier un document. Ce guide montre comment encadrer l'un de ces appels avec une porte d'approbation humaine en utilisant le SDK KLA Control Plane. KLA Control Plane est une couche de sécurité d'exécution, d'audit et de gouvernance qui s'applique sur place (govern-in-place) : vous instrumentez votre code d'agent existant plutôt que de le reconstruire sur une nouvelle plateforme. Un seul checkpoint suffit pour qu'un appel d'outil se mette en pause en attendant un humain, soit acheminé vers un réviseur, et ne reprenne qu'après une validation explicite.

Comment fonctionne une porte

Vous encadrez l'appel à risque dans un checkpoint. Le checkpoint soumet une Decision Request (l'action ainsi que son contexte) au KLA policy engine, qui la résout en l'un des quatre résultats possibles, par ordre de priorité : allow, warn, require_approval ou block. Lorsque la politique renvoie require_approval, l'exécution se met en pause. KLA ouvre une Escalation (une unité de travail en pause qui attend l'intervention d'un humain) et l'achemine vers le Decision Desk, l'espace de travail où des réviseurs autorisés approuvent ou refusent les actions en attente. L'appel du SDK reste bloqué jusqu'à ce qu'un réviseur tranche, puis rend la main à votre code.

sequenceDiagram
  participant App as Votre agent
  participant KLA as Checkpoint KLA
  participant Desk as Decision Desk
  App->>KLA: checkpoint("process_payment", context)
  KLA->>KLA: Évaluer la Decision Request
  Note over KLA: outcome = require_approval
  KLA->>Desk: Ouvrir une Escalation
  Desk-->>KLA: Le réviseur approuve ou refuse
  KLA-->>App: Décision résolue
  App->>App: Exécuter ou gérer le refus

Ajouter le checkpoint

Ci-dessous, un appel process_payment à haut risque est encadré par une porte. Le SDK reste bloqué sur le checkpoint jusqu'à ce que l'Escalation soit résolue au Decision Desk. Vous attachez des attributs métier (montant, niveau du client) pour que la politique puisse décider et pour que le réviseur dispose d'un contexte réel.

Python

from kla_otel import KLACheckpoint, DecisionDenied

checkpoint = KLACheckpoint(agent_id="agt_9f81a7")

def process_payment(account_id: str, amount: float):
    # Bloque ici si la politique renvoie require_approval, jusqu'à ce qu'un
    # réviseur résolve l'Escalation au Decision Desk.
    decision = checkpoint.evaluate_action(
        action="process_payment",
        context={"account_id": account_id, "amount": amount},
        idempotency_key=f"pay-{account_id}-{amount}",
    )

    if decision.is_approved():
        receipt = gateway.charge(account_id, amount)
        checkpoint.log_success(receipt_id=receipt.id)
        return receipt

    # require_approval refusé, ou un block strict.
    raise DecisionDenied(
        f"Payment not authorized: {decision.reason_codes} ({decision.remediation})"
    )

TypeScript

import { KLAClient, DecisionDenied } from '@kla-digital/otel-node';

const client = new KLAClient({ agentId: 'agt_9f81a7' });

async function processPayment(accountId: string, amount: number) {
  // Attend le verdict du réviseur si la politique renvoie require_approval.
  const decision = await client.checkpoint('process_payment', {
    context: { accountId, amount },
    idempotencyKey: `pay-${accountId}-${amount}`,
  });

  if (decision.approved) {
    const receipt = await gateway.charge(accountId, amount);
    await decision.logSuccess({ receiptId: receipt.id });
    return receipt;
  }

  throw new DecisionDenied(
    `Payment not authorized: ${decision.reasonCodes} (${decision.remediation})`,
  );
}

Configurez le SDK une seule fois, au démarrage, avec votre tenant et un jeton d'accès. Chaque appel de checkpoint envoie pour vous Authorization: Bearer <token> et x-tenant-id: <tenant> à https://api.kla.digital.

Gérer un refus avec élégance

Un réviseur peut refuser l'Escalation, ou la politique peut renvoyer un block strict. Dans les deux cas, vous recevez une décision résolue et non approuvée, et non une erreur réseau. Traitez-la comme une branche attendue :

  • Lisez les codes de raison. Chaque décision autre que allow porte des reason_codes lisibles par une machine (par exemple PAYMENT_OVER_THRESHOLD) et une remediation lisible par un humain. Aiguillez votre logique sur les codes, n'analysez jamais le texte libre.
  • Faites remonter, ne plantez pas. Renvoyez un message clair à l'utilisateur appelant ou à l'agent en amont (« Le paiement nécessite l'approbation d'un responsable et a été refusé »). Le refus est déjà enregistré comme Lineage Record, vous n'avez donc pas besoin de le consigner séparément à des fins d'audit.
  • Ne réessayez pas à l'aveugle. Une action refusée ne doit pas repasser automatiquement dans le même checkpoint en boucle. Acheminez-la plutôt vers un parcours humain dans votre propre produit.
⚠️ Warning
Un checkpoint en `require_approval` peut rester bloqué aussi longtemps que le réviseur met de temps à répondre. Exécutez les appels encadrés sur un worker ou une tâche d'arrière-plan, jamais sur un thread de requête qui maintient ouverte une connexion exposée à l'utilisateur. Définissez un délai d'expiration client généreux et considérez un dépassement de délai comme « toujours en attente », et non comme « refusé ».
💡 Tip
Rendez l'appel encadré idempotent. Transmettez une `idempotency_key` stable (ici, dérivée du compte et du montant) pour que, lorsque l'action reprend après approbation (ou si votre worker redémarre en cours de route), le débit sous-jacent ne s'exécute qu'une seule fois. KLA associe l'approbation à cette clé, de sorte qu'une nouvelle exécution après validation se résout sur la même décision approuvée au lieu d'ouvrir une seconde Escalation.

Avant de mettre en production

Rédigez la politique de gating dans le Policy Builder et lancez une Simulation : rejouez des Decision Requests représentatives sur le brouillon et confirmez qu'un paiement de forte valeur se résout en require_approval tandis qu'un paiement de faible valeur se résout en allow. Une fois validée, la politique se compile en un policy pack signé et passe en production. Dès lors, chaque appel encadré produit une trace défendable : la requête, le résultat, le verdict du réviseur et l'action qui en découle, le tout consigné dans un Lineage Record que vous pourrez exporter ultérieurement sous forme de Sealed Evidence Bundle.

Ajouter une porte d'approbation humaine | Developer Docs | KLA Control Plane