Guard 流式检测流程
本文描述 chat.completions 流式响应检测场景下,Aidy 与 CyberGuard 的交互流程与异常语义。
生效条件
本文描述的是 Guard 的附加行为,不是单独插件。只有在满足 Guard 本体启用条件的前提下,并且同时满足以下条件时,Aidy 才会走流式检测:
- 当前请求属于 chat 流程
- 请求为流式请求
- 路由开启了 Guard 响应检测
- 上游返回的响应码为 200 且以
text/event-streamcontent-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 index从1开始递增(注:保证单调递增,但不保证连续)
如果当前请求阶段曾被 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.refusal,finish_reason=refusal);检测到 override_action 时输出 substitute stream(代答)。命中后立即取消上游请求并发送 EOM(见下文"命中风险后的即时动作")。
mode = async_session_block(异步会话封禁)
检测到 block_action 或 override_action 时将 session 封禁 key 写入 Redis,但当前流式响应不会被拦截,所有 chunk 继续正常转发给客户端。后续来自同一 session 的请求在进入上游前即被拦截。
async_session_block 的语义是"不阻塞当前请求"。当前请求的响应内容会完整转发给客户端,即使 CyberGuard 已检测到不安全内容。封禁效果仅对后续请求生效。
命中风险后的即时动作(仅 block 模式)
一旦触发风险动作,Aidy 立即:
- 停止继续向用户透传上游正常内容
- 输出 refusal 或 substitute
- 取消上游 LLM 请求
- 若尚未向 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 对应的
result与action status与effect_action也按这条guard.chat计算- 若整个流没有 unsafe,则按最后一个 DetectResult 回填(用于 safe / error)
- 若自始至终没有任何 DetectResult,则记为错误(
status=error,并写入error)
guard.chat_stream
- 记录整个流期间(含 EOM 后)收到的所有 unsafe DetectResult
- 以数组形式输出
- 做去重:对 unsafe 结果(含 action)进行内容去重,重复项只保留第一次出现
字段示例
guard.chat:首个 unsafeguard.chat_stream:去重后的所有 unsafe 列表