【寻迹校园 HarmonyOS NEXT 实战 44】把候选交给小艺前先脱敏:XiaoYiAgentAdapter 的数据最小化设计

本章导读:这是“寻迹校园 HarmonyOS NEXT 实战”系列第 44 篇。本文以 XiaoYiAgentAdapter.etsXiaoYiClipboardAdapter.ets 和现有测试为证据,拆解本机候选如何经过字段白名单、最多三条限制、分段截断、正则脱敏、240 字总上限和用户主动复制后再交给小艺。文中不会展示真实 Agent/Workflow ID,也不会把正则替换描述成完整 DLP。

小艺候选数据最小化原创封面图

上图是原创隐私数据流概念图,不包含真实用户数据或项目截图。AI 辅助的第一原则不是“尽量给模型更多上下文”,而是“只给完成当前任务所必需的最少信息”。

一、为什么候选对象不能直接拼进 Prompt

一条失物记录可能包含标题、精确地点、照片 URI、联系方式、私密特征、创建时间和内部状态。直接 JSON.stringify(report) 会带来四类风险:

  • 把与比较无关的字段传给外部能力;
  • 把手机号、证件号或微信号带入 Prompt;
  • 把认领用的私密答案泄露给候选人;
  • Prompt 过长,重要冲突被噪声淹没。

数据最小化不是事后加一条正则,而是从数据结构、候选数量、字段长度和交互动作共同限制。

二、先明确小艺在本项目中的职责

小艺只负责:比较脱敏候选的相似点和冲突,帮助用户决定下一步查看哪条记录。

小艺不负责:

  • 判断物品最终归属;
  • 读取私密核验答案;
  • 获取原图或沙箱路径;
  • 自动提交认领;
  • 替代双方确认交接。

职责越窄,允许字段就越容易形成白名单。

三、输入不是单条记录,而是匹配包

prepareMatchSnapshot(queryReportId) 先调用 reportService.getMatchBundle(),得到查询记录和候选集合。Service 已经完成本机规则匹配,Agent Adapter 不再重新计算分数。

ReportService:决定候选集合与顺序
XiaoYiAgentAdapter:压缩、脱敏、限制数量
XiaoYiFunctionPage:展示、复制、打开小艺
小艺:解释相似点与冲突

这样 AI 适配层不会越权修改核心匹配规则。

四、当前代码最多只取三条候选

早期规划曾写“最多五条”,但当前真实代码是:

export const XIAOYI_INITIAL_QUERY_MAX_LENGTH: number = 240;
const XIAOYI_INITIAL_QUERY_MAX_CANDIDATES: number = 3;

const candidates = bundle.candidates.slice(0, XIAOYI_INITIAL_QUERY_MAX_CANDIDATES);

文章必须跟随当前实现。最多三条能控制长度,也能让用户在小艺回复中清楚对应“候选 1、2、3”。如果未来调整数量,需要同时更新总长度、UI 预览、测试和真机粘贴验证。

五、无候选时拒绝调用

candidates.length === 0,适配器直接返回“暂无足够证据交给小艺比较”。这比发送一个只有查询记录的 Prompt 更诚实。

没有候选时,小艺无法比较相似点与冲突。硬拉起只会得到泛化建议,还可能让用户误以为系统已经发现线索。

六、Prompt 首句先限制模型任务

当前摘要第一行是:

比较以下脱敏校园失物候选,列出相似点与冲突,不判断归属。

它同时做三件事:限定领域、限定输出、声明不判断归属。后续每条记录只用稳定短格式表达:

类型/类别/模糊地点/短日期/公开特征

Prompt 设计从业务边界开始,不从“你是一个聪明助手”开始。

七、字段白名单比黑名单更可靠

compactReport() 只保留:

字段 当前限制 用途
类型 丢失/拾得 判断相反类型
类别 最多 6 字 快速识别物品大类
地点 最多 10 字 保留模糊区域
日期 MM-DD 或最多 5 字 时间接近度
公开特征 最多 18 字 颜色、外观等对比

没有进入白名单的照片 URI、内部 ID、处理记录、私密特征和持久化字段不会被序列化。

八、公开特征也需要再次清洗

用户可能把手机号写进标题或描述,所以“公开字段”不等于“天然安全”。safeText() 会先调用 redactText(),再把单段限制在最多 80 字。

compactText() 还会把换行变为空格、分号统一为逗号,并根据当前字段上限继续截断。多层上限让任何单个字段都无法吞掉全部 Prompt。

九、正则脱敏覆盖什么

当前实现处理三类模式:

value.replace(/1[3-9][0-9]{9}/g, '[已隐藏手机号]')
  .replace(/[0-9]{17}[0-9Xx]/g, '[已隐藏证件号]')
  .replace(/(微信|QQ|手机|电话|联系方式)[::]?\s*[A-Za-z0-9_-]{4,}/g, '$1[已隐藏]');

