Skip to main content
Per un agente che hai scritto tu stesso, o un framework per il quale Failproof AI non ha un adapter. Non c’è nulla da strumentare: tu emetti gli eventi. Questa è la stessa API che i quattro adapter di framework chiamano internamente. Sono tabelle di traduzione su di essa.

Installa

Nessun extra, nessuna dipendenza.

Strumenta

Leggi da cima a fondo e dice quello che significa: E cosa emette effettivamente ciascuno: Tutto ciò che è contenuto può omettere session_id e agent_id. Gli ambiti vincolano l’identità su variabili di contesto e ogni chiamata di evento la legge di nuovo, quindi non devi mai passare gli id attraverso le tue funzioni. Tutti e tre funzionano sia con async with che con with. L’annidamento di agenti costruisce l’albero. parent_id e profondità sono calcolati dalla stack:

Come un ambito si chiude

agent() gestisce le eccezioni per te: L’errore è emesso prima di agent_end, perché il dashboard chiude lo span a agent_end e qualsiasi cosa dopo è attribuita a nulla. Una cancellazione non è un fallimento, quindi le esecuzioni cancellate non inquinano la superficie degli errori. L’eccezione è sempre lanciata di nuovo: un ambito non inghiotte mai.

I metodi evento

Quindici metodi in sei famiglie. La maggior parte viene in coppia — emetti l’apertura, poi la chiusura, e l’SDK misura l’intervallo tra loro.
Preferisci gli ambiti — agent() e tool_call() — ovunque si adattino. Garantiscono l’evento di chiusura anche quando il corpo genera un’eccezione. Raggiungi questi metodi direttamente quando il tuo flusso di controllo non si annida, ad esempio una chiamata di modello dentro un helper.
Le due famiglie umane puntano in direzioni opposte.Nessun framework segnala la seconda coppia, quindi è sempre tuo compito emetterla.
Passa request_id quando le chiamate di modello vengono eseguite contemporaneamente. Senza di esso, le richieste e le risposte si abbinano in ordine di arrivo per agente — e le chiamate contemporanee si abbinano male, allegando ogni risposta alla richiesta sbagliata.

Esempio

Un ciclo di chiamata di strumenti contro l’API di OpenAI, senza framework di agenti:
Questo produce gli stessi sei tipi di evento che un adapter ti darebbe. La versione completamente eseguibile, con le definizioni degli strumenti, è fornita nel repository SDK under docs/manual/examples/.

Thread e async

Le variabili di contesto si propagano nei task asyncio automaticamente. Non si propagano nei nuovi thread, perché un thread inizia con un contesto vuoto.
Senza propagate(), gli eventi del worker generano un TypeError che nomina la correzione anziché atterrare su nessuna sessione. È intenzionale: un evento senza sessione è saltato dall’ingest e restituito 200, che è il fallimento silenzioso che il livello di identità esiste per prevenire.

Strumenta un framework senza un adapter

Ogni framework di agenti ti dà le stesse tre giunzioni. Mappale e hai una traccia completa — i quattro adapter forniti non fanno nulla di più che questo.
1

Racchiudi l'esecuzione

2

Racchiudi ogni strumento

In qualsiasi cosa il framework chiami wrapper di strumento o middleware.
3

Accoppia ogni chiamata di modello

Hai un confine di nodo, passo o middleware che vale la pena vedere? Avvolgilo in una coppia di hook — hook_triggered / hook_completed — non in un agent() annidato. agent_id è una sfaccettatura a bassa cardinalità, e un’entry per nodo lo annega. Gli span hook si rendono allo stesso modo e ti danno latenza per nodo.
Manuale e automatico si compongono. Un adapter in esecuzione dentro un ambito scritto a mano si unisce a quella sessione e si aggancia a quell’agente, quindi ottieni un albero anziché due — utile quando strumenti un framework da solo insieme a uno supportato.
Due motivi, e le tre giunzioni sopra sono la risposta ad entrambi:
  • autogen-core non è stata mantenuta dal settembre 2025.
  • AG2 non espone un punto di registrazione a livello di processo equivalente agli hook degli altri framework, quindi strumentarlo significa avvolgere ogni agente ad ogni sito di costruzione.
Mappare le giunzioni a mano registra gli stessi eventi, con la stessa fedeltà, che un adapter fornito darebbe.

Approfondisci

