跳到主要内容
版本:最新版(main)

PII 信号

概述​

pii 定位请求中的个人数据,并给出每个 span 的确切字符。它提出 pii 预设问题,即基于 11 个个人数据标签的 span 问题,并读取完整输入。当模型找到规则计入的标签的 span 时,规则匹配;masking 插件用占位符替换同样的 span。

主要优势​

  • 让隐私敏感的路由变得明确:把这类请求留在私有模型上,或拒绝它们。
  • 返回位置,因此遮蔽只替换真正的个人数据。
  • 可以忽略路由接受的标签,例如电子邮件地址。
  • 按要求读取工具结果和之前的轮次。

解决什么问题?​

没有个人数据信号时,敏感流量可能在被发现之前就到达错误的模型或插件链。临时过滤器让策略难以审计。pii 把个人数据检测变成可复用的路由输入。

何时使用​

在以下情况使用 pii:

  • 请求可能携带受监管或敏感的个人数据;
  • 有些标签可以接受,另一些必须走更安全的路由;
  • 决策在提供方看到请求之前遮蔽个人数据;
  • 工具结果可能把个人数据带回对话。

配置​

recipes:
- name: default
signals:
pii:
- name: personal_data
predicate: {gte: 0.85}
ignore_labels: [EMAIL_ADDRESS]
input:
history: true
- name: tool_result_pii
input:
tool_results: true
request: false
decisions:
- name: keep-private
priority: 200
rules:
operator: OR
conditions:
- {type: pii, name: personal_data}
- {type: pii, name: tool_result_pii}
modelRefs:
- model: private-model
字段含义
name规则名称,供 {type: pii, name: ...} 条件和 masking 插件的 signal 使用
predicatespan 的最低概率;默认为模型的校准阈值(vela3-fast 上为 0.18),否则为 0.5
ignore_labels规则永不计入的标签
input.history同时读取之前的用户轮次
input.tool_results同时读取请求中的工具结果
input.request设为 false 时不读取当前用户轮次,规则只读取它指定的之前用户轮次或工具结果
on_unscanned长输入只读了部分窗口时规则报告什么:best_effort(默认)、match、no_match 或 unknown
min_coverage使用 best_effort 时,至少要读完的窗口比例(0 到 1),达到后才根据已读窗口判断;低于该比例时规则为未知。默认关闭
on_unknown模型没有给出答案时规则报告什么:match(默认)或 no_match
deployment、timeout_ms回答问题的部署,以及答案的截止时间

规则的 predicate 是策略:请为你使用的模型校准这个值,或者省略它以使用模型的校准阈值。vela3-fast 的 span 适配器在返回 span 之前会应用它自己按长度设定的阈值,所以它的 0.18 会接受它返回的每个 span。

读取什么​

问题读取当前用户轮次;设置 input.history 时读取之前的用户轮次,设置 input.tool_results 时读取文本工具结果;工具调用和非文本内容不会被读取。它还会读取 global.router.routing_input 从路由文本中移除的内容,所以个人数据无法藏在伪造的记忆块里。

编码智能体的用户轮次带有其运行框架(harness)自身的指令:例如 Claude Code 2.1.317 会在第一条用户消息的提醒中放入一行带邮箱地址的提交尾注(commit trailer)。针对智能体工具返回内容的规则应同时设置 input.request: false 和 input.tool_results: true,如上面的 tool_result_pii,这样它只读取工具结果,不读取当前轮次及 routing_input 从中移除的内容。在请求带有工具结果之前,这样的规则不会被询问,也不会匹配。

它读取完整输入。超过部署一个 scan_window 的输入被切成相互重叠的窗口,先读结尾,再读开头,然后按二分读中间;每个窗口的 span 都按其在原输入中的位置计入,因此脱敏会替换每一处。参见长输入。如果截止时间在所有窗口读完之前到达,且已读窗口中没有发现个人数据,由 on_unscanned 决定:best_effort(默认)根据已读窗口作出判断(规则设置了 min_coverage 时,需读完该比例的窗口,低于该比例时规则为未知),match 把请求按个人数据计入(严格模式),no_match 不计入,unknown 交给 on_unknown。已读窗口中发现的个人数据无论 on_unscanned 如何设置都会计入。masking 插件始终需要读完所有窗口:无法完整读取的文本不会被发送。

模型可能只找到某个值的一次出现,而漏掉后面的副本。所找到的、长度至少两个字符的值,其其他所有完全相同、整词匹配的副本也会以同一标签报告,因此遮蔽会替换每一个副本。

模型没有给出答案时​

没有任何窗口得到答案(模型失败、过载或错过截止时间)的规则会匹配,匹配类型为 unavailable:失败即拦截,决策的 rules.on_unknown 仍然决定处理方式。若要放行这类请求,写 on_unknown: no_match:

recipes:
- name: default
signals:
pii:
- name: personal_data
on_unknown: no_match
decisions:
- name: keep-private
priority: 200
rules:
operator: AND
conditions:
- {type: pii, name: personal_data}
modelRefs:
- model: private-model

回答问题的模型​

除非 pii 绑定或规则的 deployment 指定了其他部署,否则由决策模型回答所有 PII 规则;见选择部署。该问题需要 span:解析到不支持 span 的部署(例如 d3 模型)的规则会以 span_required 加载失败,除非该部署在 capabilities 中声明了 pii 预设。vela3-fast(默认)、Vela 3.0 的 d3 规格和 Vela 2.0 用它们自己的 PII 问题回答,并与该请求针对同一文本的其他问题放在同一次调用中。

global:
model_catalog:
deployments:
d3-remote:
provider: systemone
endpoint: https://systemone.example.com/v1/systemone
model: vllm-sr/d3-ultra
schema: vllm-sr/5.0
auth: {api_key_env: SYSTEMONE_API_KEY}
system:
decision_model: {deployment: d3-remote}
bindings:
pii: primary

这个信号是路由控制,不能替代脱敏、加密、访问控制或数据防泄漏。完整示例见 config/fragments/signal/pii/strict.yaml。