Skip to main content
Para um agente que você mesmo escreveu, ou um framework para o qual Failproof AI não possui adaptador. Não há nada a instrumentar: você emite os eventos. Esta é a mesma API que os quatro adaptadores de framework utilizam internamente. Eles são tabelas de tradução sobre ela.

Instalação

Sem extras e sem dependências.

Instrumentação

Leia de cima para baixo e o código diz o que significa: E o que cada um emite de fato: Tudo que está dentro pode omitir session_id e agent_id. Os escopos vinculam identidade em variáveis de contexto e cada chamada de evento a lê de volta, então você nunca precisa passar ids pelas suas funções. Os três funcionam com async with assim como com with. Aninhar agentes constrói a árvore. parent_id e profundidade são calculados a partir da pilha:

Como um escopo é fechado

agent() trata exceções para você: O erro é emitido antes de agent_end, porque o dashboard fecha o span em agent_end e qualquer coisa depois disso não é atribuída a nada. Um cancelamento não é uma falha, então execuções canceladas não poluem a superfície de erros. A exceção sempre é relançada: um escopo nunca a engole.

Os métodos de evento

Quinze métodos em seis famílias. A maioria vem em pares — você emite o abridor, depois o fechador, e o SDK mede o span entre eles.
Prefira os escopos — agent() e tool_call() — sempre que se encaixarem. Eles garantem o evento de fechamento mesmo quando o corpo lança uma exceção. Recorra a esses métodos diretamente quando seu fluxo de controle não for aninhado, como uma chamada de modelo dentro de um helper.
As duas famílias de humanos apontam em direções opostas.Nenhum framework sinaliza o segundo par, então sempre cabe a você emiti-lo.
Passe request_id quando chamadas de modelo rodarem concorrentemente. Sem ele, requisições e respostas são emparelhadas na ordem de chegada por agente — e chamadas concorrentes se desemparelham, associando cada resposta à requisição errada.

Exemplo

Um loop de chamada de ferramentas contra a API da OpenAI, sem framework de agentes:
Isso produz os mesmos seis tipos de evento que um adaptador forneceria. A versão completa e executável, com as definições de ferramentas, está disponível no repositório do SDK em docs/manual/examples/.

Threads e async

Variáveis de contexto se propagam automaticamente para tarefas asyncio. Elas não se propagam para novas threads, porque uma thread começa com um contexto vazio.
Sem propagate(), os eventos do worker lançam um TypeError indicando a correção, em vez de serem associados a nenhuma sessão. Isso é intencional: um evento sem sessão é ignorado pelo ingest e respondido com 200, que é a falha silenciosa que a camada de identidade existe para evitar.

Instrumentar um framework sem adaptador

Todo framework de agentes oferece as mesmas três costuras. Mapeie-as e você terá um trace completo — os quatro adaptadores fornecidos não fazem nada além disso.
1

Delimite a execução

2

Delimite cada ferramenta

No que quer que o framework chame de wrapper de ferramenta ou middleware.
3

Emparelhe cada chamada de modelo

Tem um limite de nó, passo ou middleware que vale a pena visualizar? Envolva-o em um par de hook — hook_triggered / hook_completed — não em um agent() aninhado. agent_id é uma faceta de baixa cardinalidade, e uma entrada por nó a satura. Spans de hook são renderizados da mesma forma e fornecem latência por nó.
Manual e automático se compõem. Um adaptador rodando dentro de um escopo escrito à mão entra nessa sessão e torna-se filho daquele agente, então você obtém uma árvore em vez de duas — útil quando você instrumenta um framework manualmente ao lado de um suportado.
Dois motivos, e as três costuras acima são a resposta para ambos:
  • autogen-core não é mantido desde setembro de 2025.
  • O AG2 não expõe nenhum ponto de registro global equivalente aos hooks dos outros frameworks, então instrumentá-lo significa envolver cada agente em cada local de construção.
Mapear as costuras manualmente registra os mesmos eventos, com a mesma fidelidade, que um adaptador fornecido faria.

Indo mais fundo

