Hook dell'agente

Agent Hooks è una funzionalità di prima classe di Agent Framework per l'applicazione di controlli di governance e runtime in punti ben definiti nell'esecuzione di un agente. Implementa il contratto AGENT-HOOKS-0.1 agnostico rispetto al framework, così i motori di policy, i gateway di approvazione, i controlli sul budget, i filtri dei contenuti e i controlli di uscita possono fare riferimento a un’unica interfaccia di controllo comune.

Importante

Agent Hooks è un piano di controllo, non un piano di telemetria. Ogni intercettore restituisce un verdetto. In enforce modalità, il framework agisce su tale verdetto; in evaluate_only modalità, registra il verdetto senza modificare l'esecuzione. Usa l'osservabilità per il tracciamento passivo, le metriche e i log.

Agent Hooks non è ancora disponibile per .NET. Usare il middlewaredell'agente, l'approvazione degli strumenti e la sicurezza dell'agente per aggiungere controlli di runtime agli agenti .NET.

Agent Hooks è sperimentale in Python. La factory emette un ExperimentalWarning al primo utilizzo e la sua API può cambiare prima della disponibilità generale.

Quando usare Agent Hooks

Usa Agent Hooks quando controlli sviluppati in modo indipendente richiedono un contratto condiviso e vincolante per l'input dell'agente, le chiamate al modello, le chiamate agli strumenti e l'output finale.

Capability Usarlo per
Agent Hooks Decisioni relative ai criteri, trasformazioni, approvazioni, budget e controlli del traffico in uscita standardizzati nell'intero ciclo di vita dell'agente.
Middleware dell'agente Funzionalità trasversale specifica dell'applicazione che non richiede il contratto di Agent Hooks né le garanzie del runtime di base.
Sicurezza dell'agente con FIDES Etichette e criteri deterministici del flusso di informazioni per contenuti non attendibili o riservati.
Approvazione degli strumenti Conferma umana delle singole invocazioni di funzione-strumento.
Osservabilità Tracce, metriche e log passivi che non controllano l'esecuzione.

Cosa impone Agent Framework

Quando aggiungi Agent Hooks a un agente, Agent Framework applica un perimetro di applicazione coordinato su tutte le esecuzioni dell’agente, le chiamate al modello e le chiamate agli strumenti. Il runtime offre le garanzie seguenti:

  • Fail closed: un rifiuto blocca l'azione protetta. Contesti non validi, verdetti non validi, errori degli interceptor ed errori di applicazione non ignorano automaticamente i controlli.
  • Scrittura di ritorno della trasformazione: Una trasformazione modifica i messaggi nativi, gli argomenti degli strumenti, i risultati degli strumenti o la risposta finale effettivamente utilizzati durante l'esecuzione. Se non è possibile applicare una trasformazione, l'esecuzione ha esito negativo.
  • Streaming memorizzato nel buffer: Nessun aggiornamento della risposta raggiunge il chiamante finché la risposta completa del modello e l'output finale non superano i punti di intercettazione.
  • Persistenza subordinata al verdetto: La persistenza attende il verdetto che la riguarda. La persistenza standard successiva all'esecuzione attende output; la persistenza della cronologia per chiamata al servizio attende ogni post_model_call.
  • Completare l'installazione del bundle: Le parti agente, chat e funzione vengono installate come un'unità, quindi non è possibile configurare accidentalmente un limite di imposizione incompleto.

Il contratto è cooperativo anziché un limite di isolamento del processo. Gli interceptor vengono eseguiti nel processo host e ricevono il contenuto necessario per prendere decisioni. Registra solo gli intercettori attendibili.

Installare Agent Hooks

Installare Agent Hooks SDK come dipendenza diretta:

pip install agent-hooks-sdk

Se si usa uv:

uv add agent-hooks-sdk

La dipendenza agent-hooks-sdk viene importata in modo lazy. Importare agent_framework non carica l’SDK, a meno di creare un bundle middleware di Agent Hooks.

Annotazioni

agent-framework-core non comprende un agent-hooks extra. Installa agent-hooks-sdk separatamente prima di creare un bundle middleware di Agent Hooks.

Aggiungere un intercettore

Un interceptor riceve un elemento agent_hooks.AgentContext (il mapping del contesto della specifica, non l'elemento agent_framework.AgentContext usato dal middleware dell'agente) e restituisce un verdetto. L'intercettore seguente blocca l'output finale contenente la parola secret. L'esempio presuppone client che sia un client di chat di Agent Framework già configurato.

from agent_framework import Agent, create_agent_hooks_middleware
from agent_hooks import ALLOW, AgentContext, InterceptionBlocked, Verdict


class SecretEgressGuard:
    def intercept(self, context: AgentContext) -> Verdict:
        if (
            context["interception_point"] == "output"
            and "secret" in str(context["target"]).lower()
        ):
            return Verdict.deny(
                reason="secret_in_output",
                message="The final response contains restricted content.",
            )
        return ALLOW


