跳轉到主要內容
防護欄防火牆 攔下一個請求時,OrcaRouter 會返回一個你的程式碼可以分支處理的型別化錯誤—— 而不是一個含糊的 400。三個安全代碼涵蓋你會遇到的情況:被篩查的 提示詞或回應、被拒絕的工具呼叫,以及保留待人工審批的工具呼叫。 本頁是這些代碼的參考——每個的使用情境、確切的 HTTP 狀態、它對你的成本,以及最重要的一條規則:重試 邏輯必須對它們做特殊處理。這三者全都標記為skip-retry;盲目地 重新執行同一個呼叫只會再次觸發同一個控制。
這些是強制執行代碼——閘道決定轉發你的 呼叫。它們有別於上游供應商錯誤(模型 429、情境 溢出)以及驗證失敗。關於某個特定請求為何被攔下,參見 為何被攔下?

1. LLM 安全錯誤代碼一覽

每次安全攔截都返回 HTTP 400,附帶 OpenAI 形狀的錯誤主體 (error.code 為下方的型別化字串)。在原生 Claude(/v1/messages) 路由上,相同的代碼以 Claude 錯誤形狀傳遞,因此 SDK 路由跨協定 是確定性的。
代碼攔下配額成本
guardrail_blocked命中 block 規則的提示詞或回應
firewall_blocked被拒絕的工具呼叫/公告無模型權杖
firewall_approval_pending保留供人工審查者審查的工具呼叫無模型權杖
error.code 分支,絕不要對訊息字串分支。訊息會指名具體的 防護欄、規則或工具,並且會變動;代碼才是穩定的契約。

2. guardrail_blocked — 被篩查的提示詞或回應

當帶有 block 動作的防護欄規則觸發時返回—— 一個拒絕清單上的關鍵字、一次正規表示式命中、一個你選擇 封鎖而非遮罩的 PII 或密鑰實體、一次 llm_judge 裁決,或一次失敗的情境接地檢查。 **HTTP 400。**訊息會指名觸發的防護欄和規則。
被封鎖的請求不消耗配額。輸入階段封鎖在計量之前 觸發,所以從不計費。輸出階段封鎖在模型回應之後 執行,所以閘道在返回錯誤之前退還預先消耗的配額。 無論哪種方式,被封鎖的呼叫你都不付費。
裁決是內容的屬性,而不是通道的屬性。重新執行 同一個提示詞——即使對著不同的模型——也會產生同樣的封鎖。 修正輸入(或政策),而不是重試。
mask 規則不會返回這個代碼。被遮罩的匹配項(例如 jane@acme.com[EMAIL])會就地修訂,呼叫 正常進行——你會得到 200,只是移除了敏感片段。只有 block 動作會浮現 guardrail_blocked。(flag 完全不改變 流量。)
{
  "error": {
    "type": "openai_error",
    "code": "guardrail_blocked",
    "message": "request blocked by guardrail \"pii-shield\": rule ssn (block)"
  }
}
關於這個代碼背後的規則類型、階段和動作,參見 防護欄。關於逐欄位的錯誤封套,參見 Webhook 與錯誤負載

3. firewall_blocked — 被拒絕的工具呼叫

防火牆對工具呼叫解析出 deny 裁決時返回—— 破壞性 shell 指令、SSRF 形狀的擷取、外向 目的地在拒絕清單上,或處於 block 模式的技能 拒絕如何浮現取決於強制執行表面

inbound / response / egress

HTTP 400error.code = firewall_blocked。主體攜帶 結構化的 error.metadatareason_code、風險 factorsrisk_score),所以 你可以解釋封鎖,而不只是看到它。

mcp surface

