Przejdź do głównej treści
Włączyłeś regułę powierzchni responsedeny lub sanitize na wywołaniach narzędzi, które twój model emituje — a twój agent woła bramę z "stream": true. Pytanie, które naprawdę ma znaczenie: czy odpowiedź strumieniowa może wyciec zablokowane wywołanie narzędzia, zanim firewall zdecyduje? Nie może, a ta strona wyjaśnia jeden mechanizm, który to zapewnia, byś mógł rozumować o opóźnieniu i fragmentach, które otrzymuje twój klient. To skupione spojrzenie na zachowanie SSE. Dla samych werdyktów zobacz Werdykty; dla gramatyki reguł zobacz referencję reguł.

1. Problem firewalla strumieniowego sse

Odpowiedź nie-strumieniowa to jedno ciało JSON — firewall widzi całość, ewaluuje tool_calls i zwraca oczyszczony wynik. Strumień jest inny: model emituje wywołanie narzędzia jako tuziny delt tool_call przez wiele ramek SSE, a gdy ramka zostanie przesłana, twój agent już ją ma — nie ma wycofania tokenu, który wysłałeś. Ewaluuj za wcześnie, a nie masz kompletnego wywołania (nazwa + pełne argumenty) do osądzenia; przesyłaj na bieżąco, a deny jest już za późno. Brama rozwiązuje to prostym, obserwowalnym kontraktem:

Treść strumieniuje na żywo

Normalne delty tekstu i rozumowania przechodzą niezmienione, w czasie rzeczywistym — zero dodanego opóźnienia na tokenach, które twój użytkownik czyta.

Ramki wywołań narzędzi są wstrzymywane

Dowolna ramka niosąca deltę tool_call (lub starszego function_call) jest wstrzymywana ze strumienia na żywo, dopóki wywołanie nie jest kompletne i zewaluowane.
Firewall to brama bezpieczeństwa, więc parsuje każdą ramkę. Nie zgaduje z surowych bajtów, że ramka jest tylko-treścią — escapowany w JSON składnik tool_calls nie ma dosłownego podłańcucha do dopasowania, więc skrót po podłańcuchu przesłałby niezewaluowane wywołanie narzędzia. Ramki SSE są małe; brama parsuje każdą z nich.

2. Sekwencja wstrzymaj-złóż-ewaluuj

Dla strumieniowej odpowiedzi chat-completions z aktywną polityką powierzchni response każda ramka, którą nadrzędny emituje, obiera jedną z dwóch ścieżek:
Strumieniuje do twojego klienta natychmiast, bajt-po-bajcie. Te nigdy nie niosą wywołania narzędzia, więc firewall nie ma czego decydować.
Buforowana poza strumieniem na żywo. Zamykająca ramka finish_reason tury narzędzia jest wstrzymywana razem z nią, ponieważ wyemitowanie jej wcześnie powiedziałoby twojemu klientowi, że tura jest skończona, zanim firewall orzeknie.
Na końcu strumienia brama składa wstrzymane ramki w kompletne wywołania narzędzi (łącząc strumieniowane fragmenty arguments każdego wywołania), ewaluuje każde z nich wobec twojej polityki na powierzchni responseta sama semantyka werdyktu i reguły co ścieżka nie-strumieniowa — i emituje tylko ocalałe:
Werdykt wstrzymanego wywołaniaCo otrzymuje twój klient
allow / auditOryginalne wstrzymane ramki, niezmienione — opóźniona przepustowość, nie ponownie zbatchowany fragment.
sanitizeWywołanie z przepisanymi argumentami (dopasowane sekrety/PII zastąpione typowanym tokenem), ponownie wyemitowane.
denyWywołanie jest odrzucone. Jeśli było jedynym wywołaniem tury, tura zamyka się z finish_reason: "stop" — strumień wygląda, jakby model nie zrobił żadnego wywołania narzędzia.
Jeśli nic nie dopasowało, płacisz tylko opóźnienie buforowania na ramkach wywołań narzędzi — treść już strumieniowała na żywo. Firewall rekonstruuje ramki tylko, gdy faktycznie działa (deny lub sanitize); czyste allow przesyła dokładne bajty twojego nadrzędnego.

3. Jeden konkretny przykład

Polityka response z regułą deny na *.delete (napisz ją w edytorze reguł konsoli) i żądanie strumieniowe, którego model decyduje wywołać zarówno db.query, jak i db.delete:
SSE timeline (what your agent receives)
───────────────────────────────────────
data: {"choices":[{"delta":{"content":"Looking that up…"}}]}   ← live
data: {"choices":[{"delta":{"content":" one moment."}}]}        ← live
                                                                ← db.query + db.delete
                                                                  tool_call frames HELD
─── end of stream ───
data: {"choices":[{"delta":{"role":"assistant",
        "tool_calls":[{"index":0,"function":{"name":"db.query",…}}]}}]}