它能覆盖常见连续手机号、18 位证件号和带联系方式前缀的账号串。替换发生在压缩前,也会在复制前再做一次。

十、正则不是完整 DLP

以下表达可能逃过当前规则:

  • 用空格、短横线或汉字拆开的手机号;
  • 邮箱、宿舍门牌、班级学号;
  • “一三八……”这类中文数字;
  • 图片中的文字;
  • 没有“微信/电话”前缀的账号;
  • 间接身份组合信息。

所以正则只是最低限度防线。更稳妥的策略仍是字段白名单、禁止原图、限制候选、用户确认和持续对抗测试。

十一、240 字总上限是最后一道保险

所有行合并后,适配器把 queryText 截断到最多 240 字。复制前 prepareClipboardPayload() 会再次脱敏并再次执行 240 字上限。

双重处理有意义:页面参数可能被其他调用路径构造,不能假设进入剪贴板前一定来自同一个安全函数。

同时要注意,简单 substring() 可能在末尾截断一个语义单元。当前真实样例为 193 字,没有触发截断;未来可考虑按候选行预算长度,但那是演进项,不应冒充当前实现。

十二、适配器返回快照,不直接打开平台

XiaoYiAgentSnapshot 只包含:

  • queryTitle
  • candidateCount
  • queryText

页面先展示快照,让用户知道会分享什么,再进入 Function 页面。数据准备与平台打开分离后,可以独立测试脱敏逻辑,也能在小艺不可用时保留原生候选。

十三、剪贴板必须由用户明确触发

XiaoYiClipboardAdapter.copyPlainText() 只在用户点击复制按钮后执行。它创建纯文本 PasteData,把共享范围设置为 ShareOption.LOCALDEVICE,再调用 setData()

const pasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text);
const property = pasteData.getProperty();
property.shareOption = pasteboard.ShareOption.LOCALDEVICE;
pasteData.setProperty(property);
await pasteboard.getSystemPasteboard().setData(pasteData);

当前适配器不读取剪贴板,不上传剪贴板,不持久化摘要,也没有新增读取权限。

十四、为什么不用自动复制

自动复制会覆盖用户剪贴板,也会削弱“用户知道数据将被分享”的控制感。当前页面把流程写成两个明确步骤:

  1. 复制脱敏摘要;
  2. 打开小艺并粘贴发送。

用户可以在第一步看到摘要,在第二步选择是否继续。即使小艺打开失败,原生候选仍然可用。

十五、错误也要最小化

剪贴板错误只映射为“系统剪贴板正忙”“系统阻止本次复制”或通用“复制失败”,不会把内部异常对象、内容或设备路径展示给用户。

平台错误同样应显示可行动文案,而不是打印包含业务数据的完整日志。开发日志可以记录错误码,但不应记录 240 字摘要正文。

十六、数据流全景

小艺脱敏白名单数据流原创结构图

上图展示从匹配包到用户主动复制的六段门禁。它是架构说明图,不代表系统读取了图中列出的所有敏感字段;真实实现通过白名单避免这些字段进入输出。

十七、测试应该同时验证正向与反向

当前测试覆盖的关键断言包括:

  • 最多输出三条候选;
  • 摘要长度不超过 240;
  • 手机号、证件号和微信账号被移除;
  • 空字符串不能进入剪贴板;
  • 剪贴板适配器只写不读。

还应持续补充绕过样例,例如带空格手机号、邮箱、中文数字和超长混合文本。隐私测试不是一次性通过后永久安全。

十八、不要在文章中泄露平台标识

源码可能包含真实 Agent ID 或 Workflow ID,它们不属于讲解脱敏算法所必需的信息。公开代码示例应统一写成 agent_xxxworkflow_xxx,日志截图也应检查相关字段。

同样不要展示签名密码、Profile、证书路径、账号或设备序列号。技术细节足够复现设计,不等于公开所有配置。

十九、本章证据边界

本章能证明当前适配器按最多三条、字段长度、正则和 240 字上限生成脱敏摘要;剪贴板只在用户操作后写入本机共享范围;相关本地测试和 2026-08-20 显式复制/粘贴真机链路已有记录。

本章不能证明正则覆盖所有敏感信息、剪贴板内容永不被系统中其他合规组件访问、所有机型行为一致,或 AI 输出能够判断最终归属。

二十、小结

AI 数据最小化不是一个 replace(),而是一条可复核链路:先限定任务,再限制候选,再使用字段白名单,然后分段压缩、正则脱敏、总长截断,最后由用户主动复制。

这条链路让小艺只看到完成“比较相似点与冲突”所需的最少文本,同时保留原生核验和最终确认。下一章继续拆解 FunctionComponent 的支持性检查、选项配置与错误码映射。

下一篇:《【寻迹校园 HarmonyOS NEXT 实战 45】FunctionComponent 接入实战:支持性检查、queryText 与错误码映射》。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