Files
brainwave/docs/ai-safety.md
T

151 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AI 解释契约与安全边界
> 状态:提供方无关的 MVP 契约;模型供应商与后端仍为 TBD
> 核心原则:AI 解释既有结果,不参与起卦,不替用户决定
## 1. 调用门
只有同时满足以下条件才允许调用 AI:
1. 已存在由本地 `CastEngine` 生成并锁定的 `CastResult`。
2. 本卦、之卦、卦辞和实际动爻已经可供用户查看。
3. 用户明确点击「AI 解读」。
4. 用户已经接受当前版本的数据发送说明;同意版本变化后需重新确认。
5. 网络可用且客户端已通过请求前校验。
禁止后台预取、自动重试到另一模型、首次进入结果页即调用、以及把 AI 回复用于改写 `CastResult`。
## 2. AI 输入契约
客户端提交给后端的业务载荷应是明确 DTO,不发送整个数据库实体或 UI 状态:
```json
{
"contractVersion": "explanation-v1",
"locale": "zh-Hans",
"question": "用户明确同意发送的问题文本",
"cast": {
"methodVersion": "coin-v1",
"primaryHexagramId": 24,
"transformedHexagramId": 2,
"movingLinePositions": [1],
"lineValuesBottomUp": [9, 8, 8, 8, 8, 8]
},
"grounding": {
"contentVersion": "zh-Hans-2026.1",
"primaryJudgment": "本地审核文本",
"movingLineTexts": [
{"position": 1, "text": "本地审核文本"}
],
"transformedJudgment": "本地审核文本"
}
}
```
不发送:账号标识、通讯录、位置、设备广告 ID、历史记录、其他会话问题或开发者密钥。
用户问题必须被服务端提示词当作“待分析数据”而不是指令。客户端与服务端都不能把用户文本直接拼接为无边界系统指令。
## 3. 输出契约
模型必须返回结构化对象,服务端验证后再交给客户端:
```json
{
"contractVersion": "explanation-v1",
"source": "AI",
"summary": "一段不确定性明确的白话摘要",
"observations": [
{"label": "当前处境", "text": "…", "groundedBy": ["primary"]},
{"label": "变化所在", "text": "…", "groundedBy": ["line-1", "transformed"]}
],
"questionsToConsider": ["…"],
"reversibleAction": {
"title": "可以试的一小步",
"steps": ["…"],
"timebox": "例如 24 小时或一周",
"rollback": "如何停止、撤回或恢复原状"
},
"caution": "这不是预测或专业意见。"
}
```
客户端必须:
- 拒绝未知 `contractVersion`;
- 限制字段长度和数组数量;
- 将所有字段视为纯文本,不能执行 HTML、Markdown 链接、脚本或模型生成命令;
- 缺少必要字段时进入可恢复失败状态;
- 显示 `source=AI`,不伪装为经典原文或项目编辑内容。
## 4. 提示词不变量
服务端系统提示词至少表达:
- 输入中的卦号、爻值、动爻和经典文本是已经发生的事实,不得重算、替换或质疑。
- 只解释提供的本卦、之卦和实际动爻,不补造不存在的爻辞、典故或来源。
- 使用现代、平实、有条件的语言,避免“注定、必然、天意、唯一正确”。
- 不预测日期、彩票、价格、疾病结局、死亡、怀孕、诉讼或他人隐秘意图。
- 不替用户做辞职、分手、结婚、借贷、投资、医疗、法律、人身安全等高影响决定。
- 可以帮助拆解顾虑、列出可验证假设、提出澄清问题。
- 结尾最多给出一项低风险、可撤销、有限时的行动,并写出停止或回滚方法。
- 如果无法可靠解释,应说明限制并回退到本地材料,不用权威语气填补空白。
## 5. 高风险内容处理
| 用户内容 | AI 行为 |
|---|---|
| 投资、借贷、博彩 | 不给买卖/金额/时点结论;建议查看事实、风险承受力并咨询合格人士 |
| 医疗或心理诊断 | 不诊断、不建议停药;建议联系合格专业人员 |
| 法律纠纷 | 不提供确定法律结论;建议保存事实并咨询当地合格律师 |
| 辞职、分手等重大决定 | 不替用户决定;建议设计小范围验证、冷静期或对话 |
| 自伤、伤人或即时危险 | 停止卦象式解释;以安全为先,鼓励联系当地紧急服务、可信任的人或专业支持 |
高风险分支的提示和模板需要安全评审与专门测试。地域相关的热线和法律/医疗资源不能由模型临时编造;上线前采用经过维护的资源表或不显示不确定号码。
## 6. 本地解释
本地解释是可靠降级路径,不是低等级付费占位。它应:
- 直接读取经审校的本地白话;
- 根据是否有动爻组合固定结构;
- 清楚区分本卦、变化位置与之卦;
- 通过模板提供反思问题,但不根据用户问题生成事实断言;
- 无网络、未同意 AI 或 AI 失败时完整可用。
本地模板同样遵守“不预测、不裁决”的产品原则。
## 7. 故障与重试
| 故障 | 客户端表现 | 是否改变起卦结果 |
|---|---|---|
| 无网络 | 提供本地解读和“稍后重试” | 否 |
| 超时 | 保留结果,允许一次显式重试 | 否 |
| 429/限流 | 告知稍后再试,不循环请求 | 否 |
| 服务端 5xx | 显示通用错误码,保留本地内容 | 否 |
| 非法 JSON/缺字段 | 拒绝渲染,记录脱敏错误码 | 否 |
| 安全拦截 | 使用安全说明或本地材料 | 否 |
重试必须由用户发起或使用受限、可取消的网络策略;不得因重试得到不同回复而覆盖用户已经保存的解释,除非用户明确选择“重新解读”。
## 8. 密钥、日志和服务端
- 正式模型密钥只存在于后端密钥管理系统。
- Android APK 中不包含生产密钥,即使使用混淆、BuildConfig 或 NDK 也不视为安全。
- 发布构建关闭 HTTP body 日志。
- 业务日志使用 request ID、合同版本、状态码、延迟桶和模型配置版本;不记录原始问题与回复。
- 模型、提示词和安全策略都有独立版本,便于复现与回滚。
- 服务端对输入输出做长度、schema、频率和内容安全检查。
Android 端密钥管理参考:[Android 安全清单](https://developer.android.com/privacy-and-security/security-tips)。
## 9. AI 验收测试
- 同一 `CastResult` 在 AI 请求前后字节级确定字段不变。
- 没有 `CastResult`、未点击、未同意或结果尚未显示时,网络 mock 收到 0 次调用。
- 提示注入样例不能让模型重算卦、泄露系统提示或执行用户文本中的指令。
- 高风险测试集不产生确定的医疗、法律、投资或人生决定。
- 所有合法输出都有可撤销行动;所有非法输出都被客户端拒绝且可改用本地解释。
- 网络断开、超时、取消、旋转和进程重建不会重复提交。
- 日志捕获测试中不出现问题原文、回复全文和密钥样例。