data: {"choices":[{"finish_reason":"tool_calls"}]}
Twój agent odczytuje tekst asystenta w czasie rzeczywistym, potem otrzymuje tylko db.querydb.delete zostało złożone, zewaluowane, odmówione i nigdy nie wyemitowane. Ocalałe wywołanie jest reindeksowane od 0, a zdarzenie firewalla dla odmówionego wywołania ląduje w twoim logu zdarzeń z regułą, która odpaliła.
Wytocz politykę response strumieniową najpierw w trybie cienia. W trybie cienia każdy egzekwujący werdykt jest degradowany do audit (powód poprzedzony przedrostkiem [shadow] would …), a wszystkie ramki wywołań narzędzi przechodzą — więc możesz potwierdzić, że polityka dopasowuje to, czego oczekujesz, na prawdziwym ruchu strumieniowym, zanim zacznie odrzucać wywołania.

4. Blokady inbound zwierają obwód przed startem strumienia

Taniec wstrzymanych ramek dotyczy tylko powierzchni response — wywołań, które model emituje. Deny inbound (narzędzie, które agent ogłasza) odpala przed wywołaniem modelu nadrzędnego, więc żądanie strumieniowe, które uruchamia regułę inbound, nigdy nie otwiera strumienia SSE w ogóle: zwraca zwykłe HTTP 400 z kodem błędu firewall_blocked, oznaczone skip-retry. Bez ramek, bez okna wstrzymania — block ląduje jak każdy błąd nie-strumieniowy.

5. Guardrails na tym samym strumieniu

Odpowiedź strumieniowa może nieść politykę wyjścia Guardrail i politykę response firewalla naraz. Działają na różnych rzeczach — guardrails prześwietlają tekst, który model strumieniuje; firewall zarządza wywołaniami narzędzi — i komponują się:
  • Block wyjścia guardrail (strumieniowo): skaner wyjścia tnie strumień w momencie, gdy reguła się uruchomi, przesyła pojedynczy generyczny fragment zastępczy — [Response blocked by content policy.] z finish_reason: "content_filter" — i zatrzymuje się. Komunikat jest celowo generyczny (bez kategorii reguły), więc sondujący nie może wyliczyć twojej polityki. Wstrzymanie firewalla w locie, gdy to się dzieje, jest odrzucane, więc wstrzymane wywołanie narzędzia nie może się wymknąć po bloku.
  • Mask wyjścia guardrail (strumieniowo): maskowanie żądania przed modelem jest na żywo; maskowanie in-band na żywo strumieniowanego wyjścia jest w planach. Na strumieniu reguła mask rejestruje dopasowanie, ale obecnie przesyła oryginalny fragment — pisz ją, wiedząc, że redakcja nie jest jeszcze przepisana na drucie. Block wyjścia jest w pełni egzekwowany na strumieniach.
Ta strona opisuje kształt SSE chat-completions OpenAI. Ten sam kontrakt wstrzymaj-ewaluuj-emituj jest okablowany per format — natywne Anthropic Messages, Gemini, xAI i strumień OpenAI Responses każdy niesie go we własnym kształcie zdarzenia — więc zachowanie obserwowalne dla klienta jest identyczne niezależnie od tego, który dostawca obsłużył żądanie.

6. Co to oznacza dla twojego klienta

Kilka praktycznych konsekwencji modelu wstrzymanych ramek:
Tura, której jedyne wywołanie narzędzia zostało odmówione, zamyka się z finish_reason: "stop" zamiast "tool_calls" — dla twojego agenta czyta się to jako „model zdecydował się nie wywołać narzędzia”. Tura, gdzie niektóre wywołania ocalały, zamyka się z "tool_calls", niosąc tylko ocalałe.
Gdy nadrzędny dołącza usage tokenów do tego samego terminalnego fragmentu, który firewall wstrzymał, brama ponownie dołącza go do ostatniej zrekonstruowanej ramki — klient, który zażądał usage strumienia, wciąż go dostaje.
Jeśli model wyemitował treść i wywołanie narzędzia w tej samej ramce, treść jest odzyskiwana i ponownie emitowana, nawet gdy wywołanie narzędzia jest usuwane — zablokowanie jednego wywołania nigdy nie odrzuca twojego tekstu asystenta.
Nie zgłaszasz strumienia do żadnego z tego. Przypnij politykę do klucza (lub ustaw domyślną przestrzeni roboczej) i strumieniuj dokładnie jak wcześniej — egzekwowanie jest w bramie.

Dokąd dalej

Etapy i powierzchnie

inbound, response, mcp, egress — gdzie każda reguła ewaluuje.

Werdykty

allow, audit, deny, sanitize, pending_approval, cap_cost.

Sanityzuj argumenty

Zredaguj sekrety z argumentów wywołania narzędzia — tylko warstwa argumentów.

Tryb cienia

Degraduj egzekwujące werdykty do audit, gdy mierzysz wpływ.
Gdzie to siedzi na ścieżce żądania, zobacz jak OrcaRouter inspekcjonuje i opóźnienie ścieżki egzekwowania. Dla zagrożeń, które egzekwowanie na powierzchni response powstrzymuje, zobacz niebezpieczne wywołania narzędzi i eksfiltrację danych. Dla pełnej gramatyki reguł zobacz referencję reguł firewalla.