result.blocked = true)。-、_(必填)。X-API-Key)与密钥值。Authorization、密钥值填写为 Bearer <token 值>。result.blocked(必填)。true 或 BLOCK(必填)。result.sanitized_text),网关进行输出改写。放行时,网关会取该字段的完整取值整体替换原始检测文本(如打码后的文本);关闭开关则原样透传。内容改写仅在输出方向(响应送审)生效,需与检测方向 输入 + 输出 配合使用;输入方向不支持内容改写。若外部服务在输入阶段返回改写内容,或策略未开启内容改写时返回改写内容,网关将会忽略此时的替换字段,继续根据命中字段判定。角色 | 职责 |
AI 网关(调用方) | 封装统一送审信封、发起送审请求、解析审核结论并按策略执行放行 / 阻断 / 改写 |
外部安全服务(审核服务) | 接收送审请求、按自身检测能力完成内容判定、返回 JSON 格式的审核结论 |
术语 | 定义 |
送审(Audit Request) | 网关向审核服务发起的一次检测调用 |
审核单元(Audit Unit) | 一次送审所对应的检测对象,由 audit_id 唯一标识。可以是完整的请求/响应 Body、一个 SSE Event Batch,或一次超大 Body 分段传输的完整内容 |
审核结论(Decision) | 审核服务针对某个审核单元返回的判定结果:放行(allow)、阻断(block)或替换(replace) |
内联信封(Inline Envelope) | Body 直接内嵌于 content.body 的送审形态,与"分段传输"相对 |
Event Batch | 流式响应场景下,由一个或多个完整 SSE Event 组成的审核单元 |
传输(Transfer) | 超大 Body 场景下,由 begin、chunk、end 三个阶段构成的完整传输过程 |
protocol 字段声明其类型;审核服务可据此选择专用解析器,也可直接对 content.body 执行通用检测。项目 | 约定 |
请求方法 | POST |
请求 Content-Type | 内联信封送审,以及超大 Body 的 Begin、End 阶段为 application/json;超大 Body 的 Chunk 阶段为 application/octet-stream |
响应 Content-Type | 审核服务的响应必须为 application/json |
协议版本请求头 | X-CNGW-Audit-Schema-Version: 2.0,网关在所有送审请求中携带 |
鉴权 | 双方约定一个固定 Header,Header 名称与取值由网关侧配置,对应控制台的 API Key(Header) |
状态码语义 | 正常审核结论(包括 block)必须返回 HTTP 2xx;返回非 2xx 表示审核服务调用失败(而非内容违规),网关按策略配置的检测失败策略处理 |
decision = "block",自定义字段映射模式下为命中判定字段取命中值。{"schema_version": "2.0","audit_id": "7c96777a-5f8f-4e58-9b16-2fdc0de3a7ba","direction": "request","protocol": {"category": "mcp","name": "mcp-streamable-http","version": "2025-03-26"},"http": {"method": "POST","path": "/mcp","headers": {"content-type": ["application/json"],"accept": ["application/json, text/event-stream"],"mcp-protocol-version": ["2025-03-26"]}},"streaming": {"mode": "possible","format": "sse","unit": "full_body"},"content": {"media_type": "application/json","encoding": "json","body": {"jsonrpc": "2.0","id": 17,"method": "tools/call","params": {"name": "knowledge_search","arguments": { "query": "请介绍一下这个产品" }}}},"gateway_context": {"request_id": "req-123","gateway_id": "gateway-abc123","route_id": "route-456","service_id": "service-789"}}
字段 | 类型 | 约束 | 说明 |
schema_version | string | 必选 | 固定为 2.0 |
audit_id | string | 必选 | 当前审核单元的唯一 ID;标准响应模式下必须原样回显,自定义字段映射模式不要求回显 |
direction | string | 必选 | request(请求送审)或 response(响应送审) |
protocol | object | 必选 | 原始业务协议的识别结果,参考原始业务协议标识 |
http | object | 必选 | 原始 HTTP 请求或响应的元信息 |
streaming | object | 必选 | 请求方向的流式意图,或响应方向的实际流式审核状态 |
content | object | 必选 | 原始协议 Body(内联信封)或传输描述(分段传输) |
gateway_context | object | 可选 | 网关依据当前请求上下文自动补充,不由调用方填写 |
字段 | 类型 | 说明 |
method | string | 原始请求方法,仅请求送审携带 |
path | string | 原始请求路径,不含 Query String,仅请求送审携带 |
status_code | int | 原始响应状态码,仅响应送审携带 |
headers | object | Header 名统一转为小写,取值统一为字符串数组 |
query | string | 原始 Query String,默认不携带,仅网关显式开启 Query 透传后出现 |
method、path、headers;普通响应送审携带 status_code、headers。content-type、accept、mcp-protocol-version、a2a-version,其余 Header 由网关白名单配置决定。authorization、cookie、x-api-key、mcp-session-id 等)不会随送审请求发出。content.encoding 解析 content.body,不应假设 Body 一定是 JSON 对象。字段 | 类型 | 说明 |
media_type | string | 原始媒体类型;JSON 类型为原始 Content-Type 去除参数并转为小写 |
encoding | string | Body 的编码方式: json / text / base64 |
body | mixed | 按 encoding 编码后的内容;分段传输(Begin 阶段)时不出现 |
transfer | object | 传输描述,仅超大 Body 分段传输的 Begin 阶段出现 |
原始 Body | encoding | body 取值 |
JSON | json | 完整 JSON 值,可能是对象、数组或标量 |
文本 | text | 原始字符串(原始 text/* 类型) |
二进制 | base64 | Base64 字符串(媒体类型保持原始值) |
空 Body | base64 | 空字符串 "";SSE 空终止单元使用 text 编码,见 流结束语义 |
GET /sse 仅用于建立响应流,请求阶段直接跳过,后续仍可进入流式响应审核。字段 | 类型 | 约束 | 说明 |
request_id | string | 可选 | 请求 ID,可能继承客户端传入值 |
trace_id | string | 可选 | 链路追踪 ID,可能继承客户端传入值 |
gateway_id | string | 可选 | 网关实例 ID |
route_id | string | 可选 | 命中的路由 ID |
service_id | string | 可选 | 命中的服务 ID |
workspace_id | string | 可选 | 工作空间 ID |
consumer_id | string | 可选 | 消费者 ID,鉴权成功后填充 |
tenant_id | string | 可选 | 预留字段,无稳定数据来源时不输出 |
gateway_id、route_id、service_id、workspace_id 及鉴权成功后的 consumer_id 来自网关运行上下文,可作为稳定的治理维度。request_id、trace_id 可能继承客户端传入值,可用于日志关联,不应单独作为可信身份依据。mode | 适用方向 | 说明 |
none | 请求/响应 | 原始请求未表达流式返回意图,或响应为非流式 |
requested | 请求 | 原始请求明确要求流式返回 |
possible | 请求 | 原始协议可能返回 SSE,例如 MCP Streamable HTTP |
active | 响应 | 流式响应送审进行中,仅出现在 Event Batch 送审中 |
mode 为 requested 或 possible 时,审核单元为 unit = "full_body";mode = "none" 时,format 与 unit 可能省略。mode = "none";流式响应的字段规则见流式响应送审。protocol 字段声明 content.body 应遵循哪种业务协议语义进行解析。字段 | 类型 | 约束 | 说明 |
category | string | 必选 | 协议大类: llm / dify / a2a / mcp / agent |
name | string | 必选 | 协议名称,见下表 |
version | string | 可选 | 协议版本,来源见下方说明 |
operation | string | 可选 | 操作标识,当前仅 LLM 类协议输出 |
场景 | protocol.category | protocol.name | 识别依据 |
OpenAI Chat Completions | llm | openai-chat-completions | 路径 /v1/chat/completions |
OpenAI Responses | llm | openai-responses | 路径 /v1/responses |
Anthropic Messages | llm | anthropic-messages | 路径 /v1/messages |
A2A JSON-RPC | a2a | a2a-jsonrpc | JSON-RPC 调用方式 |
A2A HTTP+JSON | a2a | a2a-http-json | application/a2a+json、:send 或 :stream |
MCP Streamable HTTP | mcp | mcp-streamable-http | MCP Streamable HTTP |
protocol.name 选择内部解析器,也可直接对完整 content.body 执行通用检测。protocol.version 为 v1,protocol.operation 分别为 chat.completions、responses、messages。protocol.version 取自请求的 A2A-Version Header;请求未携带该 Header 时,此字段可能省略。protocol.version 取自请求的 MCP-Protocol-Version Header;initialize 请求尚未完成版本协商,该字段会省略。direction = "request";http.method、http.path、http.headers;content.body 按 content.encoding 表示审核执行时的完整业务协议 Body,包含更高优先级插件此前对请求体的修改;JSON 为完整 JSON 值,不保证字节级格式一致。direction = "response"、http 携带 status_code。以下为 A2A JSON-RPC 响应送审示例:{"schema_version": "2.0","audit_id": "b238ce7f-8616-4914-b21f-a65f144cf90f","direction": "response","protocol": {"category": "a2a","name": "a2a-jsonrpc","version": "1.0"},"http": {"status_code": 200,"headers": { "content-type": ["application/json"] }},"streaming": { "mode": "none" },"content": {"media_type": "application/json","encoding": "json","body": {"jsonrpc": "2.0","id": "task-001","result": {"id": "task-001","status": { "state": "completed" },"artifacts": [{ "parts": [ { "kind": "text", "text": "A2A Agent 返回内容" } ] }]}}},"gateway_context": { "request_id": "req-123" }}
{"schema_version": "2.0","audit_id": "audit-stream-0003","direction": "response","protocol": { "category": "mcp", "name": "mcp-streamable-http", "version": "2025-03-26" },"http": {"status_code": 200,"headers": { "content-type": ["text/event-stream"] }},"streaming": {"mode": "active","format": "sse","unit": "event_batch","stream_id": "req-123:response","sequence": 3,"final": false,"context_before": {"media_type": "text/event-stream","encoding": "text","body": "...previous approved context tail..."}},"content": {"media_type": "text/event-stream","encoding": "text","body": "data: {\\"jsonrpc\\":\\"2.0\\",\\"id\\":17,\\"result\\":{\\"content\\":[{\\"type\\":\\"text\\",\\"text\\":\\"当前批次的返回内容\\"}]}}\\n\\n"},"gateway_context": {"request_id": "req-123","gateway_id": "gateway-abc123","route_id": "route-456","service_id": "service-789"}}
字段 | 类型 | 说明 |
mode | string | 流式响应送审时固定为 active |
format | string | 当前固定为 sse |
unit | string | 固定为 event_batch,表示当前审核单元由一个或多个完整 SSE Event 组成 |
stream_id | string | 同一条逻辑响应流内保持不变,用于关联与观测;当前不承诺全局唯一,不得作为安全身份或持久化状态的隔离键 |
sequence | int | 当前逻辑响应流内实际送审单元的序号,从 1 开始严格递增 |
final | bool | 当前 Batch 是否为该逻辑响应流的最后一个送审单元 |
context_before | object | 可选的已放行历史尾部,仅用于识别跨 Batch 风险,不属于当前可改写内容 |
audit_id;标准响应模式下必须回显当前 Batch 的 audit_id。audit_id 不用于跨 Batch 关联,跨 Batch 关联应使用 stream_id。content 与 context_before 完成审核,不应仅依赖 stream_id 在服务端长期保存跨 Batch 状态。content.body 为当前待审核的完整 SSE Event 原始文本,可包含一个或多个 Event。content.media_type 固定为 text/event-stream,content.encoding 固定为 text。context_before.body 可能仅为前文尾部,不保证自身构成完整 SSE Event。审核服务可将其用于辅助判断,但不得并入替换结果。context_before 中的内容已下发至客户端,后续 Batch 不得再修改或撤回。schema_version 与 audit_id。各审核结论的处理行为如下:审核结论 | 网关行为 |
allow | 将当前 Batch 原样下发至客户端 |
block | 终止响应流。由于 SSE 场景的 HTTP 200 响应头通常已发送,客户端收到的是 event: error,而非新的 HTTP 403 |
replace | 仅在开启流式响应改写时允许返回。 content 必须为当前整个 Event Batch 的完整替换值(非 Patch),且由完整 SSE Event 组成;替换后继续处理后续 Batch,若替换内容包含该协议可识别的终止 Event,则结束响应流 |
replace 响应示例:{"schema_version": "2.0","audit_id": "audit-stream-0003","decision": "replace","reason_code": "CONTENT_REDACTED","content": {"media_type": "text/event-stream","encoding": "text","body": "data: {\\"jsonrpc\\":\\"2.0\\",\\"id\\":17,\\"result\\":{\\"content\\":[{\\"type\\":\\"text\\",\\"text\\":\\"替换后的安全内容\\"}]}}\\n\\n"}}
final = true。final = true;若已产生送审单元、尚未出现 final = true 且未进入审核旁路,则补发 final = true 且 content.body = "" 的空终止单元,其 encoding 为 text。异常中断时不保证收到终止单元。allow 或 block,不允许 replace。final = true,同一 stream_id 不再产生后续 Event Batch。审核结论 | 控制台配置项 | 网关最终行为 |
allow | — | 原样透传当前审核单元 |
block | 命中动作 = 拦截 | 阻断请求或终止响应流,返回拦截提示文案 |
replace | 命中动作 = 拦截 且开启内容改写(仅输出方向;命中动作为观察时不执行替换) | 用审核服务返回的内容整体替换当前审核单元;替换优先于命中阻断 |
schema_version、audit_id 或 decision。{"schema_version": "2.0","audit_id": "7c96777a-5f8f-4e58-9b16-2fdc0de3a7ba","decision": "allow"}
{"schema_version": "2.0","audit_id": "7c96777a-5f8f-4e58-9b16-2fdc0de3a7ba","decision": "block","reason_code": "CONTENT_RISK","message": "内容不符合安全策略"}
reason_code 与 message 为可选字段。message 是否作为客户端提示由网关策略决定——对应控制台拦截提示文案配置为「从响应中读取」时生效,读取为空时回退默认文案。tools/call 非流式响应执行完整 Body 替换的示例(direction = "response"):{"schema_version": "2.0","audit_id": "audit-response-001","decision": "replace","reason_code": "CONTENT_REDACTED","content": {"media_type": "application/json","encoding": "json","body": {"jsonrpc": "2.0","id": 17,"result": {"content": [ { "type": "text", "text": "替换后的安全内容" } ],"isError": false}}}}
replace 时必须满足以下约束:content 对象;content.media_type 与 content.encoding 必须与送审请求完全一致;content.body 表示替换后的整个当前审核单元,是完整替换值而非 Patch;replace,网关将其**转换为 block**,再按观察 / 拦截策略处理。项目 | 约定 |
触发条件 | 由网关配置决定,当前默认超过 1 MiB 进入分段;接入方不应硬编码该阈值 |
容量上限 | 默认最大接收 32 MiB,超出上限的请求不进入送审;接入方不应硬编码该阈值 |
分片大小 | 以 Begin 阶段声明的 content.transfer.chunk_bytes 为准,网关会根据 Body 大小动态调整 |
超时 | begin、全部 chunk 与 end 共用同一个传输总超时,以网关实际下发的配置为准;控制台创建策略时对应 检测总超时(默认 500 毫秒,取值范围 50~5000 毫秒) |
流式意图 | 网关在 Begin 前不会再次完整解析 Body;无法从路径或 Header 明确判断流式意图时, streaming.mode 保守标记为 possible,该值不代表响应一定为流式 |
改写能力 | 当前分段协议不支持 replace,仅返回 allow 或 block |
Content-Type: application/jsonX-CNGW-Audit-Schema-Version: 2.0X-CNGW-Audit-Id: <audit_id>X-CNGW-Audit-Transfer-Phase: beginX-CNGW-Audit-Transfer-Id: <transfer_id>
protocol、http、streaming、gateway_context 与内联信封一致;content 不再包含 body,改为携带传输描述:{"content": {"media_type": "application/json","encoding": "json","transfer": {"transfer_id": "transfer-123","total_bytes": 5242880,"sha256": "<完整原始Body的SHA-256十六进制值>","chunk_bytes": 262144}}}
{"schema_version": "2.0","audit_id": "<audit_id>","transfer_id": "transfer-123","status": "continue","next_sequence": 1}
Content-Type: application/octet-streamX-CNGW-Audit-Schema-Version: 2.0X-CNGW-Audit-Id: <audit_id>X-CNGW-Audit-Transfer-Phase: chunkX-CNGW-Audit-Transfer-Id: transfer-123X-CNGW-Audit-Transfer-Sequence: 1X-CNGW-Audit-Transfer-Offset: 0
sequence = N,审核服务返回:{"schema_version": "2.0","audit_id": "<audit_id>","transfer_id": "transfer-123","status": "continue","next_sequence": 2}
Content-Type: application/jsonX-CNGW-Audit-Schema-Version: 2.0X-CNGW-Audit-Id: <audit_id>X-CNGW-Audit-Transfer-Phase: endX-CNGW-Audit-Transfer-Id: transfer-123
{"schema_version": "2.0","audit_id": "<audit_id>","transfer_id": "transfer-123","phase": "end","chunks": 20,"total_bytes": 5242880,"sha256": "<完整原始Body的SHA-256十六进制值>"}
sequence、offset、total_bytes 与 sha256。media_type 解释:JSON 可解析为 JSON 值,文本按对应字符集读取,二进制保持原始字节。Begin 阶段的 content.encoding 描述该内容在内联信封中的表示方式,不是 Chunk 的传输编码;即使其值为 base64,也不得对重组后的 Chunk 再次执行 Base64 解码。allow 或 block,且必须同时原样回显 schema_version、audit_id 与 transfer_id:{"schema_version": "2.0","audit_id": "<audit_id>","transfer_id": "transfer-123","decision": "allow"}
文档反馈