操作场景
自定义安全服务用于将客户自有或第三方厂商的安全产品(如自建内容审核平台、第三方安全产品)接入 AI 网关。配置完成后,网关会在请求转发前、以及(可选)模型响应返回后,将完整的原始报文全量转发至外部安全服务送审,并按外部服务返回的判定结果执行放行、拦截或内容改写。
该功能适用于以下场景:
企业已建设自有内容安全/风控系统,希望 AI 网关复用现有安全能力,而非切换安全产品。
需要同时使用网关内置安全策略与第三方安全产品,对同一资源叠加防护。
需要在安全检测的同时完成内容处理(如 PII 识别后返回打码文本,替换原文后继续转发)。
前提条件
已创建 AI 网关实例,且实例处于运行中状态。
已准备可用的外部安全服务检测接口:支持 HTTP/HTTPS 协议,能够接收网关全量转发的原始请求体/响应体,并自行解析待检内容。
已明确外部服务响应中用于判定"命中/放行"的字段路径及取值(如
result.blocked = true)。如外部服务需要鉴权,已获取 API Key(请求头名称与密钥值)。
如计划长期使用,建议已在服务管理中配置该服务;仅做临时验证时可在配置页手动填写地址。
操作步骤
步骤1:进入自定义安全服务页面
1. 登录 AI 网关控制台,选择目标网关实例进入详情页。
2. 在左侧导航栏,选择安全与配置 > 安全防护,进入安全防护页面。
3. 在页面上方单击自定义安全服务 Tab,进入自定义安全服务页面。
说明:
送审流程依次为:调用方请求进入 AI 网关 → 全量转发(网关进行字段映射)→ 外部安全服务执行检测 → 判定映射解析(按响应判定映射解析命中结果)→ 放行后转发至上游模型。检测方向为输入+输出时,模型响应返回后会重复转发与判定环节,对输出内容二次送审。
步骤2:填写基本信息
在自定义安全服务策略模块中,单击新建策略,在弹出的对话框中填写以下参数:
策略名称:策略标识,以字母开头,支持字母、数字、
-、_(必填)。描述:策略用途说明(选填)。
步骤3:配置服务连接
1. 在服务地址方式处选择地址来源(必填):
选择已有服务(默认,推荐):在选择服务下拉框中,选择已在服务管理模块注册的服务,服务列表支持 HTTP/HTTPS 两种协议。另外,下拉框右侧提供刷新按钮与新建服务入口,单击新建服务将跳转至服务管理的新建服务页面,创建完成后返回本页,单击刷新按钮即可选择新建的服务。
手动填写地址:在服务地址输入框中填写外部安全服务的检测接口完整地址(支持 HTTP/HTTPS),端口与路径包含在地址中,不支持单独的参数配置。
2. 在鉴权方式处选择鉴权类型(必填):
无:外部服务无需鉴权。
API Key(Header):填写 Header 名称(如
X-API-Key)与密钥值。3. 单击测试连接,验证网关到外部服务的连通性;若已填写命中判定字段,测试结果会同步展示判定字段的解析结果。
说明:
推荐复用服务管理中已注册的后端服务,统一维护地址;仅在临时验证场景下使用手动填写地址。手动填写的地址不落地为 服务管理 的服务记录,正式使用建议改为选择已有服务。
注意:
Header 名称与密钥值加密存储,密钥值保存后不可查看,请自行留存备份。
若外部服务采用 Bearer Token 鉴权,可将 Header 名称填写为
Authorization、密钥值填写为 Bearer <token 值>。步骤4:配置响应判定映射
按以下三组配置,告诉网关如何从外部服务的返回结果中读取判定信息:
1. 命中判定:
命中判定字段路径:外部服务响应中用于判断是否命中的字段路径,如
result.blocked(必填)。命中值:字段取值等于此值时视为命中,如
true 或 BLOCK(必填)。2. 拦截提示文案:选择文案来源(必填)。
使用默认文案:输入框已预填默认话术“您的请求包含违规内容,已被安全策略拦截。请修改后重试。”,您可直接修改为自定义固定文案。
从响应中读取:填写外部服务响应中拦截文案所在的字段路径;读取为空时,回退默认文案。
3. 内容改写(可选):开启开关后,填写改写内容字段路径(必填,如
result.sanitized_text),网关进行输出改写。放行时,网关会取该字段的完整取值整体替换原始检测文本(如打码后的文本);关闭开关则原样透传。内容改写仅在输出方向(响应送审)生效,需与检测方向 输入 + 输出 配合使用;输入方向不支持内容改写。若外部服务在输入阶段返回改写内容,或策略未开启内容改写时返回改写内容,网关将会忽略此时的替换字段,继续根据命中字段判定。说明:
网关仅支持单层或简单嵌套的字段路径取值,不支持脚本或表达式处理数组遍历、多条件联合判断。若外部服务响应结构复杂,建议在其侧新增适配接口,将判定结果扁平化后再对接。
步骤5:配置检测行为控制
检测方向(必填):仅输入(默认)或 输入 + 输出。
命中动作(必填):观察或拦截。当命中动作为拦截时,按审核结论阻断请求或改写内容,并返回拦截提示文案。
检测总超时(必填):调用外部服务的最长等待时间,取值范围 50~5000 毫秒(含边界),默认 500 毫秒。
检测失败策略(必填):异常时放行 / 异常时拦截。
注意:
选择异常时放行时,审核超时或连接失败会放行请求,存在安全绕过风险。检测总超时会累加到请求整体耗时,检测方向为输入 + 输出时总耗时为两次外部调用耗时之和。
步骤6:绑定生效范围并提交
1. 在生效范围处选择作用范围(必填):
全部:对该实例下所有资源(模型 API / MCP 服务(SSE 除外)/ Agent API(A2A))生效。
部分:仅对选定的资源生效。在选择资源区域通过模型 API、MCP 服务、Agent API 三个页签切换资源类型(页签展示已选数量),在对应列表中按名称搜索并勾选资源;列表展示资源的名称、路径、协议。
2. 单击提交,完成创建;单击关闭则放弃本次配置。
步骤7:查看与管理策略
1. 在策略列表中,可通过搜索框按策略名称、描述过滤策略。单击目标策略名称,可以打开右侧详情滑窗,查看基本信息、生效范围与响应判定映射三部分配置。单击返回策略列表可退回列表页。
2. 在策略列表右侧的操作列,可执行编辑、禁用(可恢复)、删除(不可恢复)操作:
禁用:弹窗提示“确认禁用策略「策略名称」?禁用后该策略将立即停止生效,其绑定的资源将不再受此策略保护。”,单击确认禁用后生效。禁用后可在列表中随时重新启用,策略配置将被完整保留。
删除:弹窗提示“确认删除策略「策略名称」?删除后该策略将立即失效,且操作不可恢复。”,单击确认删除后生效。
步骤8:查看内容审核明细
1. 在自定义安全服务页面下方的内容审核明细模块,可以按命中动作、检测方向筛选,查看本 Tab 下所有策略的送审命中记录。
2. 单击下载明细,可以导出当前筛选结果为 CSV 文件,限制最多为 1000 条。
送审协议说明(外部安全服务对接规范)
本节规定 AI 网关(以下简称“网关”)与外部安全服务(以下简称“审核服务”)之间的送审接口契约,供审核服务的开发对接方实现接入时使用。
网关不直接转发原始业务报文,而是先将原始请求/响应封装为统一送审信封(Schema Version 2.0),再 POST 至审核服务。无论原始业务采用 OpenAI 兼容协议、Anthropic、Dify、A2A 还是 MCP,网关均输出同一套信封结构,审核服务只需对接一次契约,无需逐协议适配解析器。
协议概述与术语
交互角色
角色 | 职责 |
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 三个阶段构成的完整传输过程 |
规范动词约定
本规范采用 RFC 2119 定义的要求级别:必须(MUST)、不得(MUST NOT)、应当(SHOULD)、不应(SHOULD NOT)、可(MAY)。
协议设计原则
语义保持:统一信封不改写原始业务协议的语义,仅通过
protocol 字段声明其类型;审核服务可据此选择专用解析器,也可直接对 content.body 执行通用检测。结构归一,字节不归一:JSON Body 会被解析为完整 JSON 值,对象、数组与标量的语义保持不变,但不承诺空格、换行、字段顺序等字节级格式与原始报文一致;超大 Body 的 Chunk 阶段传输原始字节。
HTTP 约定
项目 | 约定 |
请求方法 | 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 表示审核服务调用失败(而非内容违规),网关按策略配置的检测失败策略处理 |
注意:
审核服务不得通过返回非 2xx 状态码表达内容违规。内容违规必须以 HTTP 2xx 响应体表达——标准响应模式下为
decision = "block",自定义字段映射模式下为命中判定字段取命中值。统一送审信封
以下为 MCP Streamable HTTP 请求的送审示例(内联信封形态):
{"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 | 可选 | 网关依据当前请求上下文自动补充,不由调用方填写 |
http 字段
字段 | 类型 | 说明 |
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 由网关白名单配置决定。凭据与会话类 Header(
authorization、cookie、x-api-key、mcp-session-id 等)不会随送审请求发出。说明:
凭据类 Header 默认不透传,用于避免客户密钥泄漏至第三方审核服务。如审核服务的检测逻辑确需 Query 参数参与,需在网关侧显式开启 Query 透传。
content 编码
审核服务应当依据
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 编码,见 流结束语义 |
说明:
无 Body 的请求不会生成请求内容送审。例如 MCP Legacy SSE 的
GET /sse 仅用于建立响应流,请求阶段直接跳过,后续仍可进入流式响应审核。gateway_context 字段
该对象由网关依据当前请求上下文填充,可能包含以下字段:
字段 | 类型 | 约束 | 说明 |
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 可能继承客户端传入值,可用于日志关联,不应单独作为可信身份依据。streaming 字段
该字段用于区分请求方向的流式意图与响应方向的实际流式审核状态。
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 执行通用检测。OpenAI Chat Completions、OpenAI Responses、Anthropic Messages 的
protocol.version 为 v1,protocol.operation 分别为 chat.completions、responses、messages。A2A 的
protocol.version 取自请求的 A2A-Version Header;请求未携带该 Header 时,此字段可能省略。MCP 的
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" }}
流式响应送审
开启流式响应审核后,网关不会等待整条 SSE 流结束再统一送审,而是按以下时序处理:
1. 网关将收到的完整 SSE Event 组装为 Event Batch(审核单元);
2. 按流内顺序同步调用审核服务送审当前 Batch;
3. 网关取得审核结论并按策略处理后,才将当前 Batch 下发至客户端。
处理规则:
被过滤规则或抽样规则未选中的 Batch 不会调用审核服务。
审核服务超时、网络错误或返回非 2xx 时,网关按策略配置的异常时放行(Fail-Open)或异常时拦截(Fail-Closed)处理。
Batch 边界由网关按 Event 数、字节数或等待时间动态生成。
Event Batch 送审格式
以下为 MCP Streamable HTTP 的 SSE 响应送审示例:
{"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"}}
streaming 字段(流式响应)
字段 | 类型 | 说明 |
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 风险,不属于当前可改写内容 |
注意:
每个 Event Batch 生成独立的
audit_id;标准响应模式下必须回显当前 Batch 的 audit_id。audit_id 不用于跨 Batch 关联,跨 Batch 关联应使用 stream_id。审核服务应当依据本次
content 与 context_before 完成审核,不应仅依赖 stream_id 在服务端长期保存跨 Batch 状态。审核服务不应假设一次请求只产生一个 Event,也不应依赖固定的 Batch 大小。
content 与上下文规则
content.body 为当前待审核的完整 SSE Event 原始文本,可包含一个或多个 Event。普通 Batch 的
content.media_type 固定为 text/event-stream,content.encoding 固定为 text。context_before.body 可能仅为前文尾部,不保证自身构成完整 SSE Event。审核服务可将其用于辅助判断,但不得并入替换结果。已出现在
context_before 中的内容已下发至客户端,后续 Batch 不得再修改或撤回。审核结果处理
审核服务的响应格式见 审核响应;标准响应模式下必须回显当前 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"}}
上表为命中动作 = 拦截时的处理行为。命中动作为观察时,网关仅记录判定,不执行内容阻断与替换;检测异常仍按检测失败策略处理。
流结束语义
OpenAI Chat Completions、OpenAI Responses、Anthropic、Dify 与 A2A 按各自协议的终止 Event 确定
final = true。MCP Streamable HTTP 与自定义 SSE 无统一的带内终止标记。上游连接 EOF 时:若仍有待送审内容,最后一个非空 Batch 可直接携带
final = true;若已产生送审单元、尚未出现 final = true 且未进入审核旁路,则补发 final = true 且 content.body = "" 的空终止单元,其 encoding 为 text。异常中断时不保证收到终止单元。空终止单元仅允许返回
allow 或 block,不允许 replace。一旦某个单元
final = true,同一 stream_id 不再产生后续 Event Batch。审核响应
审核服务的响应必须为 JSON。审核结论与控制台策略配置的对应关系如下:
审核结论 | 控制台配置项 | 网关最终行为 |
allow | — | 原样透传当前审核单元 |
block | 命中动作 = 拦截 | 阻断请求或终止响应流,返回拦截提示文案 |
replace | 命中动作 = 拦截 且开启内容改写(仅输出方向;命中动作为观察时不执行替换) | 用审核服务返回的内容整体替换当前审核单元;替换优先于命中阻断 |
网关支持自定义字段映射模式,对应控制台响应判定映射的三组配置;按配置路径读取判定、提示与替换字段,不要求返回固定的
schema_version、audit_id 或 decision。说明:
当输出方向开启改写且存在替换字段时,替换优先于命中阻断;替换内容仍须通过格式与大小校验。
命中动作为观察时不执行内容阻断与替换。
超大 Body 分段的 Begin / Chunk 确认响应及 End 关联字段必须满足超大请求 Body 分段协议的要求;End 阶段的审核判定可使用字段映射。
放行
{"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 是否作为客户端提示由网关策略决定——对应控制台拦截提示文案配置为「从响应中读取」时生效,读取为空时回退默认文案。替换
以下为对 MCP
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**,再按观察 / 拦截策略处理。超大请求 Body 分段协议
当请求 Body 不适合放入单个 JSON 信封时,网关仍调用同一 Endpoint,并通过 begin → chunk → end 三个阶段完成送审。
通用规则:
项目 | 约定 |
触发条件 | 由网关配置决定,当前默认超过 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 |
Begin
请求头:
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}
Chunk
请求头:
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
请求体为原始字节,不做 JSON 或 Base64 包装。每收到
sequence = N,审核服务返回:{"schema_version": "2.0","audit_id": "<audit_id>","transfer_id": "transfer-123","status": "continue","next_sequence": 2}
End
请求头:
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。注意:
所有 Chunk 均为原始字节,重组后应按
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"}