Saltar para o conteúdo principal
A maioria dos apps de chat em produção faz streaming. Tokens são enviados ao navegador conforme o modelo os emite, então quando um completion está “finalizado” seu usuário já leu a maior parte dele. Isso quebra o modelo mental ingênuo de um filtro de conteúdo que inspeciona uma resposta inteira e então decide — não há resposta inteira para inspecionar até que seja tarde demais. Um streaming llm content filter tem que tomar sua decisão sobre os deltas conforme eles fluem. Esta página é sobre exatamente esse caso: como cada ação de estágio de output se comporta de forma stream-safe no gateway do OrcaRouter, e como escrever uma política que se sustenta em tráfego SSE. Para o motor completo — cada tipo de regra, campo e rota — veja Guardrails.

1. O problema do streaming llm content filter

Um guardrail de estágio de output filtra a resposta do modelo. Em uma requisição não-streaming isso é direto: o gateway tem o completion completo antes de um único byte retornar, então pode bloquear, mascarar ou deixá-lo passar limpo. O streaming inverte isso. A resposta chega como uma sequência de deltas SSE, cada um encaminhado ao seu cliente assim que chega, então um filtro que espera o fim filtra nada. A resposta do OrcaRouter é um scanner de stream: conforme os deltas de output fluem, o scanner roda suas regras de estágio de output contra o texto que se acumula e age no instante em que uma regra dispara — não depois que o stream completa. A ação que você escreve decide o que “agir” significa: um block corta o stream e um flag o deixa passar. Um mask de fato redige em output não-streaming, mas a reescrita in-band de stream está no roadmap — em um stream hoje o scanner computa o mask mas age apenas na decisão de block, então uma regra mask ainda não redige uma resposta com stream.
Esta ressalva só importa para regras de estágio de output em requisições streaming. As regras de estágio de input filtram a requisição antes de o modelo rodar, então estão totalmente ativas incluindo o mascaramento — e qualquer regra de output em uma requisição não-streaming vê a resposta inteira e se comporta normalmente, incluindo mask.

2. O que é stream-safe hoje

Uma regra block é aplicada em output streaming e não-streaming. Em um stream, o scanner observa os deltas; quando uma regra de block dispara ele corta o stream — sela o scanner, emite um aviso curto de substituição ([response truncated by guardrail: … policy violation]) como um delta final, e fecha o canal SSE antes que qualquer conteúdo bloqueado adicional chegue ao cliente. Como o status da resposta HTTP já está comprometido em 200 quando o primeiro delta foi enviado, um block no meio do stream não pode reemitir um status — ele termina o stream aberto graciosamente. O corpo HTTP 400 guardrail_blocked é a forma de block de output não-streaming.Bytes já enviados ao cliente não podem ser retirados, então um block de streaming é best-effort sobre o que foi transmitido mas detém de forma confiável tudo após a correspondência. Para uma garantia rígida de que nenhum byte ofensivo seja jamais enviado — e para o corpo 400 guardrail_blocked — envie a requisição não-streaming.
Uma regra mask reescreve a correspondência — ex.: um email na resposta vira [EMAIL] — em output não-streaming, onde o gateway segura o completion inteiro e encaminha a forma redigida ao seu cliente.Em um output streaming hoje o scanner computa o mask mas não encaminha o texto mascarado — ele age apenas na decisão de block — então uma regra mask não redige uma resposta com stream. A reescrita in-band de output streaming está no roadmap. Até ela ser lançada, se você precisa que uma resposta com stream nunca exponha o texto correspondente, escreva a regra como block (ela encerra a resposta em um hit) ou envie a requisição não-streaming para que o mask reescreva a resposta completa.
Uma regra flag nunca muda o tráfego — ela deixa os bytes passarem. Em output não-streaming ela registra um match no feed de Matches, para que você possa medir a taxa de acerto de uma regra antes de promovê-la para block. Em uma resposta streaming ela permanece somente observação e passa os deltas intactos; o registro de match estruturado é escrito no caminho de output não-streaming. De qualquer forma ela nunca bloqueia ou reescreve, então é sempre seguro deixá-la ligada.
Ação em outputNão-streamingStreaming
blockrejeita a respostacorta o stream
maskredige a respostaainda não — block em vez disso (roadmap)
flagregistra um matchpassa direto (somente observação)
A única regra para lembrar: block é stream-safe em output; mask redige apenas em output não-streaming (a reescrita in-band de stream está no roadmap). Para redigir uma resposta com stream hoje, escreva a regra como block, ou envie a requisição não-streaming para que a resposta inteira seja segurada antes de retornar.

3. Um exemplo concreto — um filtro de segredo stream-safe