工具錯誤firewall deny: <reason>)返回,而非傳輸 失敗——所以模型看到拒絕,可以選另一個工具、詢問 使用者,或停止,而不是讓執行崩潰。
sanitize 不是封鎖。sanitize 裁決從工具呼叫引數中 修訂匹配到的子字串,並轉發清理後的呼叫——它從不 返回 firewall_blocked。(唯一例外:在 inbound 表面上,那裡 還沒有呼叫時引數,sanitize 升級為拒絕。)
{
  "error": {
    "type": "openai_error",
    "code": "firewall_blocked",
    "message": "tool \"shell.exec\" blocked by firewall: denied tool",
    "metadata": {
      "reason_code": "FW-TOOL-001",
      "risk_score": 92,
      "factors": ["denied_tool"]
    }
  }
}
就配額而言,inbound 封鎖在上游模型呼叫之前觸發,所以它消耗 無模型權杖。每一個裁決參見裁決詞彙表, 這個代碼防禦的威脅參見危險的工具呼叫

4. firewall_approval_pending — 保留供人工審查

在工具呼叫命中 pending_approval 裁決的那一刻返回。 人在環路(human-in-the-loop)閘門不能是阻塞式的內聯等待,所以閘道立即返回一個 保留回應,而不是長輪詢。 HTTP 400。錯誤攜帶審批 id,讓你的代理知道要解析 哪個保留。 這是唯一一個你應該以解析並重新提交來回應的代碼——而不是 把它當成終端失敗:
1

從保留錯誤中讀取審批 id

id 可從錯誤主體中恢復。先別重試呼叫—— 天真的重試只會再次保留。
2

等待決定

審查者從控制台解析它(Developer+),或你的審批 系統收到一個 HMAC 簽署的 webhook 回呼。你的代理輪詢 GET /api/v1/firewall/approvals/:id 取得狀態。
3

帶著審批權杖重新提交

一旦核准,重新發出原始呼叫,攜帶單次使用的 X-OrcaRouter-Firewall-Approval 標頭。閘道辨識該 id 並 讓那一個呼叫通過。
審批路由(/api/v1/firewall/approvals/*)在 防火牆閘道範圍化的金鑰上執行,而非你的控制台工作階段。完整迴圈參見 人工審批(HITL), 回呼簽名參見Webhook 負載

5. 為何三者都 skip-retry

標準 SDK 重試邏輯假設 400 可能在第二次嘗試時成功。這些 代碼打破了那個假設——封鎖是確定性的,所以盲目重試 浪費一次往返,並(對於保留的呼叫)默默地重新排入一次審批。
OrcaRouter 自己的內部重試/回退機制從不在另一個通道上重新嘗試 返回這些代碼之一的呼叫。在你的客戶端中比照辦理: 遇到安全代碼,停下並依裁決行動,不要迴圈。
  • guardrail_blocked → 修正輸入或放寬政策;向使用者 呈現拒絕。不要重試。
  • firewall_blocked → 該動作被禁止;讓代理選擇 不同的工具或請求協助。不要重試。
  • firewall_approval_pending → 解析保留,然後帶著審批標頭 重新提交一次(§4)。不帶標頭的重試會再次保留。

6. 配額與計費摘要

安全攔截從不為被攔下的工作單元向你計費。
代碼何時觸發計費結果
guardrail_blocked(input)模型呼叫之前從不計量
guardrail_blocked(output)模型回應之後退還預先消耗的配額
firewall_blocked(inbound)模型呼叫之前無模型權杖
firewall_approval_pending派發之前無模型權杖
防護欄的 llm_judgegrounding 規則確實會呼叫模型以得出其 裁決,那些評審權杖會作為單獨的評審子項計費——即使 裁決是封鎖。那是檢查的成本,而非被封鎖的請求本身的成本。

7. 相關參考

為何被攔下?

將單次封鎖追溯到產生它的確切規則、表面和原因。

裁決詞彙表

每個防火牆裁決——allow、audit、deny、sanitize、pending_approval、 cap_cost——以及各自發出什麼。

Webhook 與錯誤負載

完整的錯誤封套、error.metadata 欄位,以及審批回呼 簽名。

強制執行模式

影子、觀察與強制執行——裁決何時真正改變流量。
關於產生這些代碼的控制,參見防護欄防火牆;關於詞彙,參見 概念詞彙表