Chuyển đến nội dung chính
Bạn đã bật một quy tắc bề-mặt-responsedeny hoặc sanitize trên các cuộc gọi tool mà mô hình của bạn phát ra — và agent của bạn gọi gateway với "stream": true. Câu hỏi thực sự quan trọng: một phản hồi streaming có thể rò rỉ một cuộc gọi tool bị block trước khi firewall quyết định không? Nó không thể, và trang này giải thích cơ chế duy nhất làm điều đó thành sự thật để bạn có thể suy luận về độ trễ và các chunk mà client của bạn nhận. Đây là một cái nhìn tập trung vào hành vi SSE. Để biết bản thân các verdict, xem Verdict; để biết ngữ pháp quy tắc, xem tham chiếu quy tắc.

1. Bài toán firewall streaming sse

Một phản hồi không-streaming là một thân JSON — firewall thấy toàn bộ, đánh giá các tool_calls, và trả về kết quả đã làm sạch. Một stream thì khác: một mô hình phát ra một cuộc gọi tool dưới dạng hàng chục delta tool_call trên nhiều frame SSE, và một khi một frame được chuyển tiếp, agent của bạn đã có nó — không có việc thu hồi một token bạn đã gửi. Đánh giá quá sớm và bạn không có cuộc gọi đầy đủ (tên + đối số đầy đủ) để phán xét; chuyển tiếp khi đi và một deny đã quá muộn. Gateway giải quyết điều này bằng một hợp đồng đơn giản, quan sát được:

Content stream live

Các delta văn bản và reasoning bình thường đi qua không đổi, trong thời gian thực — không thêm độ trễ nào trên các token mà người dùng của bạn đọc.

Các frame tool-call được giữ

Bất kỳ frame nào mang một delta tool_call (hoặc function_call legacy) đều bị giữ lại khỏi stream live cho đến khi cuộc gọi hoàn tất và được đánh giá.
Firewall là một cổng bảo mật, nên nó parse mọi frame. Nó không đoán một frame là chỉ-content từ các byte thô — một thành viên tool_calls đã JSON-escape không có chuỗi con literal để khớp, nên một lối tắt chuỗi-con sẽ chuyển tiếp một cuộc gọi tool chưa-đánh-giá. Các frame SSE nhỏ; cổng parse từng cái.

2. Trình tự giữ-lắp ráp-đánh giá

Với một phản hồi chat-completions streaming có một chính sách bề-mặt-response hoạt động, mỗi frame mà thượng nguồn phát ra đi một trong hai đường:
Stream qua tới client của bạn ngay lập tức, byte-cho-byte. Những cái này không bao giờ mang một cuộc gọi tool, nên firewall không có gì để quyết định.
Buffer ra khỏi stream live. Frame finish_reason đóng của một lượt tool được giữ cùng nó, vì phát ra nó sớm sẽ báo cho client của bạn rằng lượt đã xong trước khi firewall phán xét.
cuối-stream, gateway lắp ráp các frame được giữ thành các cuộc gọi tool đầy đủ (nối các mảnh arguments được stream của mỗi cuộc gọi), đánh giá mọi cái với chính sách của bạn trên bề mặt responsecùng ngữ nghĩa verdict và quy tắc như đường không-streaming — và chỉ phát ra các cái sống sót:
Verdict của cuộc gọi được giữCái client của bạn nhận
allow / auditCác frame được giữ gốc, không đổi — một pass-through bị trễ, không phải một chunk được re-batch.
sanitizeCuộc gọi với các đối số được viết lại (secret/PII đã khớp thay bằng một token có kiểu), phát ra lại.
denyCuộc gọi bị bỏ. Nếu nó là cuộc gọi duy nhất của lượt, lượt đóng với finish_reason: "stop" — stream trông như mô hình không làm cuộc gọi tool nào.
Nếu không gì khớp, bạn chỉ trả giá độ trễ buffer trên các frame tool-call — content đã stream live. Firewall tái dựng các frame chỉ khi nó thực sự hành động (một deny hoặc một sanitize); một allow sạch chuyển tiếp đúng các byte của thượng nguồn bạn.

3. Một ví dụ cụ thể