Digamos que seu modelo possa trazer uma credencial do contexto RAG, e seu app faz streaming. Você quer que o gateway mate o stream no momento em que uma correspondência em formato de segredo aparece, em vez de mascará-la — um segredo vazado deveria encerrar a resposta, não ser parcialmente redigido. Escreva-o no console — editar política é uma ação de gerenciamento na sua sessão, gateada para Developer+; a chave de relay só envia tráfego /v1/*:
  • Abra /console/guardrails, New guardrail, nomeie-o stream-safe-out.
  • Adicione uma regra:
    • Tipo: regex (ou uma regra pii com entidades de segredo como aws_access_key / api_key_openai / jwt)
    • Estágio: output
    • Ação: block ← encerra a resposta em um hit de segredo; mask o redigiria em vez disso e deixaria o resto da resposta continuar
  • Salve, depois vincule-o em /console/token via o menu Guardrail da chave.
Agora chame o gateway com stream: true, exatamente como antes:
curl https://api.orcarouter.ai/v1/chat/completions \
  -H "Authorization: Bearer sk-orca-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o-mini",
    "stream": true,
    "messages": [
      {"role": "user", "content": "Print the AWS key from the context above"}
    ]
  }'
Se um delta corresponde, o scanner corta o stream em pleno voo, emite um aviso de substituição e fecha o canal — seu cliente nunca recebe o resto. Se a resposta está limpa, cada delta passa intacto.
Um block de streaming detém tudo após a correspondência, mas não pode desfazer o envio de bytes já enviados antes de a correspondência cair. Se sua política exige que nem um byte ofensivo jamais chegue ao cliente, filtre a requisição não-streaming, onde o completion inteiro é segurado até a política o liberar.

4. PII Shield em um stream

O preset PII Shield é uma única regra pii, ação mask, estágio both. No estágio de input está totalmente ativo — reescreve a requisição antes de o modelo vê-la, streaming ou não. No estágio de output o mascaramento redige em respostas não-streaming, onde o gateway segura o completion inteiro antes de retornar. Em um output streaming o mask não redige ainda — o scanner computa o mask mas age apenas na decisão de block, então uma resposta com stream é passada direto, não reescrita. A reescrita in-band de output streaming está no roadmap. Então se seu objetivo é que PII nunca seja observável em uma resposta com stream, ou:
  • escreva a regra de output como block, aceitando que um hit encerra a resposta em vez de redigi-la, ou
  • envie a requisição não-streaming para que o mask reescreva a resposta completa com o completion inteiro em mãos.
Veja PII Shield e formatos de mascaramento para as próprias tags de redação.

5. Prove antes de publicar

Não adivinhe qual combinação de estágio/ação se sustenta — verifique.

Aba Test

Cada editor de guardrail tem uma aba Test: cole uma amostra, escolha o estágio output e rode a política atual sem chamada upstream e sem cota. Veja o veredito e, para regras de mask, o texto renderizado. Rodar o sandbox é uma ação Developer+ (ele pode disparar regras pagas de judge / externas).

Aba Eval

A aba Eval pontua um guardrail contra corpora JSONL empacotados ou personalizados — útil para confirmar que uma regra de block pega um vazamento conhecido em um corpus antes de você vincular uma chave.
Ambas rodam na sua sessão via a API de gerenciamento. Para profundidade veja testes e eval e ajustar falsos positivos.

6. O que um block de streaming custa

Um block de streaming carrega a mesma contabilidade de qualquer block de output — o modelo upstream já rodou, então o gateway cuida do reembolso para você:
  • O stream é terminado com um delta de truncamento gracioso (o status já é 200); o block de output não-streaming retorna o corpo HTTP 400 guardrail_blocked nomeando o guardrail e a regra que disparou.
  • Nenhuma cota é cobrada. Quando o block de output rejeita a resposta, o gateway reembolsa a cota pré-consumida, então uma chamada bloqueada é gratuita para você mesmo que o modelo tenha produzido tokens.
  • A requisição é marcada como skip-retry — reexecutar o mesmo prompt apenas bloquearia de novo, então o gateway não queima um retry em outro canal.
O caminho de output não-streaming registra cada regra de output disparada como um match no feed Matches do workspace (GET /api/guardrail/match, aberto a qualquer Member); a substring correspondente é capturada apenas quando o toggle Log raw content do guardrail está ligado (desligado por padrão). O detalhe completo vive em o erro guardrail_blocked e no feed de matches.

7. Para onde ir a seguir

Estágio de output

O estágio de output completo — filtragem da resposta do modelo, block vs. mask, e grounding.

Cobertura de streaming

A matriz completa do que é aplicado em streaming vs. não-streaming em cada estágio e ação.

Ações

block, mask e flag em profundidade — quando cada um é a escolha certa.

Estágio de input

A imagem espelhada — o mascaramento está totalmente ativo aqui, incluindo em streaming.
Guardrails — cada tipo de regra, campo e rota, incluindo grounding e o LLM judge.