Como a gravação realmente funciona. Nada disso é necessário para começar.
Toda gravação tem a mesma forma: um span abre, o trabalho aninha dentro dele, e cada evento de abertura recebe um de fechamento.O par é a unidade. Cada evento de fechamento carrega uma duração que o SDK mede a partir do evento de abertura correspondente.Abaixo há uma execução real por framework — capturada a partir dos exemplos que acompanham o SDK, com o nome do modelo normalizado. Note o quanto retorna de uma única chamada.
14 events
Nós se tornam pares de hook, então você obtém latência por nó sem sobrecarregar a lista de agentes.
Não existe evento de fim de sessão. Uma sessão não é algo que você fecha — é um grupo de eventos que compartilham um session_id.O status é derivado da forma do trace:Então uma sessão termina quando todos os pares são fechados. Os adaptadores emitem agent_end para você, e no encerramento fecham tudo que ainda estiver aberto e marcam como incompleto — uma execução com crash se resolve como done com uma lacuna visível, em vez de ficar pendente.
É por isso que uma sessão pode abranger duas chamadas. Um interrupt() do LangGraph pausa a execução, o span raiz permanece aberto deliberadamente, e a chamada de retomada o fecha. Ambas as chamadas são uma única sessão.
session_id e agent_id são opcionais em todo método de evento. Quando omitidos, são resolvidos a partir do escopo envolvente:
Passá-los explicitamente ainda funciona e tem precedência. Se nada estiver vinculado e nada for passado, a chamada lança um TypeError indicando a correção, em vez de emitir um evento sem sessão, que o ingest ignoraria enquanto responderia 200.Os escopos vinculam identidade em variáveis de contexto. Essas se propagam automaticamente para tarefas asyncio, mas não para novas threads — envolva um worker em failproofai_sdk.propagate().

Quem gera qual id

Como adaptadores resolvem session_id

O primeiro match vence:
  1. Uma opção session_id explícita
  2. Metadados por chamada
  3. O escopo session() envolvente
  4. Metadados do framework
  5. O próprio id de execução do framework
Ele nunca é inventado enquanto um desses existir — um id sintetizado dividiria uma execução entre várias sessões.

Mantenha agent_id com baixa cardinalidade

É a faceta principal em toda superfície do dashboard, e uma coluna LowCardinality(String). Um valor por execução degrada a coluna e preenche o dropdown de filtros com uma entrada por execução.Os adaptadores protegem essa coluna para você:O id real é mantido em fw_agent_id / fw_run_id, onde permanece consultável sem ser uma faceta.
Esta proteção só toca rótulos que o framework escolheu. Um agent_id que você passa você mesmo — para event.* ou para failproofai_sdk.agent(...) — é gravado exatamente como fornecido. Reescrever silenciosamente um argumento explícito seria pior do que a cardinalidade que previne, então nomeie seus próprios spans adequadamente.
O que cada framework registra, medido a partir das execuções acima:Um traço significa que o framework não possui tal conceito. human_pause e human_interrupt descrevem uma pessoa agindo sobre o agente, o que nenhum framework sinaliza — emita-os você mesmo.
Um evento nunca chega sozinho. Um abre um span, outro o fecha, e o evento de fechamento carrega uma duração que o SDK mede a partir do evento de abertura.
Um evento de abertura sem evento de fechamento é um span que nunca termina. A sessão é renderizada como ainda em execução, para sempre, e sua duração ativa continua crescendo. Este é o modo de falha a observar quando você instrumenta manualmente.

Regras de correlação

  • Reutilize o mesmo tool_call_id, hook_id, pause_id ou input_id para o evento de conclusão correspondente.
  • O SDK calcula duration_ms para tool_result, hook_completed, agent_resume e human_input. Passá-lo nesses métodos lança ValueError.
  • duration_ms é aceito em model_response, porque apenas quem chama conhece a latência real do provedor. Deve ser um inteiro — um float lança ValueError no ponto de chamada, porque o servidor lê a coluna como um inteiro sem sinal de 32 bits e armazenaria NULL para qualquer outro valor.
  • Chaves de correlação têm escopo por tipo e sessão, então uma chamada de ferramenta e um hook podem compartilhar um id com segurança, e duas sessões concorrentes podem reutilizar os mesmos ids sem colisão. Elas não têm escopo por agente: um par aberto sob um agente e fechado sob outro ainda correlaciona, que é o caso comum em frameworks multi-agente.
  • request_id emparelha model_request com model_response. Sem ele, eventos de modelo são emparelhados em ordem por agente, então chamadas concorrentes se desemparelham.
  • Um par dividido entre processos ainda correlaciona no downstream, mas o SDK não pode calcular sua duração em processo.
  • O mapa pendente armazena no máximo 10.000 inícios e remove a entrada mais antiga quando cheio.