Come la registrazione funziona effettivamente. Niente di tutto ciò è necessario per iniziare.
Ogni registrazione ha la stessa forma: uno span si apre, il lavoro si annida dentro, e ogni evento di apertura ne ottiene uno di chiusura.La coppia è l’unità. Ogni evento di chiusura porta una durata che l’SDK misura dal suo evento di apertura.Di seguito è una vera esecuzione per framework — catturata dagli esempi forniti con l’SDK, nome del modello normalizzato. Nota quanto ritorna da una singola chiamata.
14 eventi
I nodi diventano coppie di hook, quindi ottieni la latenza per nodo senza che affollino l’elenco degli agenti.
Non c’è evento di chiusura sessione. Una sessione non è qualcosa che chiudi — è un gruppo di eventi che condividono un session_id.Lo stato è derivato dalla forma della traccia:Quindi una sessione termina quando ogni coppia è chiusa. Gli adapter emettono agent_end per te, e in fase di teardown chiudono qualsiasi cosa ancora aperta e la contrassegnano come incompleta — un’esecuzione arrestata si assesta come done con un gap visibile anziché stare sospesa.
Questo è il motivo per cui una sessione può coprire due chiamate. Un interrupt() di LangGraph mette in pausa l’esecuzione, lo span radice rimane deliberatamente aperto, e la chiamata ripresa lo chiude. Entrambe le chiamate sono una sessione.
session_id e agent_id sono opzionali in ogni metodo evento. Omessi, si risolvono dall’ambito che li racchiude:
Pasarli esplicitamente funziona ancora e ha precedenza. Senza nulla vincolato e nulla passato, la chiamata genera un TypeError che nomina la correzione anziché emettere un evento senza sessione, che l’ingest salterebbe mentre restituisce 200.Gli ambiti vincolano l’identità su variabili di contesto. Queste si propagano nei task asyncio automaticamente ma non nei nuovi thread — avvolgi un worker in failproofai_sdk.propagate().

Chi conia quale id

Come gli adapter risolvono session_id

La prima corrispondenza vince:
  1. Un session_id esplicito
  2. Metadati per-chiamata
  3. L’ambito session() che lo racchiude
  4. Metadati del framework
  5. L’id di esecuzione proprio del framework
Non è mai inventato mentre uno di questi esiste — un id sintetizzato dividerebbe un’esecuzione su più sessioni.

Mantieni agent_id a bassa cardinalità

È la sfaccettatura primaria su ogni superficie del dashboard, e una colonna LowCardinality(String). Un valore per-esecuzione degrada la colonna e riempie il dropdown del filtro con un’entry per esecuzione.Gli adapter difendono quella colonna per te:L’id reale è conservato su fw_agent_id / fw_run_id, dove rimane interrogabile senza essere una sfaccettatura.
Questa guardia tocca solo etichette che il framework ha scelto. Un agent_id che passi tu stesso — a event.*, o a failproofai_sdk.agent(...) — è registrato esattamente come dato. Riscrivere silenziosamente un argomento esplicito sarebbe peggio della cardinalità che previene, quindi nomina i tuoi span di conseguenza.
Quale framework registra cosa, misurato dalle esecuzioni sopra:Un trattino significa che il framework non ha un tale concetto. human_pause e human_interrupt descrivono una persona che agisce sull’agente, che nessun framework segnala — emettili tu stesso.
Un evento non arriva mai solo. Uno apre uno span, uno lo chiude, e l’evento di chiusura porta una durata che l’SDK misura dal suo evento di apertura.
Un evento di apertura senza uno di chiusura è uno span che non finisce mai. La sessione si rende come ancora in esecuzione, per sempre, e la sua durata attiva continua a crescere. Questo è il modo di fallimento da osservare quando strumenti a mano.

Regole di correlazione

  • Riutilizza lo stesso tool_call_id, hook_id, pause_id, o input_id per l’evento di completamento corrispondente.
  • L’SDK calcola duration_ms per tool_result, hook_completed, agent_resume, e human_input. Passarlo a questi metodi genera ValueError.
  • duration_ms è accettato su model_response, perché solo il chiamante conosce la vera latenza del provider. Deve essere un intero — un float genera ValueError al sito di chiamata, perché il server legge la colonna come un intero senza segno a 32 bit e memorizzerebbe NULL per qualsiasi cosa diversa.
  • Le chiavi di correlazione sono scoped per genere e sessione, quindi una chiamata di strumento e un hook possono condividere un id in sicurezza, e due sessioni contemporanee possono riutilizzare gli stessi id senza collisioni. Non sono scoped per agente: una coppia aperta sotto un agente e chiusa sotto un altro ancora si correla, che è il caso ordinario nei framework multi-agente.
  • request_id accoppia model_request con model_response. Senza di esso, gli eventi di modello si abbinano in ordine per agente, quindi le chiamate contemporanee si abbinano male.
  • Una coppia divisa tra processi ancora si correla a valle, ma l’SDK non può calcolarne la durata in-processo.
  • La mappa in sospeso contiene al massimo 10.000 avviamenti e elimina l’entry più vecchia quando è piena.
