响应头与错误码
AISIX 会通过多种面向调用方的 API 格式返回响应。失败的 Chat Completions 请求、Anthropic 风格 Messages 请求和透传路由请求使用的错误信封并不完全相同。
本参考帮助你理解响应头、重试提示、状态码和错误字段。排查时应先确认请求的 URL 路径,再查看对应错误格式,然后判断失败来自调用方、网关侧还是上游服务提供方。
错误响应格式
请根据请求 的 URL 路径识别适用的错误信封。
| 响应来源 | 错误信封 | 阅读 |
|---|---|---|
OpenAI 兼容代理路由,例如 /v1/chat/completions、/v1/completions、/v1/embeddings、/v1/responses、音频、图像和 rerank | {"error": {...}} | OpenAI 风格代理错误 |
Anthropic 风格代理路由,例如 /v1/messages 和 /v1/messages/count_tokens | {"type":"error","error": {...}} | Anthropic 风格代理错误 |
/mcp 和 /mcp/{server} 下的 MCP 路由 | JSON-RPC 错误信封 | MCP 错误 |
/a2a/{agent} 下的 A2A 调用 | 上游 JSON-RPC 响应;转发前失败使用 HTTP 错误;上游分发失败使用 JSON-RPC 错误 | A2A 错误 |
/a2a/{agent}/.well-known/agent-card.json 下的 A2A Agent Card | 成功时使用 Agent Card JSON;网关或上游失败时使用 HTTP 错误响应 | A2A 错误 |
| 已配置的透传路由 | 转发上游状态码和响应体;AISIX 生成的失败使用 {"error": {...}} | 透传错误 |
代理响应头
运行时响应头会因端点而异,不应假设每个响应头都适用于所有 /v1/* 路由。
| 响应 头 | 使用场景 |
|---|---|
x-aisix-call-id | 出现在 Chat Completions 响应中,用于关联一次网关调用。 |
x-aisix-request-id | 出现在每个代理响应中,用于将响应与该请求产生的任何访问日志和用量事件关联起来。一些 MCP 失败发生在用量核算之前;请参阅用量事件。该请求头默认在请求上同样被接受:发送你自己的 ID,AISIX 会全程使用该值而不再自行生成。从哪些请求头读取 ID 可配置,因此具体部署可以扩展或关闭该行为。参见复用自己的请求 ID。 |
x-aisix-served-by | 出现在成功的 Chat Completions 路由响应中,用于识别实际处理请求的目标模型。 |
x-aisix-cache | 出现在缓存策略覆盖的聊天请求上:hit、miss 或 bypass。只有 Cache-Control: no-cache 会产生 bypass;no-store 仍会执行缓存查询,因此报告 hit 或 miss。用于确认响应是否由网关缓存返回。 |
x-aisix-cache-layer | 出现在缓存命中时:完全相同请求的匹配为 exact,向量相似度匹配为 semantic。用于区分命中来自哪个匹配层。 |
x-aisix-cache-similarity | 出现在语义缓存命中时。匹配条目的余弦相似度,取值 0–1。用于校准策略的相似度阈值。 |
x-ratelimit-* | 按维度拆分的一组响应头,名称以 -requests、-tokens、-concurrent 结尾。当调用方 API Key 配置了限流时,会出现在成功的 Chat Completions 响应中,用于查看请求、Token 和并发限制状态。 |
X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-ResetX-RateLimit-Scope | 仅出现在 AISIX 自身限流器产生的 429 上,用于判断触发的是哪条限制以及何时可以重试。参见限流拒绝响应头。 |
Retry-After | 当网关能够给出重试提示时,会出现在限流、AISIX Cloud 预算和所有候选不可用的拒绝响应中;当 AISIX 能解析上游 429 的重试提示时,也会透出该响应头。调用方可据此判断重试时间。 |
限流拒绝响应头
当 AISIX 自身的限流器拒绝一个请求时,返回的 429 会描述拒绝该请求的那一条限制,OpenAI 风格和 Anthropic 风格两种错误信封都是如此。
| 响应头 | 取值 |
|---|---|
X-RateLimit-Limit | 拒绝该请求的那条限制的配置上限。 |
X-RateLimit-Remaining | 该上限之下的剩余额度。触发拒绝时为 0。 |
X-RateLimit-Reset | 该限制重新放行请求所需的秒数。 |
Retry-After | 与上一行相同的秒数,客户端可以按自己已支持的那个响应头退避。 |
X-RateLimit-Scope | AISIX 扩展,标明是哪条限制拒绝了请求:rps、rpm、rph、rpd、tpm、tpd 或 concurrency。 |
X-RateLimit-Reset 是以秒为单位的时长,不是时间戳,因此客户端不需要与网关对时。对于有窗口的限制,它向当前固定窗口的结束时刻倒数。它永远不会为 0,最小值是 1。
一个调用方 API Key、一个模型或一条限流策略都可以同时配置多条限制。对于某一个请求,只有其中一条会拒绝它——AISIX 最先发现耗尽的那一条——响应头描述的就是这一条。X-RateLimit-Scope 让这些数字不再含糊,因为各维度的单位并不相同:x-ratelimit-limit: 1000 在 rpm 下是 1000 次请求,在 tpm 下是 1000 个 Token,在 concurrency 下是 1000 个在途请求。
有两种情况不适用上面的读法:
- 路由模型或语义路由。 分发会跳过每一个超出自身限制的目标并尝试下一个;当所有目标都用尽时,响应头描述的是最后一个拒绝的目标,那是配置在该目标上的限制,而不是配置在请求所寻址的别名上的。应当把它理解为"请求为什么无法被投递",而不是调用方自身的配额。
- 合议模型。 合议成员或评审模型超出自身限制时,请求会以
429失败,但该响应不携带这些响应头,也不携带Retry-After。
并发拒绝是唯一没有固定窗口的情况。并发槽位在某个在途请求结束时释放,而网关无法预测这个时刻,因此 X-RateLimit-Reset 和 Retry-After 都固定返回 60。
一个原始的拒绝响应如下:
HTTP/1.1 429 Too Many Requests
content-type: application/json
retry-after: 43
x-ratelimit-limit: 100
x-ratelimit-remaining: 0
x-ratelimit-reset: 43
x-ratelimit-scope: rpm
x-aisix-request-id: 018f3c1f-...
{"error":{"message":"request limit exceeded (requests)","type":"rate_limit_exceeded"}}
HTTP 响应头名称不区分大小写,AISIX 在网络上以小写形式写出。读取 X-RateLimit-Limit 和读取 x-ratelimit-limit 的客户端都能匹配到。
X-RateLimit-* 系列响应头只在 AISIX 自身拒绝请求时出现。以下情况不会出现:
- 成功响应。
200响应携带的是按维度拆分的x-ratelimit-*系列:x-ratelimit-limit-requests、x-ratelimit-limit-tokens、x-ratelimit-limit-concurrent以及各自对应的remaining和reset。这一系列只报告调用方 API Key 自身的rpm、tpm和concurrency状态,不包含模型限制、限流策略,也不包含按秒、按小时、按天的窗口。 - 上游返回的
429。 AISIX 能解析出服务提供方的Retry-After时会透传,但服务提供方的配额状态并非 AISIX 所知,因此不会给出自己的这几个值。 - AISIX Cloud 预算拒绝。 预算限制的是消费金额,而不是请求数或 Token 数。它同样返回
429,在错误体中带上结构化的预算字段;只有当控制面给出了重置时间时才携带Retry-After。
因此,X-RateLimit-* 是否出现,就是调用方判断"拒绝来自 AISIX 自身限流器"的依据。仅凭 Retry-After 无法判断——如上面两种情况所示,其他拒绝也会带上它。
代理状态码
当错误信封包含错误类型时,应优先查看它。状态码给出大类,错误类型通常能标识更精确的网关状态。
| 状态码 | 含义 |
|---|---|
400 | 请求无效。 |
401 | 调用方认证缺失或无效。 |
403 | 调用方已通过身份认证,但已配置的访问控制不允许该请求。 |
404 | 请求的资源未找到。网关生成的示例包括未知 模型别名、MCP 服务器或 A2A Agent。上游服务也可能返回 404;AISIX 会保留上游 4xx 状态码。 |
413 | 请求体超过代理请求体大小限制。 |
422 | 内容被安全护栏拦截,可能是策略命中,也可能是关闭式失败的安全护栏无法评估该内容。参见安全护栏拒绝。 |
429 | 请求触发限流或 AISIX Cloud 预算拒绝。 |
501 | 解析出的服务提供方适配器未实现该端点。 |
502 | 上游服务提供方返回服务端失败,或适配器将上游失败映射为代理错误格式。 |
503 | 身份认证依赖项或服务提供方适配器不可用,或所有路由候选都被运行时状态过滤。 |
504 | 上游请求超时。 |
OpenAI 风格代理错误
AISIX 的 OpenAI 兼容代理错误使用如下信封:
{
"error": {
"message": "...",
"type": "invalid_request_error"
}
}
当 AISIX 没有对应值时,会省略 param 和 code 字段。AISIX Cloud 预算拒绝会在 error 对象中包含结构化预算字段,例如 scope、limit_usd、spent_usd、period 和 retry_after_seconds。
常见的 AISIX error.type 取值如下:
| 错误类型 | 常见状态码 | 含义 |
|---|---|---|
invalid_api_key | 401 | 调用方认证缺失或无效。无效、已过期或未映射的 JWT 也使用此类型;具体情况请检查 error.code。 |
permission_denied | 403 | 调用方 API Key 无权使用请求的模型、调用方客户端 IP 不在模型的 allowed_cidrs 范围内,或已验证的 JWT 不满足必需 Scope 或 Claim。 |
model_not_found | 404 | 请求的模型别名未配置。 |
invalid_request_error | 400 或 413 | 请求体或端点使用方式无效。过大的 OpenAI 风格请求会返回该错误类型和 413 状态码。 |
provider_unavailable | 503 | 选中的上游服务提供方适配器无法完成请求。 |
all_candidates_unavailable | 503 | 所有路由候选都被过滤或不可用。 |
api_error | 503 | AISIX 无法完成内部依赖操作,例如获取用于 JWT 身份认证的签名密钥。 |
content_filter | 422 | 请求或响应被安全护栏拦截。安全护栏无法评估内容时 error.code 为 guardrail_unavailable;策略命中时该字段不存在。参见安全护栏拒绝。 |
billing_error | 429 | AISIX Cloud 预算执行拒绝了请求,原因是具有阻断动作的预算已超限,或预算的故障处理策略在控制面不可用时拒绝了请求。 |
rate_limit_exceeded | 429 | 请求超过已配置的限流规则。 |
not_implemented | 501 | 解析出的服务提供方适配器未实现该端点。 |
timeout | 504 | 上游请求超时。 |
upstream_error | 不固定,上游服务端失败通常为 502 | 上游服务提供方返回错误,AISIX 将其渲染为代理错误格式。 |
身份认证错误码
OpenAI 风格代理错误可能包含以下用于调用方身份认证的稳定 error.code 值。Anthropic 风格代理错误会省略 code;请改用其 HTTP 状态码和按状态映射的 error.type。
这并不是 error.code 的全部取值。部分 OpenAI 风格路由会在安全护栏无法评估内容而拒绝请求时携带 guardrail_unavailable;具体接口差异请参见安全护栏拒绝。来源 IP 拒绝携带 ip_restricted,预算拒绝携带 budget_exceeded。
error.code | 状态码 | 含义 |
|---|---|---|
api_key_expired | 401 | 调用方 API Key 的到期时间已过。 |
api_key_disabled | 401 | 调用方 API Key 已被管理员禁用。 |
jwt_invalid | 401 | JWT 格式错误,或未通过签发者、签名、签名算法、受众、必需 Claim 或生效时间验证。 |
jwt_expired | 401 | JWT 的 exp 到期时间已过。 |
jwt_claims_rejected | 403 | JWT 有效,但不满足信任提供方要求的 Scope 或绑定 Claim。 |
jwt_identity_unmapped | 401 | 缺少已配置的身份 Claim,或该 Claim 未映射到绑定此 OIDC 提供方的调用方 API Key。 |
jwks_unavailable | 503 | AISIX 无法解析或获取信任提供方的签名密钥。请检查 OIDC Discovery 或 JWKS 端点,然后重试。 |
有关 JWT 信任提供方配置和拒绝行为,请参阅 JWT 身份认证。
上游服务提供方错误
OpenAI 风格路由会通过同一错误信封渲染上游服务提供方失败,但 AISIX 不一定原样返回上游响应。
上游 4xx 响应会保留客户端可见的 HTTP 类别。原生 OpenAI 上游错误可以保留 OpenAI 风格字段。跨服务提供方上游错误会使用 upstream_error,并可能包含更具体的 error.code,例如限流、权限或模型未找到代码。
上游 5xx 响应通常会返回 502。AISIX 不暴露上游 5xx 响应体,因为其中可能包含服务提供方账号、基础设施或私有诊断信息。
Anthropic 风格代理错误
POST /v1/messages 和 POST /v1/messages/count_tokens 使用 Anthropic 风格错误信封:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "..."
}
}
Anthropic 信封会省略 OpenAI 信封可能携带的 param 和 code 字段。因此这些路由上的安全护栏因无法评估内容而拒绝请求时,不会带上部分 OpenAI 风格路由会携带的 guardrail_unavailable;失败标记仍然会写在消息里。参见安全护栏拒绝。
嵌套的 error.type 遵循与 Anthropic SDK 兼容的状态映射:
| 状态码 | Anthropic error.type |
|---|---|
400 或 422 | invalid_request_error |
401 | authentication_error |
403 | permission_error |
404 | not_found_error |
408 | timeout_error |
413 | request_too_large |
429 | rate_limit_error |
503 | overloaded_error |
| 其它状态码 | api_error |
AISIX 保留 408 映射以兼容 Anthropic SDK。网关侧产生的超时通常会通过服务提供方错误处理暴露,而不是作为原生 408 响应返回。
示例参见 Anthropic 风格 Messages API。
MCP 错误
ANY /mcp 和 ANY /mcp/{server} 使用 MCP Streamable HTTP 和 JSON-RPC 响应结构。身份认证失败或请求体过大等错误仍可能在 MCP 处理程序运行前使用 401 或 413 等 HTTP 状态码。
当安全护栏阻断工具调用或工具结果时,AISIX 会返回 HTTP 200,并在响应体中返回标记了 isError 的工具结果。MCP 把 JSON-RPC 协议错误保留给不合法的请求;策略拒绝属于工具执行失败,因此调用方 Agent 会把它当作工具输出读取并据此调整:
{
"jsonrpc": "2.0",
"id": 42,
"result": {
"content": [{ "type": "text", "text": "tool call blocked by content policy (guardrail 'block-secrets')" }],
"isError": true
}
}
这与 OpenAI 兼容路由不同,后者的安全护栏拦截使用 HTTP 422 和 OpenAI 风格错误信封。
被拒绝或不存在的工具则仍然是协议错误——HTTP 200 且 error.code 为 -32602——因为此时请求本身指定了调用方无权调用的对象。
消息措辞和失败标记词表参见安全护栏拒绝。
A2A 错误
POST /a2a/{agent} 会原样返回成功的上游 JSON-RPC 响应。网关识别 Agent 并进入 A2A 分发后,如果上游连接失败或返回非成功响应,则会返回 HTTP 502 和 JSON-RPC 错误信封:
{
"jsonrpc": "2.0",
"id": 42,
"error": {
"code": -32000,
"message": "..."
}
}
安全护栏拒绝使用同一个 JSON-RPC 错误信封,HTTP 状态码为 422;其 code 是 JSON-RPC 的 -32000,不是网关错误码。参见安全护栏拒绝。
部分失败发生在 AISIX 转发 A2A 请求之前,因此不使用 JSON-RPC 错误。调用方身份认证缺失或无效时返回 401;调用方 Key 无权访问已注册 Agent 时返回 403;Agent 未知或已禁用时返回 404。限流或 AISIX Cloud 预算拒绝返回 429。
Agent Card 发现使用普通 HTTP 状态码,而不是 JSON-RPC 信封。调用方身份认证缺失或无效时返回 401,Agent 访问被拒绝时返回 403,Agent 未知或已禁用时返回 404。如果网关无法从上游 Agent 获取可用的 Agent Card,则返回 502。如果网关无法从请求中确定自身的对外地址,则返回 500,而不是返回一份仍然公布上游 Agent 地址的 Agent Card。
流式方法(message/stream、tasks/resubscribe)只在流建立之前遵循上述规则。响应一旦开始,状态行已经发出,之后的上游失败便无法再变成 502:网关会把 JSON-RPC 错误信封作为流的最后一个事件转发,并在用量事件中记录该失败。如果上游对流式调用返回的是普通 JSON-RPC 响应而非流,该响应会作为单个事件转发。
透传错误
当 AISIX 收到上游 HTTP 响应且没有网关策略替换该响应时,命中的透传路由会原样转发上游的状态码和响应体。
AISIX 生成的失败会使用 OpenAI 风格代理错误信封,包括调用方身份认证拒绝、缺少 allowed_routes 授权或来源不在路由 source_cidrs 内(403,来源拒绝携带 error.code: ip_restricted)、护栏阻断,以及上游传输、超时或响应解码失败。护栏阻断是一次 422,流式响应上则是一个终止性 SSE error 事件。参见安全护栏拒绝。
未被任何显式路由认领的 /passthrough/* 路径会按普通流程返回响应体为空的 404。创建一条透传路由即可认领该路径。
安全护栏拒绝
安全护栏停止流量有两种原因,两者对调用方的含义并不相同。
策略命中指安全护栏读到了内容并拒绝了它。关闭式失败的可用性故障指安全护栏根本无法评估内容,而它的配置规定「检查不了的就不放行」。
两者都属于安全护栏拒绝。两者都会遵循所请求端点自身的错误约定,也都会被记为安全护栏阻断。
标识第二种情况的有两样东西,很容易混淆:
error.code在携带它的那些接口面上是一个固定取值,而不是逐类故障的取值。在 OpenAI 风格信封上它是guardrail_unavailable,只在安全护栏无法评估时出现,策略命中时该字段不存在。有两个接口面不遵循这条规则:桥接的/v1/responses流始终发送content_filter,/v1/realtime始终发送content_filtered——无论是策略命中还是可用性故障都一样。- 失败标记(
lakera_timeout、unscannable_body等)来自由代码定义、取值范围有限的集合,写在拒绝消息文本的括号中。消息所在字段取决于接口协议,例如 OpenAI、Anthropic 和 A2A 错误的error.message、桥接 Responses 流的顶层message,或 MCP 工具结果的result.content[].text。标记不是error.code的取值,也没有专门的信封字段承载它。
消息按固定形态构造:
<side> rejected: guardrail '<name>' could not evaluate it (<tag>)
<side> rejected: a guardrail could not evaluate it (<tag>)
当无法指名某一条具体的安全护栏时使用第二种形态。网关代表整条护栏链、而不是基于某个成员的判定发起的拒绝,都属于这种情况。<side> 为 request 或 response;在 /mcp 上则是 tool call 或 tool result。
策略命中使用同样的形态,但不带标记:
<side> blocked by content policy (guardrail '<name>')
<side> blocked by content policy
在 OpenAI 风格路由上,error.code 是否存在本身就是信号,因此按它做分支。在桥接的 /v1/responses 流和 /v1/realtime 上,code 是常量,无法区分策略命中与可用性故障——只有消息括号里的标记能区分。请把标记词表当作一个已知取值集合,而不是字符串中的固定位置。
各接口面的拒绝信封
每个接口面都保留自己协议的错误形态,因此 guardrail_unavailable 并不会送达所有调用方。Anthropic 风格路由根本没有 code 字段,/mcp 以工具结果在带内应答,/a2a 以 JSON-RPC 应答。
| 接口面 | HTTP | 响应体 | code |
|---|---|---|---|
OpenAI 兼容路由,非流式——包括 /v1/chat/completions、/v1/embeddings、/v1/audio/transcriptions、/v1/audio/translations,以及 Batch 和 Fine-tuning 路由 | 422 | {"error":{"message":...,"type":"content_filter","code":"guardrail_unavailable"}} | guardrail_unavailable |
/v1/chat/completions,流式 | 200,随后一个终止性 SSE error 事件 | {"error":{"message":...,"type":"content_filter"}} | 无 |
/v1/responses,上游原生提供 Responses API 时 | 422 | 同上述非流式 OpenAI 信封 | guardrail_unavailable |
/v1/responses,AISIX 为不原生提供 Responses API 的服务提供方做桥接时 | 200,随后一个终止性 SSE error 事件 | 扁平结构,与 Responses 错误事件一致:{"type":"error","code":"content_filter","message":...,"param":null,"sequence_number":N} | content_filter |
/v1/messages 和 /v1/messages/count_tokens,非流式 | 422 | {"type":"error","error":{"type":"invalid_request_error","message":...}} | Anthropic 信封没有 code 字段 |
/v1/messages,流式 | 200,随后一个终止性 SSE error 事件 | {"type":"error","error":{"type":"invalid_request_error","message":...}} | Anthropic 信封没有 code 字段 |
| 透传路由,非流式 | 422 | 同上述非流式 OpenAI 信封 | guardrail_unavailable |
| 透传路由,流式 | 200,随后一个终止性 SSE error 事件 | {"error":{"type":"content_filter","message":...}} | 无 |
/mcp 和 /mcp/{server} | 200 | 一个标记了 isError 的工具结果,文本即拒绝消息。参见 MCP 错误。 | 不适用 |
/a2a/{agent} | 422 | {"jsonrpc":"2.0","id":...,"error":{"code":-32000,"message":...}} | code 是 JSON-RPC 的 -32000,不是网关错误码 |
/v1/realtime | 没有状态码——会话已经建立 | 一个 WebSocket 文本帧 {"type":"error","error":{"type":"invalid_request_error","code":"content_filtered","message":...}},随后是关闭帧,关闭码为 1011、原因为 content policy | content_filtered |
有两点需要提前规划。Anthropic 风格路由上的 SDK 无法基于 error.code 分支,因为该信封没有这个字段——请改用 HTTP 状态码和消息。以及,在大多数流式接口面上,拒绝都发生在一个已经返回 200 的响应上,因此只检查状态码的客户端看到的是一次成功但被截断的流。
网关发起的失败标记
以下三个来自代理自身、代表整条护栏链发起,此时没有任何安全护栏产生可携带标记的判定,因此它们不会指名某条安全护栏。
| 标记 | 方向 | 出现位置 |
|---|---|---|
unscannable_body | 请求侧和响应侧 | 部分内容无法按送达形态完成评估。请求侧可能是扫描器无法解析的 /v1/messages 或 /v1/messages/count_tokens 正文。响应侧可能是被保留的流最终没有任何可扫描内容、无法解析的 /mcp 工具结果,或 AISIX 无法在不替换非法字节序列的情况下解码的非流式音频转录或翻译响应。参见 AISIX 无法扫描的帧和 AISIX 解码不出来的转录文本。 |
output_buffer_exceeded | 仅响应侧 | 流式响应在被扫描之前就超出了保留缓冲区上限。出现在 /v1/chat/completions、/v1/messages、/v1/responses 和透传路由上。这里只有 /v1/chat/completions 和透传路由会遵循 on_buffer_exceeded;/v1/messages 和 /v1/responses 在溢出时一律关闭式失败。 |
mask_writeback_failed | 请求侧和响应侧 | 掩码判定无法写回正文,因此内容被拒绝,而不是不经掩码就转发。仅出现在 /mcp 上,tools/call 参数和工具结果两侧都有。 |
对于无法读取的 Anthropic 请求、MCP 工具结果或纯文本音频转录,只有当至少一条作用域内的安全护栏读取该交换方向且在该方向采用 fail-closed 时,unscannable_body 才会触发拒绝。如果该方向的所有读取器都 fail-open,AISIX 会中继内容,并把 unscannable_body 记录到 guardrail_bypassed_reason;对于音频,AISIX 仍会扫描尽力解码得到的文本,因此只有被替换的字节序列逃过检查。安全护栏链若不读取该方向,则既不拒绝,也不记录绕过。被保留的流最终没有可扫描内容则不同:一旦执行型输出安全护栏已经扣住该流,AISIX 就会拒绝,不受 fail_open 影响。
output_buffer_exceeded 通常不是一次状态码拒绝。在大多数路由上流都已经返回了 200,因此拒绝以终止性 SSE error 事件送达,被扣住的帧则被丢弃。
唯一的例外是 /v1/responses 且上游原生提供 Responses API:此时尚未交付任何内容,请求会以 422 被拒绝。当 AISIX 为不提供该 API 的服务提供方做桥接时,同样的溢出则以终止性 SSE error 事件送达。
各安全护栏类型发起的失败标记
每种远程安全护栏都会把自己后端的故障归入一个有限集合。无论该条目怎么配置,用的都是同一个标记。fail-open 时它是 Bypass 的原因,fail-closed 时它是拒绝的标记,因此同一次故障两种配置读起来是一样的。
| 安全护栏类型 | 失败标记 |
|---|---|
lakera | lakera_timeout、lakera_throttled、lakera_5xx、lakera_too_large、lakera_config_error |
presidio | presidio_timeout、presidio_throttled、presidio_5xx、presidio_too_large、presidio_config_error |
openai_moderation | openai_moderation_timeout、openai_moderation_throttled、openai_moderation_5xx、openai_moderation_too_large、openai_moderation_config_error |
azure_content_safety 和 azure_content_safety_text_moderation | azure_cs_timeout、azure_cs_throttled、azure_cs_5xx、azure_cs_config_error |
bedrock | bedrock_timeout、bedrock_throttled、bedrock_too_large、bedrock_5xx |
aliyun_text_moderation 和 aliyun_ai_guardrail | aliyun_timeout、aliyun_throttled、aliyun_5xx、aliyun_bad_response、aliyun_config_error |
custom | custom_timeout、custom_script_error、custom_engine_error、custom_no_verdict、custom_bad_verdict、custom_unknown_action |
semantic | semantic_embed_unresolved、semantic_embed_timeout、semantic_embed_upstream |
两种 Azure 类型共用一套词表,因为它们调用的是同一个服务;两种阿里云类型同理。请把标记理解为在指认后端,而不是在指认某条安全护栏条目——后者请看消息中的安全护栏名称。
标记的含义与名称一致。_timeout 是配置的等待时间耗尽,_throttled 是后端返回 429。_5xx 是服务端或传输层故障。_config_error 是非 429 的 4xx,例如凭证被拒或端点填错。_too_large 是后端因体积拒绝了载荷。
aliyun_bad_response 指 2xx 但响应体不是文档描述的结构。它与 aliyun_5xx 分开,因为两者的修复方式不同。
custom_* 一组区分脚本超时、抛异常、引擎无法启动。它同时覆盖脚本什么都没返回、返回的结构不是判定,以及返回了词表之外的动作。
内置的 keyword 和 pii 安全护栏在网关内部运行、不调用任何后端,因此没有失败标记。这两者的阻断完全不 携带 error.code。
你还会在哪里遇到这些标记
各安全护栏类型自身的标记会出现在四个面向运维的位置,因此从调用方错误消息里读到的标记可以直接拿去检索:
- 用量记录中的审计命中。 关闭式失败的拒绝记为
action=blocked_unavailable,标记写入error_type。普通策略命中记为action=blocked,error_type为空。监控模式下评估失败的观察会把标记记在它的would_block摘要中。 aisix_guardrail_latency_secondsPrometheus 直方图。 关闭式失败的blocked、bypassed,以及监控模式下失败的would_block,其error_type标签都会携带该标记。普通策略命中使用none。result标签在关闭式失败的拒绝上仍然是blocked,不会另起取值,因此既有的result="blocked"告警仍会统计到它。参见指标参考。aisix_guardrail_bypasses_totalPrometheus 计数器。 失败开放的执行会在reason标签下使用同一个标记递增该计数器。它统计的是绕过事件而不是请求,并且没有安全护栏、类型或阶段标签。- 用量事件上的
guardrail_bypassed_reason。 安全护栏 fail-open 时不会拒绝任何内容,调用方也 收不到任何消息,但同一个标记会记录在这里。每条代理路由的用量事件都会携带该字段;追溯批处理归因事件除外,因为这些事件没有解析安全护栏链。
网关自己发起的那三个标记是例外。它们不是安全护栏执行,因此不会出现在审计命中或安全护栏执行直方图的 error_type 中。失败关闭的拒绝会记录 guardrail_blocked,并在调用方消息和网关日志中写入该标记。当适用的失败开放策略放行 unscannable_body 时,用量事件会把该标记记录到 guardrail_bypassed_reason。aisix_guardrail_bypasses_total 计数器仍会递增,但由于没有安全护栏真正执行,因此不会发出延迟直方图观测值。