hooks = create_agent_hooks_middleware(
    {"secret-egress": SecretEgressGuard()},
)

agent = Agent(
    client=client,
    instructions="You are a helpful assistant.",
    middleware=[hooks],
)

try:
    response = await agent.run("Summarize the account details.")
except InterceptionBlocked as exc:
    print(f"Blocked: {exc.result.verdict.reason}")

Passare il bundle come singolo elemento dell'elenco middleware dell'agente. Installare esattamente un bundle di Agent Hooks su ogni agente.

Punti di intercettazione

Agent Framework genera automaticamente i punti di intercettazione applicabili:

Punto di intercettazione Quando viene emesso Destinazione della trasformazione
agent_startup Prima del primo input in una sessione di Agent Hooks Non trasformabile
input Quando una richiesta esterna arriva all'agente Contenuto di input e ruolo
pre_model_call Prima di ogni richiesta di modello Messaggi inviati al modello
post_model_call Dopo ogni risposta completa del modello Contenuto della risposta, chiamate di strumenti eseguite dal framework e motivo di fine
pre_tool_call Prima della chiamata di ogni strumento eseguito dal framework Argomenti degli strumenti
post_tool_call Dopo che uno strumento ha esito positivo o negativo Risultato dello strumento
output Prima che la risposta finale raggiunga il chiamante Contenuto della risposta finale
agent_shutdown Quando la sessione Agent Hooks si completa, fallisce o viene annullata Non trasformabile

agent_startup.tools_registered è lo snapshot dello strumento di inizio dell'esecuzione. Ogni pre_model_call payload include gli strumenti efficaci per tale chiamata al modello nel relativo campo facoltativo tools . Sono inclusi gli strumenti aggiunti durante l'esecuzione da provider di contesto, server MCP connessi o divulgazione progressiva. Il campo viene omesso quando la chiamata non dispone di strumenti o il set di strumenti non può essere proiettato.

Un'esecuzione che invoca uno strumento in genere produce:

agent_startup input → → pre_model_callpost_model_callpost_tool_callpre_tool_call → → pre_model_callpost_model_call → → outputagent_shutdown

Giudizi

Il contratto ha tre decisioni: allow, denye transform. L'SDK di Python fornisce anche helper per avvisi e dinieghi revocabili.

Risultato API Python Behavior
Consentire ALLOW oppure Verdict(decision=Decision.ALLOW) Continuare con la destinazione invariata.
Consenti con avviso Verdict.warn(...) Continuare e includere l'avviso nel registro di intercettazione.
Deny Verdict.deny(...) Bloccare l'azione protetta.
Rifiutare in attesa di approvazione Verdict.escalate(...) Bloccare a meno che il resolver di approvazione configurato non restituisca un verdetto di autorizzazione.
Trasformazione Verdict(decision=Decision.TRANSFORM, transform=Transform(...)) Riscrivere un valore in $target, quindi continuare con il valore riscritto.

I rifiuti a livello di esecuzione e di modello generano InterceptionBlocked e impediscono al risultato protetto di raggiungere il chiamante o la fase successiva. In un punto di intercettazione dello strumento, un rifiuto del criterio impedisce l'azione dello strumento o ne elimina il risultato e restituisce al modello un errore di controllo contenente il motivo del criterio, senza il payload di destinazione rifiutato. In questo modo il ciclo dell'agente può continuare. Un errore dell'host o di applicazione interrompe l'esecuzione.

Interrompere un'esecuzione dal middleware di funzione

Importare MiddlewareFailure da agent_framework. Il middleware della funzione converte in genere un'eccezione normale in un risultato di errore dello strumento, quindi consente al ciclo dell'agente di continuare. Se il middleware di funzione non può continuare in modo sicuro, solleva MiddlewareFailure a partire dall'eccezione sottostante. Il runtime interrompe l'esecuzione e propaga l'errore al chiamante anziché convertirlo in un risultato dello strumento.

Non intercettare MiddlewareFailure nel middleware. Intercettandolo consente al ciclo di continuare e di modificare il comportamento di chiusura non riuscita per il comportamento di apertura non riuscita. Agent Hooks utilizza questo segnale internamente quando il suo livello di applicazione del middleware di funzione non riesce. Passare middleware fail-closed personalizzato in una sequenza, ad esempio,middleware=[policy_middleware].

In caso di chiamate simultanee agli strumenti, il runtime annulla le chiamate affini in corso prima di propagare l'errore. La cancellazione è cooperativa, quindi un tool sincrono già in esecuzione in un worker thread potrebbe completare i propri effetti collaterali, ma il suo risultato viene scartato.

Applicare una trasformazione

