Blog
Arquitetura

Inference hooks do Claude: se o seu servidor de política cair, quem decide é um checkbox

O Claude Enterprise agora manda cada prompt e cada tool call para o seu servidor de segurança antes do modelo rodar. Mas um erro desse servidor nunca vira deny. Como eu montaria esse servidor e o que eu decidiria antes de ligar.

Um timeout no seu servidor de política nunca vira bloqueio. Quem decide se o pedido passa ou trava é a configuração de failure handling que alguém marcou no painel.

Esse é o detalhe que eu olharia primeiro nos inference hooks, que a Anthropic acabou de colocar como GA no Claude Enterprise junto com um security center em beta.

O que acontece

A ideia é simples. Antes de cada inferência, a Anthropic faz um POST assinado para um servidor HTTPS seu (a doc chama de AI security server) com a transcrição da conversa. O servidor responde allow ou deny. Se negar, o pedido nem chega no modelo e a pessoa vê o motivo que você escreveu.

São dois eventos. O prompt dispara antes da inferência. O tool_call dispara quando a resposta do modelo tem chamadas de ferramenta, antes de qualquer uma rodar, se a opção Validate tool calls estiver ligada. Um único hook vale para claude.ai, Cowork, Claude Code, Claude in Chrome e o resto, sem instalar nada na máquina de ninguém.

Pense na portaria de um prédio que liga para o apartamento antes de deixar a visita subir. Funciona bem. Mas se o interfone estiver mudo, a regra do condomínio é que decide: ou ninguém sobe, ou todo mundo sobe.

Por que isso importa

Pela doc, timeout, status diferente de 200, corpo que não dá para ler e endpoint fora do ar contam como falha de webhook. E uma falha de webhook nunca vira deny. O orçamento padrão é de 5 segundos para a troca inteira, com conexão e TLS incluídos. A Anthropic tenta de novo uma única vez, e só se a conexão nem abriu.

Tem mais uma peça. Falhas seguidas abrem um circuit breaker: a Anthropic para de chamar o seu servidor e aplica o failure handling em todo pedido. Enquanto o breaker está aberto, o Activity Feed não registra os pedidos um a um. Fica só o registro de que o breaker abriu.

Então a pergunta de arquitetura vem antes do código. Se a sua política for “falha aberta”, uma indisponibilidade de dez minutos no servidor vira dez minutos sem DLP nenhum. Se for “falha fechada”, vira dez minutos com todo mundo da empresa travado no Claude. Acho que as duas respostas são defensáveis. Depende do que vaza se passar.

Como eu montaria o servidor

Veja: o servidor precisa ser rápido e chato. Cada milissegundo dele soma na latência de todo pedido da organização, inclusive em shadow mode quando a validação de tool call está ligada.

Um esboço em TypeScript, só com o que a doc especifica:

type Verdict = { action: "allow" } | { action: "deny"; deny_reason: string };

export async function handle(req: Request): Promise<Response> {
  const raw = await req.text();
  if (!verifySignature(req.headers, raw)) {
    return new Response("bad signature", { status: 401 });
  }

  const frame = JSON.parse(raw);
  const id = req.headers.get("webhook-id"); // igual ao request_id, serve de chave de idempotência

  let verdict: Verdict = { action: "allow" };
  if (frame.type === "prompt" || frame.type === "tool_call") {
    verdict = await checkPolicy(frame); // DLP, allowlist de modelo, regra por projeto
  }
  // tipo desconhecido: allow. A doc pede isso, porque erro conta como falha e abre o breaker.

  queueAudit(id, frame.type, verdict); // grava depois de responder, fora do caminho crítico
  return Response.json(verdict);
}

Três decisões estão aí dentro. A assinatura segue o Standard Webhooks, um HMAC-SHA256 sobre webhook-id, timestamp e corpo, comparado em tempo constante. Allowlist do bloco de IP da Anthropic ajuda, mas a própria doc diz que não substitui a assinatura. Evento de tipo novo recebe allow, porque responder erro conta como falha. E a auditoria vai para uma fila, porque escrever no banco antes de responder é pagar latência que o usuário sente.

O deny_reason também merece cuidado. Ele vai direto para a tela da pessoa, com no máximo 500 caracteres. “Remova o número do cartão e envie de novo” ajuda. “DLP-RULE-4471” não ajuda ninguém.

O que eu checaria antes de ligar

Começaria em shadow mode, que registra os vereditos sem bloquear nada, e depois subiria por porcentagem de pedidos. Quem vem de DLP tradicional costuma esperar mascarar o trecho sensível e deixar o resto passar. Pera. Aqui o veredito é só allow ou deny, sem reescrita. E imagem sem texto extraído não é inspecionada, então print de documento passa.

Outro ponto que pega o usuário: cada pedido carrega a conversa inteira. Se o servidor avalia a transcrição toda, a mensagem negada continua lá e todo pedido seguinte também é negado. No Claude Code o caminho é /rewind até o prompt que trouxe o conteúdo. Vale colocar isso no texto do motivo.

Na prática, eu levaria para a reunião com segurança três perguntas: falha aberta ou fechada, quem atende quando o breaker abrir, e qual o p99 do servidor sob carga. Qual vocês escolheriam para falha?

Fontes

esc
  • Home Início
  • Sobre Trajetória e como trabalho
  • Blog Artigos sobre IA, plataforma e liderança
  • Projetos Demos públicos de frontend com IA
  • Currículo Web, PDF, Markdown e texto
  • Setup Hardware e ferramentas
  • Inference hooks do Claude: se o seu servidor de política cair, quem decide é um checkbox Arquitetura
  • Claude Code vazava o e-mail no User-Agent: o que eu checaria amanhã Segurança
  • Sete fases e onze testes: como a tela do agente aguenta queda, pausa e falta de rede Arquitetura
  • RAG no navegador custa 23 MB de download: como eu decidiria entre WebGPU e backend Arquitetura
↑↓ navegar ↵ abrir esc fechar