deny 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ść, ewaluujetool_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:Ramka treści / roli / rozumowania / usage → przesłana teraz
Ramka treści / roli / rozumowania / usage → przesłana teraz
Strumieniuje do twojego klienta natychmiast, bajt-po-bajcie. Te nigdy nie
niosą wywołania narzędzia, więc firewall nie ma czego decydować.
Ramka tool_call (lub starsza function_call) → wstrzymana
Ramka tool_call (lub starsza function_call) → wstrzymana
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.arguments każdego wywołania),
ewaluuje każde z nich wobec twojej polityki na powierzchni response — ta
sama semantyka werdyktu i reguły co ścieżka nie-strumieniowa — i emituje
tylko ocalałe:
| Werdykt wstrzymanego wywołania | Co otrzymuje twój klient |
|---|---|
allow / audit | Oryginalne wstrzymane ramki, niezmienione — opóźniona przepustowość, nie ponownie zbatchowany fragment. |
sanitize | Wywołanie z przepisanymi argumentami (dopasowane sekrety/PII zastąpione typowanym tokenem), ponownie wyemitowane. |
deny | Wywoł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. |
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:
db.query — db.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.
4. Blokady inbound zwierają obwód przed startem strumienia
Taniec wstrzymanych ramek dotyczy tylko powierzchni response — wywołań, które model emituje. Denyinbound
(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.]zfinish_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:finish_reason może się zmienić
finish_reason może się zmienić
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.usage wciąż przybywa
usage wciąż przybywa
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.tekst, który dzielił fragment z wywołaniem narzędzia, jest zachowany
tekst, który dzielił fragment z wywołaniem narzędzia, jest zachowany
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.
bez zmiany w kodzie agenta
bez zmiany w kodzie agenta
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.