Installare failproofai-sdk installa tutto, tutti e quattro gli adapter inclusi. Gli extra tirano il framework, non l’adapter.
import failproofai_sdk è contrattualmente zero-dipendenza, applicato da un test che installa la wheel costruita con --no-deps e un altro che prova che nessun framework raggiunge sys.modules.
Non c’è un attributo failproofai_sdk.crewai. Gli adapter sono deliberatamente non esposti sul package di livello superiore: toccare uno importerebbe il framework come effetto collaterale di un accesso agli attributi, rompendo la promessa di zero-dipendenza. Usa instrument().
L’auto-rilevamento legge sys.modules, non l’elenco dei pacchetti installati, quindi un framework che hai installato ma mai importato non è strumentato e non è mai importato per tuo conto. Per vedere cosa è collegato:
instrument("crewai") su una macchina senza CrewAI non genera. Registra un avviso e restituisce (), quindi un framework mancante non fa mai cadere un processo che strumenta anche altri.L’avviso porta il sottostante ImportError, e quel messaggio nomina il comando di installazione esatto — così la correzione è nei tuoi log, non nascosta.
Imposta FAILPROOFAI_SDK_STRICT=1 affinché generi al contrario. Quel flag è letto una sola volta e cachato, quindi esportalo prima che il tuo processo inizi anziché impostarlo mid-run.
instrument() deve venire dopo il tuo import del framework. L’auto-rilevamento legge sys.modules, quindi una chiamata nuda sopra l’import trova nulla, installa nulla, e restituisce ().
Fai male e il processo viene eseguito con l’SDK importato, l’adapter apparentemente installato, e nemmeno un evento emesso. Registra un avviso dicendo esattamente quello — quindi controlla i tuoi log per primo quando un’esecuzione non registra nulla.
Lo spool è quello che rende questo sicuro: il tuo agente non si blocca mai sulla rete, e un’interruzione di Cloud significa una directory in crescita anziché eventi persi.Ogni flush scrive un file batch, .tmp per primo, poi fsync, poi un rename atomico:
Il daemon raccoglie solo .jsonl, quindi non può mai leggere un file scritto a metà. Lo stem porta un timestamp, id processo e numero di sequenza, quindi due processi che flushano nello stesso millisecondo non possono collisioni. La coda è limitata a 10.000 eventi; passato questo i più vecchi sono scartati e registrati.
collector.redact non si applica ai tuoi eventi SDK. Non li vede mai.
Il daemon spedisce i tuoi batch. Non li apre o li riscrive.La redazione viene eseguita dove il daemon scrive i suoi propri eventi — non dove i batch sono spediti. Quindi un prompt o un argomento di strumento che tiene una chiave API ancora la tiene all’arrivo.È deliberato. Queste sono le tue stesse chiamate di strumentazione, e riscriverle in transito significherebbe che gli eventi che ricevi non sono gli eventi che hai emesso.
Controlli i payload alla sorgente, in due posti:
  • Spegni la cattura di contenuto sull’adapter. Il nome dell’opzione differisce, e un adapter non ne ha alcuno — non è un singolo interruttore universale:
    • LangChain / LangGraph, Pydantic AI — capture_content=False
    • LlamaIndex — capture_messages=False
    • CrewAI — nessuno switch di contenuto; session_id è l’unica opzione che legge, quindi i prompt e i completamenti sono sempre registrati.
    instrument() scarta le opzioni che un adapter non legge, quindi passare il nome sbagliato non genera nulla e non cambia nulla.
  • Non consegnare il segreto a input= in primo luogo.
collector.redact non è un sostituto per nessuno dei due.
Una directory spool vuota è lo stato salutistico. Non usarla per controllare la consegna.
Il daemon cancella ogni batch entro millisecondi dalla sua spedizione, quindi un ls corre il collector e mostra una frazione di ciò che hai emesso — indistinguibile da un SDK che non ha registrato nulla.Per confermare che gli eventi effettivamente atterrano, controlla il dashboard. Per osservare lo spool riempirsi, ferma prima il daemon.
Ogni callback viene eseguito dentro un wrapper il cui unico compito è lanciare di nuovo, quindi la tua chiamata sta esattamente in un try e tutto ciò che l’SDK fa accade al di fuori di esso.Il default è giusto in produzione e sbagliato mentre esegui il debug, perché può solo mai provare “non è crashato”. Imposta FAILPROOFAI_SDK_STRICT=1 per rendere un fallimento ingoiato rumoroso.

Problemi comuni

Un evento di apertura non ha uno di chiusura: un model_request senza model_response, o un tool_use senza tool_result. Usa gli ambiti, che garantiscono la coppia anche quando il corpo genera. Se chiami i metodi evento direttamente, usa try e finally.
È misurato dall’evento di apertura corrispondente, quindi è rifiutato su tool_result, hook_completed, agent_resume, e human_input. È accettato su model_response, perché solo tu conosci la vera latenza del provider, e deve essere un intero.
Il thread non ha mai ereditato il contesto. Avvolgi il callable in failproofai_sdk.propagate(). Vedi Thread e async.
I campi extra si fondono ultimi, quindi uno denominato come un campo reale come model o outcome lo sovrascriverebbe e cambierebbe una colonna memorizzata. Spazianomina i tuoi; gli adapter usano un prefisso fw_.
agent_id è una sfaccettatura a bassa cardinalità e ci hai messo un id di esecuzione. Usa un nome di ruolo o nodo e metti l’id reale in un campo di payload.

Avanti

Come funziona

Coppie, id, ciclo di vita della sessione, e consegna.

Leggi una traccia

Segui la causalità attraverso la sessione che hai appena catturato.

Adapter di framework

LangGraph, CrewAI, LlamaIndex, e Pydantic AI.