Un percorso di trasformazione deve iniziare da $target. Ad esempio, un intercettore può sostituire il contenuto finale della risposta:

from agent_hooks import ALLOW, AgentContext, Decision, Transform, Verdict


class OutputRedactor:
    def intercept(self, context: AgentContext) -> Verdict:
        if context["interception_point"] != "output":
            return ALLOW

        return Verdict(
            decision=Decision.TRANSFORM,
            reason="redacted_output",
            transform=Transform(
                path="$target.content",
                value="[Response removed by policy]",
            ),
        )

Le trasformazioni vengono applicate ai valori di Agent Framework Content , mantenendo contenuto avanzato supportato anziché ridurre ogni valore al testo normale. Un percorso non valido o una sostituzione incompatibile applica il comportamento fail-closed anziché continuare con il valore originale.

Approvazione degli strumenti e trasformazioni degli argomenti

L'approvazione degli strumenti di Agent Framework e il punto di approvazione di Agent Hooks sono meccanismi distinti. Per uno strumento funzione con approval_mode="always_require", Agent Framework crea la richiesta di approvazione umana prima dell'esecuzione del middleware della funzione. Se una pre_tool_call trasformazione modifica gli argomenti associati all'approvazione, la concessione originale non esegue alcuna operazione. Il framework restituisce una richiesta di sostituzione contenente gli argomenti modificati e l'esecuzione richiede una seconda approvazione.

Avvertimento

Per gli strumenti che usano approval_mode="always_require", trasformare la chiamata dello strumento in in post_model_call modo che la prima richiesta di approvazione del framework contenga i valori effettivi. In alternativa, restituisci Verdict.escalate(...) in pre_tool_call e risolvi l'approvazione tramite gli Agent Hooks resolver. Le trasformazioni degli argomenti devono essere eseguite prima dell'elaborazione dei criteri o della sicurezza. La mutazione successivamente non riesce a chiudersi con MiddlewareFailure.

Streaming e persistenza

Agent Hooks mantiene l'API di streaming, ma utilizza la semantica dell'output bufferizzato. Agent Framework assembla la risposta completa del modello, genera post_model_call, assembla la risposta dell'agente finale e genera output prima di rilasciare gli aggiornamenti. Se uno dei due punti nega la risposta, il chiamante non riceve aggiornamenti parziali.

Questo comportamento privilegia l'applicazione fail-closed dell'output rispetto alla latenza token per token. Una trasformazione dell'output si riflette anche negli aggiornamenti eventualmente rilasciati al chiamante.

La persistenza è controllata dal punto di intercettazione che copre l'operazione di persistenza:

  • Per impostazione predefinita, la cronologia e le altre operazioni dei provider successive all'esecuzione attendono il verdetto output. Un output rifiutato non viene conservato, mentre una trasformazione dell'output viene conservata dopo essere stata trasformata.
  • Quando si imposta require_per_service_call_history_persistence=True nel costruttore Agent o in client.as_agent(...), ogni scambio con il modello viene reso persistente dopo essere stato consentito dal relativo verdetto post_model_call. Una successiva negazione output non annulla la cronologia già autorizzata.
  • Per la persistenza predefinita successiva all'esecuzione, i tentativi rimangono soggetti alla decisione output finale. La modalità per chiamata al servizio rende invece persistente ogni risposta del modello che supera post_model_call.

Importante

Se il contenuto del modello non deve diventare persistente, applicare tale criterio in post_model_call quando require_per_service_call_history_persistence=True. Un criterio per il traffico in uscita applicato solo all'output protegge ciò che raggiunge il chiamante, ma non rimuove retroattivamente gli scambi con il modello già consentiti e resi persistenti in post_model_call.

Sessioni e record di controllo

Per impostazione predefinita, ogni esecuzione dell'agente crea una sessione di Agent Hooks. agent_startup e agent_shutdown delimitano l'esecuzione e i record ricevono un unico ID di sessione con una sequenza monotonicamente crescente.

Usare record_sink per ricevere ogni InterceptionRecord:

records = []

hooks = create_agent_hooks_middleware(
    {"secret-egress": SecretEgressGuard()},
    record_sink=records.append,
)

I record di intercettazione acquisiscono decisione, motivo, riepilogo dell'interceptor, modalità, identità e sequenza senza copiare il payload intercettato nel record di controllo. L'intercettore stesso riceve comunque il contesto completo.

Estendere una sessione a più esecuzioni

Usare create_agent_hooks_middleware_from_emitter() quando l'applicazione possiede una sessione Agent Hooks di durata maggiore, ad esempio una conversazione con un unico registro delle approvazioni:

from agent_framework import Agent, create_agent_hooks_middleware_from_emitter
from agent_hooks import AgentContextBuilder, InterceptionEmitter