Một chính sách response với một quy tắc deny trên *.delete (soạn nó trong trình chỉnh sửa quy tắc của console) và một request streaming mà mô hình của nó quyết định gọi cả db.querydb.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"}]}
Agent của bạn đọc văn bản assistant trong thời gian thực, rồi nhận chỉ db.querydb.delete đã được lắp ráp, đánh giá, deny, và không bao giờ phát ra. Cuộc gọi sống sót được re-index từ 0, và event firewall cho cuộc gọi bị deny đáp xuống events log của bạn với quy tắc đã kích hoạt.
Triển khai một chính sách response streaming dưới shadow mode trước. Trong shadow mode mọi verdict thực thi bị hạ cấp thành audit (lý do thêm tiền tố [shadow] would …) và tất cả frame tool-call đi qua — nên bạn có thể xác nhận chính sách khớp đúng cái bạn mong đợi trên traffic stream thật trước khi nó bắt đầu bỏ các cuộc gọi.

4. Block inbound đoản mạch trước khi stream bắt đầu

Vũ điệu giữ-frame chỉ dành cho bề mặt response — các cuộc gọi mà mô hình phát ra. Một deny inbound (một tool mà một agent quảng bá) kích hoạt trước cuộc gọi mô hình thượng nguồn, nên một request streaming vấp một quy tắc inbound không bao giờ mở một stream SSE cả: nó trả về một HTTP 400 thuần với mã lỗi firewall_blocked, đánh dấu skip-retry. Không frame, không cửa sổ giữ — block đáp xuống như bất kỳ lỗi không-streaming nào.

5. Guardrails trên cùng stream

Một phản hồi streaming có thể mang một chính sách output Guardrail một chính sách response firewall cùng lúc. Chúng tác động lên những thứ khác nhau — guardrails sàng lọc văn bản mà mô hình stream; firewall quản trị các cuộc gọi tool — và chúng kết hợp:
  • Block guardrail output (streaming): scanner output cắt stream ngay khi một quy tắc vấp, chuyển tiếp một chunk thay thế generic duy nhất — [Response blocked by content policy.] với finish_reason: "content_filter" — và dừng. Thông điệp cố tình generic (không có category quy tắc) nên một prober không thể liệt kê chính sách của bạn. Một lần giữ firewall đang bay khi điều này xảy ra bị bỏ đi, nên một cuộc gọi tool bị giữ lại không thể trượt ra sau block.
  • Mask guardrail output (streaming): che request trước khi mô hình là live; che in-band live của output được stream đang trong roadmap. Trên một stream một quy tắc mask ghi lại match nhưng hiện chuyển tiếp chunk gốc — soạn nó biết rằng việc che chưa được viết lại trên đường truyền. Block output được thực thi đầy đủ trên stream.
Trang này mô tả hình dạng SSE chat-completions của OpenAI. Cùng hợp đồng giữ-đánh giá-phát được nối theo từng format — Anthropic Messages native, Gemini, xAI, và stream OpenAI Responses mỗi cái mang nó trong hình dạng event riêng — nên hành vi quan-sát-được-bởi-khách-hàng giống hệt bất kể provider nào phục vụ request.

6. Điều này nghĩa là gì cho client của bạn

Một vài hệ quả thực tế của mô hình giữ-frame:
Một lượt mà cuộc gọi tool duy nhất bị deny đóng với finish_reason: "stop" thay vì "tool_calls" — với agent của bạn nó đọc là “mô hình chọn không gọi một tool.” Một lượt mà một số cuộc gọi sống sót đóng với "tool_calls", mang chỉ các cái sống sót.
Khi một thượng nguồn gói usage token lên cùng chunk cuối mà firewall đã giữ, gateway gắn lại nó vào frame tái dựng cuối — một client đã yêu cầu stream usage vẫn nhận được.
Nếu mô hình phát ra content một cuộc gọi tool trong cùng frame, content được khôi phục và phát ra lại ngay cả khi cuộc gọi tool bị bóc — block một cuộc gọi không bao giờ bỏ văn bản assistant của bạn.
Bạn không opt một stream vào bất kỳ điều nào trong số này. Gắn một chính sách vào key (hoặc đặt một mặc định workspace) và tiếp tục stream y như trước — việc thực thi ở gateway.

Đi đâu tiếp theo

Stage & bề mặt

inbound, response, mcp, egress — nơi mỗi quy tắc đánh giá.

Verdict

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

Sanitize đối số

Che secret khỏi đối số của một cuộc gọi tool — chỉ tầng đối số.

Shadow mode

Hạ cấp các verdict thực thi thành audit trong khi bạn đo tác động.
Để biết nơi cái này nằm trong đường request, xem cách OrcaRouter kiểm trađộ trễ đường thực thi. Để biết các mối đe dọa mà thực thi bề-mặt-response kiềm chế, xem cuộc gọi tool nguy hiểmrò rỉ dữ liệu. Để biết toàn bộ ngữ pháp quy tắc, xem tham chiếu quy tắc firewall.