Instalar failproofai-sdk instala tudo, incluindo os quatro adaptadores. Os extras instalam o framework, não o adaptador.
import failproofai_sdk é contratualmente de dependência zero, verificado por um teste que instala o wheel compilado com --no-deps e outro que prova que nenhum framework alcança sys.modules.
Não existe atributo failproofai_sdk.crewai. Os adaptadores são deliberadamente não expostos no pacote de nível superior: acessar um importaria o framework como efeito colateral de um acesso a atributo, quebrando a promessa de dependência zero. Use instrument().
A detecção automática lê sys.modules, não a lista de pacotes instalados, então um framework que você tem instalado mas nunca importou não é instrumentado e nunca é importado em seu nome. Para ver o que está conectado:
instrument("crewai") em uma máquina sem CrewAI não lança exceção. Registra um aviso e retorna (), então um framework ausente nunca derruba um processo que também instrumenta outros.O aviso carrega o ImportError subjacente, e essa mensagem indica o comando exato de instalação — então a correção está nos seus logs, não oculta.
Defina FAILPROOFAI_SDK_STRICT=1 para que ele lance uma exceção em vez disso. Essa flag é lida uma vez e armazenada em cache, então exporte-a antes de seu processo iniciar em vez de defini-la durante a execução.
instrument() deve vir depois da importação do seu framework. A detecção automática lê sys.modules, então uma chamada sem argumentos acima do import não encontra nada, não instala nada e retorna ().
Errar isso e o processo roda com o SDK importado, o adaptador aparentemente instalado, e nenhum evento emitido. Ele registra um aviso dizendo exatamente isso — então verifique seus logs primeiro quando uma execução não registrar nada.
O spool é o que torna isso seguro: seu agente nunca bloqueia na rede, e uma interrupção do Cloud significa um diretório crescendo em vez de eventos perdidos.Cada flush escreve um arquivo de lote, .tmp primeiro, depois fsync, depois um rename atômico:
O daemon só lê .jsonl, então nunca pode ler um arquivo parcialmente escrito. O nome do arquivo carrega um timestamp, id de processo e número de sequência, então dois processos fazendo flush no mesmo milissegundo não podem colidir. A fila tem capacidade máxima de 10.000 eventos; além disso, descarta os mais antigos e registra um log.
collector.redact não se aplica aos seus eventos do SDK. Ele nunca os vê.
O daemon envia seus lotes. Ele não os abre nem os reescreve.A redação roda onde o daemon escreve seus próprios eventos — não onde os lotes são enviados. Então um prompt ou argumento de ferramenta contendo uma chave de API ainda a contém na chegada.Isso é intencional. Estas são suas próprias chamadas de instrumentação, e reescrevê-las em trânsito significaria que os eventos que você recebe não são os eventos que você emitiu.
Você controla os payloads na fonte, em dois lugares:
  • Desative a captura de conteúdo no adaptador. O nome da opção é diferente, e um adaptador não tem nenhuma — este não é um interruptor universal único:
    • LangChain / LangGraph, Pydantic AI — capture_content=False
    • LlamaIndex — capture_messages=False
    • CrewAI — sem opção de conteúdo alguma; session_id é a única opção que ele lê, então prompts e completions são sempre gravados.
    instrument() descarta opções que um adaptador não lê, então passar o nome errado não lança nada e não altera nada.
  • Não passe o segredo para input= em primeiro lugar.
collector.redact não é substituto para nenhum dos dois.
Um diretório de spool vazio é o estado saudável. Não o use para verificar a entrega.
O daemon deleta cada lote em milissegundos após enviá-lo, então um ls compete com o collector e mostra uma fração do que você emitiu — indistinguível de um SDK que não gravou nada.Para confirmar que os eventos realmente chegaram, verifique o dashboard. Para observar o spool enchendo, pare o daemon primeiro.
Todo callback roda dentro de um wrapper cuja única função é relançar, então sua chamada fica em exatamente um try e tudo que o SDK faz acontece fora dele.O padrão é correto em produção e errado durante debug, porque só pode provar “não crashou”. Defina FAILPROOFAI_SDK_STRICT=1 para tornar uma falha engolida visível.

Problemas comuns

Um evento de abertura não tem evento de fechamento: um model_request sem model_response, ou um tool_use sem tool_result. Use os escopos, que garantem o par mesmo quando o corpo lança uma exceção. Se você chamar os métodos de evento diretamente, use try e finally.
É medido a partir do evento de abertura correspondente, então é rejeitado em tool_result, hook_completed, agent_resume e human_input. É aceito em model_response, porque apenas você conhece a latência real do provedor, e deve ser um inteiro.
A thread nunca herdou o contexto. Envolva o callable em failproofai_sdk.propagate(). Veja Threads e async.
Campos extras são mesclados por último, então um nomeado como um campo real, como model ou outcome, o sobrescreveria e alteraria uma coluna armazenada. Use um namespace nos seus; os adaptadores usam o prefixo fw_.
agent_id é uma faceta de baixa cardinalidade e você colocou um id de execução nela. Use um nome de role ou nó e coloque o id real em um campo de payload.

Próximos passos

Como funciona

Pares, ids, ciclo de vida da sessão e entrega.

Leia um trace

Siga a causalidade pela sessão que você acabou de capturar.

Adaptadores de framework

LangGraph, CrewAI, LlamaIndex e Pydantic AI.