emitter = InterceptionEmitter().register(SecretEgressGuard())
builder = AgentContextBuilder(
    agent_id="support-agent",
    framework="agent-framework",
    session_id="conversation-42",
)

hooks = create_agent_hooks_middleware_from_emitter(emitter, builder)
agent = Agent(client=client, middleware=[hooks])

await emitter.emit(builder.agent_startup(tools_registered=[]))
await agent.run("First turn")
await agent.run("Second turn")
await emitter.emit(builder.agent_shutdown(reason="completed"))

In questa modalità, l'applicazione configura l'emettitore e gestisce direttamente l'avvio, l'arresto e il ripristino in caso di errore. Il middleware genera i punti per esecuzione da input a output.

Configurare l'applicazione

create_agent_hooks_middleware() accetta i controlli seguenti:

Parametro Finalità
interceptors Una sequenza di intercettori o una mappatura tra nomi e intercettori. Almeno uno è obbligatorio.
resolver Risolve i rifiuti revocabili tramite un canale di approvazione. Senza un sistema di risoluzione, la negazione rimane attiva.
mode "enforce" applica i verdetti. "evaluate_only" registra ciò che accadrebbe, ma consente ogni azione.
composition Seleziona il modo in cui vengono combinati più verdetti degli interceptor.
identity_provider Produce identità di contesto associate al contenuto. Il valore predefinito è "jcs-sha256".
timeout Timeout per interceptor e resolver per le chiamate awaitable. Il valore predefinito è cinque secondi. Un interceptor o resolver sincrono che blocca il ciclo di eventi non può essere interrotto preventivamente da questo timeout.
record_sink Riceve ogni record di intercettazione senza payload.

La composizione predefinita è first_deny sequenziale, con l'approvazione configurata per interrompere il fold. L'ordine degli intercettori è quindi importante: colloca i controlli che devono essere sempre eseguiti prima di quelli che possono richiedere l'approvazione. Vedere l'elenco di controllo per la produzione di Agent Hooks prima di selezionare un altro profilo di composizione.

Eseguire il rollout con la modalità di sola valutazione

Usare evaluate_only per misurare il comportamento dei criteri prima dell'applicazione:

hooks = create_agent_hooks_middleware(
    {"secret-egress": SecretEgressGuard()},
    mode="evaluate_only",
    record_sink=records.append,
)

In questa modalità gli interceptor vengono eseguiti e i record includono i relativi verdetti, ma nessuna azione viene bloccata o trasformata. Non descrivere una distribuzione evaluate_only come governance applicata.

Regole di composizione

Posizionare il bundle per primo nell'elenco di middleware dell'agente affinché costituisca il limite di applicazione più esterno:

agent = Agent(
    client=client,
    middleware=[
        create_agent_hooks_middleware([SecretEgressGuard()]),
        application_middleware,
    ],
)

Segui queste regole:

  • Installare esattamente un bundle Agent Hooks per ogni agente. I pacchetti impilati vengono rifiutati.
  • Mantenere intatto il bundle. I relativi middleware di agente, chat e funzione non possono essere installati separatamente.
  • Installare il bundle su Agent, non direttamente in un client di chat o tramite un provider di contesto.
  • Il middleware posizionato prima del bundle è al di fuori del perimetro di applicazione. Considerare la posizione esterna come limite esterno di attendibilità.
  • Assegnare a ogni agente annidato un bundle dedicato quando anche l'attività interna del modello e degli strumenti richiede l'intercettazione.

Limitazioni correnti

  • solo Python: gli hook dell'agente non sono ancora implementati negli SDK .NET o Go.
  • API sperimentale: le firme e il comportamento delle factory possono cambiare prima della disponibilità generale.
  • Streaming con buffering: gli aggiornamenti non vengono rilasciati token per token perché l'output deve essere completo prima di un verdetto fail-closed.
  • Strumenti ospitati: Gli strumenti eseguiti da un provider di modelli non passano attraverso la giunzione della chiamata a funzione di Agent Framework. Le chiamate e gli output vengono visualizzati in post_model_call, ma pre_tool_call e post_tool_call non possono bloccare l'esecuzione sul lato server del provider.
  • Limite cooperativo: Agent Hooks non esegue gli interceptor in una sandbox e non protegge da un host ostile. I percorsi di codice che ignorano la pipeline protetta dell'agente non sono coperti.
  • La disponibilità dell'intercettore influisce sulla disponibilità dell'agente: In modalità di imposizione, un errore o un timeout dell'intercettore blocca l'azione sorvegliata in base alla progettazione.

Per indicazioni sul rollout in produzione, sui motivi degli errori e sugli avvisi, vedere il runbook operativo di Agent Hooks.

Agent Hooks non è ancora disponibile per Go. Usare middleware dell'agente, approvazione degli strumenti e sicurezza dell'agente per aggiungere controlli in fase di esecuzione agli agenti Go.

Passaggi successivi