diff --git a/docs/ai-data-permission-privacy.md b/docs/ai-data-permission-privacy.md new file mode 100644 index 0000000..4ea0d4f --- /dev/null +++ b/docs/ai-data-permission-privacy.md @@ -0,0 +1,164 @@ +# AI 数据权限、隐私授权与用户设置设计 + +## 1. 概述 + +定义 AI 分析可使用的数据范围、用户授权开关、隐私边界和字段发送规则。所有规则由 Snapshot Builder 执行,Runtime 无权绕过。 + +## 2. 用户授权项 + +存储在 `UserAiSettings` 中: + +| 字段 | 默认值 | 说明 | +|------|--------|------| +| `allowAiAnalysis` | `true` | 总开关。关闭后禁止创建任何 AI Job | +| `allowUseLearningBehavior` | `true` | 是否允许使用学习行为数据(时长、频率、pattern) | +| `allowUseUserProfile` | `true` | 是否允许使用用户画像(目标、等级、偏好) | +| `allowUseDocumentContent` | `false` | 是否允许使用资料原文片段。默认关闭,需用户主动开启 | +| `allowStoreAiAnalysisHistory` | `true` | 是否允许保存 AI 分析历史 | +| `allowUserModelCredential` | `true` | 是否允许使用自己的 DeepSeek Key | +| `fallbackToPlatformKey` | `true` | 用户 Key 不可用时是否回退到平台 Key | + +### 授权变更行为 + +| 用户操作 | HTTP | 立即影响 | +|---------|------|----------| +| 关闭 `allowAiAnalysis` | PUT /ai/settings | 禁止创建新 Job;pending Job → cancelled;running Job → cancelRequested | +| 关闭 `allowUseDocumentContent` | PUT /ai/settings | 新 Snapshot 不包含资料原文;已生成但未消费的 Snapshot 重用不受影响 | +| 开启 `allowUseDocumentContent` | PUT /ai/settings | 新 Snapshot 可包含资料原文 | +| 关闭 `allowUserModelCredential` | PUT /ai/settings | 已有 credential 不删除但不再用于新 Job;running Job 若使用用户 Key 继续完成 | + +## 3. 用户设置项 + +存储在 `UserLearningProfile` 中: + +| 字段 | 类型 | 说明 | 枚举值 | +|------|------|------|--------| +| `learningGoal` | string | 学习目标 | —(自由文本 + 预选项) | +| `currentLevel` | enum | 当前水平 | `beginner` / `basic` / `intermediate` / `advanced` / `expert` | +| `dailyAvailableMinutes` | int | 每日可用学习分钟 | 1-480 | +| `qualityPreference` | enum | 质量偏好 | `light` / `standard` / `deep` / `exam` | +| `ageRange` | enum | 年龄段(可选) | `unknown` / `under_18` / `age_18_24` / `age_25_34` / `age_35_44` / `age_45_54` / `age_55_plus` | +| `occupation` | string | 职业(可选) | 自由文本 | +| `aiAcceptanceLevel` | enum | AI 接受度 | `low` / `medium` / `high` | +| `digitalSkillLevel` | enum | 数字技能 | `low` / `medium` / `high` | +| `preferredQuestionTypes` | string[] | 偏好题型(可选) | 如 `["single_choice", "true_false"]` | +| `preferredLanguage` | string | 偏好语言 | `zh-CN` / `en-US` / `auto` | + +## 4. 隐私边界 + +### 4.1 硬约束(不可被 AI 覆盖) + +| 约束 | 来源 | 说明 | +|------|------|------| +| `dailyAvailableMinutes` | 用户设置 | AI 推荐的 estimatedMinutes 不得超过此值 | +| `allowAiAnalysis` | 用户授权 | 关闭时直接拒绝所有 Job | +| `allowUseDocumentContent` | 用户授权 | 关闭时不发送原文给模型 | +| `allowUseLearningBehavior` | 用户授权 | 关闭时不发送行为信号给模型 | + +### 4.2 禁止收集的数据 + +- 精确年龄(只允许 ageRange,且为可选) +- 性别 +- 收入 +- 精确位置(只用 timezone offset) +- 设备标识符(只用 phone/tablet/desktop/web 类别) + +### 4.3 优先级体系 + +``` +Level 0: 隐私授权 / 安全 / 合规 ← 不可覆盖 +Level 1: 用户明确设置 ← AI 必须遵守 +Level 2: 学习目标和任务类型 +Level 3: 测评结果 +Level 4: 学习行为信号 +Level 5: 内容结构 +Level 6: 设备与当前场景 +Level 7: 用户画像辅助字段 +Level 8: AI 自己的推断 +``` + +### 4.4 设备信息限制 + +设备信息(phone / tablet / desktop / web)只能用于调整任务形式: + +| 设备 | 适合任务 | 不适合任务 | +|------|---------|-----------| +| phone | 卡片、判断、单选、短复习 | 复杂题组、长文阅读 | +| tablet | 阅读、标注、笔记、轻量题组 | — | +| desktop/web | 深度学习、复杂题组、资料整理 | — | + +**设备信息不得用于判断学习能力。** + +### 4.5 年龄段限制 + +`ageRange` 只能作为辅助字段。不得根据年龄判断学习能力、智力水平或学习速度。`unknown` 是合法值。 + +## 5. Snapshot 过滤规则 + +Snapshot Builder 必须执行: + +```typescript +function buildSnapshot(userId: string, targetType: string, targetId: string): Snapshot { + const settings = getUserAiSettings(userId); + const profile = getUserLearningProfile(userId); + + return { + // 硬约束 + constraints: { + dailyAvailableMinutes: profile?.dailyAvailableMinutes ?? null, + qualityPreference: profile?.qualityPreference ?? 'standard', + learningGoal: profile?.learningGoal ?? null, + }, + + // 授权过滤 + privacyScope: { + allowDocumentContent: settings?.allowUseDocumentContent ?? false, + allowLearningBehavior: settings?.allowUseLearningBehavior ?? true, + allowUserProfile: settings?.allowUseUserProfile ?? true, + }, + + // 仅包含授权的数据 + userProfile: settings?.allowUseUserProfile ? pickSafeFields(profile) : undefined, + learningBehaviorSummary: settings?.allowUseLearningBehavior ? aggregateBehavior(userId, targetType, targetId) : undefined, + materialProgressSummary: aggregateProgress(userId, targetType, targetId), + + // 资料原文仅当授权 + contentStructureSummary: settings?.allowUseDocumentContent ? aggregateContent(targetType, targetId) : undefined, + + // 明确标注哪些字段可发送模型 + allowedModelFields: buildAllowedFields(settings, profile), + + // 设备上下文 + deviceContext: buildDeviceContext(), + + // 评分信号 + scoreSignals: calculateScores(userId, targetType, targetId), + + // 行为信号(仅当授权) + behaviorSignals: settings?.allowUseLearningBehavior ? calculateBehaviorSignals(userId, targetType, targetId) : undefined, + }; +} +``` + +### `pickSafeFields` + +从 UserLearningProfile 中只挑选安全字段: +- `learningGoal`, `currentLevel`, `qualityPreference` +- `ageRange`(仅辅助),`preferredLanguage` +- 排除:`dailyAvailableMinutes`(进 constraints,不直接进 profile) +- 排除:`occupation`(除非用户明确同意) + +## 6. DeepSeek Prompt 发送规则 + +Prompt Render(Rust Runtime 侧)只发送 `Snapshot.allowedModelFields` 中列出的字段。未授权字段不在 Snapshot 中出现或标记为未授权。 + +## 7. 验收清单 + +- [x] 输出 AI 数据权限设计文档 +- [x] 明确哪些字段必填、建议填写、可选 +- [x] 明确哪些字段可发送给模型 +- [x] 明确用户关闭 AI 授权后的 API 行为 +- [x] 明确 Snapshot Builder 必须遵守授权 +- [x] 明确 Runtime 无权绕过 API 读取用户隐私数据 +- [x] 明确用户可删除自定义 key +- [x] 明确 Admin 不可查看用户 key 明文