Aggiungere un gate di approvazione umana
Mettere in pausa una singola chiamata a uno strumento ad alto rischio per il via libera di un revisore, usando il pattern checkpoint del KLA SDK, instradata al Decision Desk.
Alcune azioni degli agenti sono troppo rilevanti per essere eseguite senza supervisione: eliminare un account, elaborare un pagamento, rilasciare un documento. Questa guida mostra come avvolgere una di queste chiamate in un gate di approvazione umana usando il KLA Control Plane SDK. KLA Control Plane è un layer di sicurezza, audit e governance a runtime che governa in loco: si strumenta il codice esistente dell'agente invece di rifarne la piattaforma. Un singolo checkpoint è sufficiente per far sì che una chiamata a uno strumento si metta in pausa in attesa di una persona, venga instradata a un revisore e riprenda solo dopo un via libera esplicito.
Come funziona un gate
Si avvolge la chiamata rischiosa in un checkpoint. Il checkpoint invia una Decision Request (l'azione più il suo contesto) al KLA policy engine, che la risolve in uno di quattro esiti, in ordine di precedenza: allow, warn, require_approval o block. Quando la policy restituisce require_approval, l'esecuzione si mette in pausa. KLA apre un'Escalation (un'unità di lavoro in pausa in attesa di una persona) e la instrada al Decision Desk, lo spazio di lavoro in cui i revisori autorizzati approvano o negano le azioni in sospeso. La chiamata dell'SDK rimane bloccata finché un revisore non decide, poi restituisce il controllo al tuo codice.
sequenceDiagram
participant App as Il tuo agente
participant KLA as KLA checkpoint
participant Desk as Decision Desk
App->>KLA: checkpoint("process_payment", context)
KLA->>KLA: Valuta la Decision Request
Note over KLA: outcome = require_approval
KLA->>Desk: Apre un'Escalation
Desk-->>KLA: Il revisore approva o nega
KLA-->>App: Decisione risolta
App->>App: Esegue o gestisce il rifiutoAggiungere il checkpoint
Qui sotto, una chiamata process_payment ad alto rischio viene messa sotto gate. L'SDK si blocca sul checkpoint finché l'Escalation non viene risolta al Decision Desk. Si allegano attributi di business (importo, livello del cliente) affinché la policy possa decidere e affinché il revisore veda un contesto reale.
Python
from kla_otel import KLACheckpoint, DecisionDenied
checkpoint = KLACheckpoint(agent_id="agt_9f81a7")
def process_payment(account_id: str, amount: float):
# Si blocca qui se la policy restituisce require_approval, finché un
# revisore non risolve l'Escalation sul 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 che è stato negato, oppure un block diretto.
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) {
// Attende il verdetto del revisore se la policy restituisce 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})`,
);
}
Configura l'SDK una sola volta, all'avvio, con il tuo tenant e un access token. Ogni chiamata di checkpoint invia Authorization: Bearer <token> e x-tenant-id: <tenant> a https://api.kla.digital per tuo conto.
Gestire un rifiuto in modo elegante
Un revisore può negare l'Escalation, oppure la policy può restituire un block diretto. Entrambi i casi arrivano come una decisione risolta e non approvata, non come un errore di rete. Trattali come un ramo previsto:
- Leggi i reason code. Ogni decisione diversa da
allowporta con séreason_codesleggibili dalla macchina (per esempioPAYMENT_OVER_THRESHOLD) e unaremediationleggibile dalle persone. Ramifica in base ai codici; non analizzare mai il testo discorsivo. - Mostra, non andare in crash. Restituisci un messaggio chiaro all'utente chiamante o all'agente a monte ("Il pagamento richiede l'approvazione di un manager ed è stato rifiutato"). Il rifiuto è già registrato come Lineage Record, quindi non è necessario tracciarlo separatamente per l'audit.
- Non riprovare alla cieca. Un'azione negata non dovrebbe rientrare automaticamente nello stesso checkpoint in un ciclo. Inoltrala invece a un percorso umano all'interno del tuo prodotto.
Prima di andare in produzione
Scrivi la policy di gating nel Policy Builder ed esegui una Simulation: riproduci Decision Request rappresentative sulla bozza e verifica che un pagamento di alto valore si risolva in require_approval mentre uno di basso valore si risolva in allow. Una volta convalidata, la policy viene compilata in un policy pack firmato e va in produzione. Da quel momento, ogni chiamata sotto gate produce una traccia difendibile: la richiesta, l'esito, il verdetto del revisore e l'azione risultante, tutto catturato come Lineage Record che potrai esportare in seguito come Sealed Evidence Bundle.
