Añadir una compuerta de aprobación humana
Pause una única llamada de herramienta de alto riesgo para obtener la aprobación de una persona mediante el patrón de checkpoint del KLA SDK, enrutándola al Decision Desk.
Algunas acciones de los agentes son demasiado trascendentales para ejecutarse sin supervisión: eliminar una cuenta, procesar un pago, publicar un documento. Esta guía muestra cómo envolver una de esas llamadas en una compuerta de aprobación humana usando el SDK de KLA Control Plane. KLA Control Plane es una capa de seguridad en tiempo de ejecución, auditoría y gobernanza de tipo govern-in-place: usted instrumenta el código de agente que ya ejecuta. Un único checkpoint basta para que una llamada de herramienta se detenga a la espera de una persona, se enrute a un revisor y se reanude solo tras una aprobación explícita.
Cómo funciona una compuerta
Usted envuelve la llamada de riesgo en un checkpoint. El checkpoint envía una Decision Request (la acción junto con su contexto) al motor de políticas de KLA, que la resuelve a uno de cuatro resultados en orden de precedencia: allow, warn, require_approval o block. Cuando la política devuelve require_approval, la ejecución se pausa. KLA abre una Escalation (una unidad de trabajo en pausa a la espera de una persona) y la enruta al Decision Desk, el espacio de trabajo donde los revisores autorizados aprueban o deniegan las acciones pendientes. Por defecto, la llamada checkpoint del SDK sondea el proposal hasta que un revisor decide, después canjea la aprobación y devuelve el control a su código; el servidor ejecuta la acción aprobada exactamente una vez.
sequenceDiagram
participant App as Su agente
participant KLA as Checkpoint de KLA
participant Desk as Decision Desk
App->>KLA: checkpoint("process_payment", context)
KLA->>KLA: Evaluar la Decision Request
Note over KLA: resultado = require_approval
KLA->>Desk: Abrir Escalation
Desk-->>KLA: El revisor aprueba o deniega
KLA-->>App: Decisión resuelta
App->>App: Ejecutar o gestionar la denegaciónAñadir el checkpoint
A continuación, una llamada de alto riesgo process_payment se protege con el SDK de gobernanza (kla-governance para Python, @kla-digital/governance para Node.js). El SDK sondea en el checkpoint hasta que la Escalation se resuelve en el Decision Desk. Los parámetros de la acción (cuenta, importe) quedan vinculados a la aprobación, de modo que la política decide sobre los valores reales y el revisor los ve.
Python
from kla_governance import ActionRequest, AgentIdentity, DecisionDenied, KLAClient
client = KLAClient(
base_url="https://api.kla.digital",
credential=get_access_token,
agent=AgentIdentity(agent_id="agt_9f81a7", release_version="1.4.2"),
mandate_id="mnd_payments",
)
def process_payment(account_id: str, amount: float):
try:
# Polls here if policy returns require_approval, until a
# reviewer resolves the Escalation on the Decision Desk.
decision = client.checkpoint(
ActionRequest(
tool="payments",
operation="charge",
destination="gateway:acct_main",
parameters={"account_id": account_id, "amount": amount},
),
proposal_id=stable_id_for(account_id, amount),
)
except DecisionDenied as denial:
# block, a denied approval, or an expired approval.
raise PaymentNotAuthorized(
f"Payment not authorized: {denial.reason_codes} ({denial.remediation})"
)
receipt = gateway.charge(account_id, amount)
decision.log_success(receipt_id=receipt.id)
return receipt
TypeScript
import { KLAClient, DecisionDenied } from '@kla-digital/governance';
const client = new KLAClient({
baseUrl: 'https://api.kla.digital',
credential: () => getAccessToken(),
agent: { agentId: 'agt_9f81a7', releaseVersion: '1.4.2' },
mandateId: 'mnd_payments',
});
async function processPayment(accountId: string, amount: number) {
let decision;
try {
// Polls here if policy returns require_approval, until a
// reviewer resolves the Escalation on the Decision Desk.
decision = await client.checkpoint(
{
tool: 'payments',
operation: 'charge',
destination: 'gateway:acct_main',
parameters: { accountId, amount },
},
{ proposalId: stableIdFor(accountId, amount) }
);
} catch (error) {
if (error instanceof DecisionDenied) {
// block, a denied approval, or an expired approval.
throw new PaymentNotAuthorizedError(
`Payment not authorized: ${error.reasonCodes} (${error.remediation})`
);
}
throw error;
}
const receipt = await gateway.charge(accountId, amount);
await decision.logSuccess({ receiptId: receipt.id });
return receipt;
}
Configure el cliente una sola vez, al arrancar, con la URL base del control plane, un token de acceso de client credentials y la vinculación del agente: el id del agente registrado, su versión de release fijada y un id de mandato activo. La identidad del tenant proviene del token verificado; el SDK nunca envía un campo de tenant en el cuerpo de la petición. Cada llamada de checkpoint envía Authorization: Bearer <token> a https://api.kla.digital en su nombre.
Gestionar una denegación con elegancia
Un revisor puede denegar la Escalation, o la política puede devolver un block firme. Ambos casos emergen de checkpoint como DecisionDenied con la decisión resuelta adjunta; el transporte tuvo éxito y el resultado quedó registrado. Trate la excepción como una rama esperada:
- Lea los reason codes. Cada decisión distinta de
allowllevareason_codeslegibles por máquina (por ejemploPAYMENT_OVER_THRESHOLD) y unaremediationlegible por personas. Ramifique según los códigos; nunca analice la prosa. - Haga visible la denegación. Devuelva un mensaje claro al usuario que llama o al agente aguas arriba ("El pago requiere aprobación de un responsable y fue rechazado"). La denegación ya está registrada como Lineage Record, así que no necesita registrarla por separado para la auditoría.
- No reintente a ciegas. Una acción denegada no debe volver automáticamente al mismo checkpoint. Escale a una vía humana dentro de su propio producto.
Un checkpoint con require_approval puede sondear durante todo el tiempo que tarde un revisor. Ejecute las llamadas protegidas en un worker o tarea en segundo plano, de modo que ninguna conexión de petición de cara al usuario permanezca abierta durante toda la espera. Pase timeout (timeoutMs en Node.js) para acotar la espera: cuando expira, el SDK lanza ApprovalTimeout, lo que significa que la aprobación sigue pendiente en el servidor. Llame de nuevo a checkpoint con el mismo proposal id para retomar la espera. Para no esperar en absoluto, pase wait_for_approval=False (waitForApproval: false); la decisión pendiente se devuelve de inmediato y usted la canjea más tarde con resume_action (resumeAction).
Haga idempotente la llamada protegida. Pase un proposal_id estable (aquí, derivado de la cuenta y el importe) para que, cuando la acción se reanude tras la aprobación (o si su worker se reinicia a mitad del proceso), el cargo subyacente se ejecute exactamente una vez. KLA vincula la aprobación a ese proposal, de modo que una nueva ejecución tras el visto bueno se resuelve a la misma decisión aprobada en lugar de abrir una segunda Escalation.
Antes de publicar
Redacte la política de la compuerta en el Policy Builder y ejecute una Simulation: reproduzca Decision Requests representativas contra el borrador y confirme que un pago de importe alto se resuelve a require_approval mientras que uno de importe bajo se resuelve a allow. Una vez validada, la política se compila en un policy pack firmado y entra en producción. A partir de entonces, cada llamada protegida produce un rastro defendible: la petición, el resultado, el veredicto del revisor y la acción resultante, todo capturado como un Lineage Record que puede exportar más adelante como Sealed Evidence Bundle.
