跳到主要内容

Guard 流式检测流程

本文描述 chat.completions 流式响应检测场景下,Aidy 与 CyberGuard 的交互流程与异常语义。

生效条件

本文描述的是 Guard 的附加行为,不是单独插件。只有在满足 Guard 本体启用条件的前提下,并且同时满足以下条件时,Aidy 才会走流式检测:

  • 当前请求属于 chat 流程
  • 请求为流式请求
  • 路由开启了 Guard 响应检测
  • 上游返回的响应码为 200 且以 text/event-stream content-type 响应

如果不满足这些条件,可能仍然是 Guard 已进入请求链路,但不会启用这里描述的"响应流式检测"流程。

async_session_block 的请求前置检查

detect_chat_response.mode = async_session_block 时,Guard 在启用流式检测前会先查询 Redis 是否存在该 session 的封禁 key:

  • 若已封禁 → 直接返回拦截(HTTP 512 + error JSON)或代答(HTTP 200 + from-security-guard 流式事件),不再建立双向流式检测
  • 若未封禁 → 正常进入流式检测流程

总体流程

建立双向流并发送 Init

Aidy 与 CyberGuard 建立 ChatCompletionStream 双向流,先发送 Init

  • policy_chain_json:当前路由的检测策略 JSON(由 Aidy 解析后转换为 policy_chain 发给 CyberGuard)
  • request_id:Aidy 请求 ID

上游 Chunk 转发为检测 Chunk

Aidy 从上游 SSE 持续读取 chat.completion.chunk,提取可检测文本后发送给 CyberGuard:

  • 请求类型:ChatCompletionStreamRequest.Chunk
  • 字段:index + content
  • index1 开始递增(注:保证单调递增,但不保证连续)

如果当前请求阶段曾被 modify_action 脱敏,Aidy 会先在 StreamEventIR 层把占位符还原,再把还原后的文本送入流式检测与客户端输出。因此流式检测、客户端观测和非流式还原保持一致,不会把已知占位符直接透传给下游。

消费 DetectResult 并放行/拦截

CyberGuard 可按自身窗口策略返回 0/1/N 条 DetectResult。 其中 checked_index = N 语义为:<= N 的内容均已检测完成。

  • safe:Aidy 放行并回放 <= checked_index 的缓存响应给用户
  • unsafe + block_action:行为因 mode 不同而异(见下)
  • unsafe + override_action:行为因 mode 不同而异(见下)
  • unsafe + modify_action:不触发 session 封禁,与非流式行为一致

mode = block(同步拦截)

检测到 block_action 时输出 refusal chunk(delta.refusalfinish_reason=refusal);检测到 override_action 时输出 substitute stream(代答)。命中后立即取消上游请求并发送 EOM(见下文"命中风险后的即时动作")。

mode = async_session_block(异步会话封禁)

检测到 block_actionoverride_action 时将 session 封禁 key 写入 Redis,但当前流式响应不会被拦截,所有 chunk 继续正常转发给客户端。后续来自同一 session 的请求在进入上游前即被拦截。

备注

async_session_block 的语义是"不阻塞当前请求"。当前请求的响应内容会完整转发给客户端,即使 CyberGuard 已检测到不安全内容。封禁效果仅对后续请求生效。

命中风险后的即时动作(仅 block 模式)

一旦触发风险动作,Aidy 立即:

  1. 停止继续向用户透传上游正常内容
  2. 输出 refusal 或 substitute
  3. 取消上游 LLM 请求
  4. 若尚未向 CyberGuard 发送 EOM,则立即发送 EOM

EOM 与收尾

EOM 发送时机

Aidy 会在以下任一时机发送 EOM

  • 上游自然结束(finish / [DONE]
  • 已命中风险并提前终止上游

EOM 会附带当前已聚合的 tool_calls(若存在)。

EOM 后行为

EOM 发出后,Aidy 继续接收 CyberGuard 返回,直到关闭或超时。

  • 正常结束:CyberGuard 在 EOM 后关闭连接(关闭前可返回 0/1/N 条 DetectResult)
  • 异常结束 1(提前关闭):EOM 前就关闭连接
  • 异常结束 2(检测超时):EOM 后超过 guard.timeout_ms 仍未关闭

日志汇总规则

流式检测结束时,Aidy 会写入两类流式检测结果字段:

guard.chat

  • 取整个流期间(含 EOM 后)收到的第一个 unsafe DetectResult
  • 保留该条 DetectResult 对应的 resultaction
  • statuseffect_action 也按这条 guard.chat 计算
  • 若整个流没有 unsafe,则按最后一个 DetectResult 回填(用于 safe / error)
  • 若自始至终没有任何 DetectResult,则记为错误(status=error,并写入 error

guard.chat_stream

  • 记录整个流期间(含 EOM 后)收到的所有 unsafe DetectResult
  • 以数组形式输出
  • 做去重:对 unsafe 结果(含 action)进行内容去重,重复项只保留第一次出现

字段示例

  • guard.chat:首个 unsafe
  • guard.chat_stream:去重后的所有 unsafe 列表