# 记忆智能系统 PRD ## 概述 **功能名称**: 记忆智能 (Memory Intelligence) **版本**: v1.1 **优先级**: Phase 2.5 (体验增强后、社区化前) **目标用户**: 家长 + 3-8 岁儿童 **更新记录**: 2025-01-22 合并 `backend/docs/memory_system_prd.md` ### 核心愿景 将当前的"数据存储"升级为有温度的**"情感连接系统"**。 我们不只是在记住数据,而是在**维护孩子与故事世界的关系**。让每一个故事不再是孤立的碎片,而是构建孩子专属"故事宇宙"的砖瓦。 ### 核心价值 让 DreamWeaver 从"故事生成工具"进化为"懂孩子的故事伙伴": - **记住孩子**: 偏好、成长阶段、兴趣变化 - **延续故事**: 角色、世界观跨故事延续 - **主动关怀**: 适时推送个性化故事建议 ### 产品痛点与解决方案 | 用户角色 | 核心痛点 | 解决方案 | 预期价值 | |---------|---------|---------|---------| | **孩子** | "上次的小兔子怎么不认识我了?" 故事之间缺乏连续性。 | **角色一致性与记忆注入** 故事开头主动提及往事,角色性格延续。 | 建立情感依恋,提升沉浸感。 | | **家长** | "这App除了生成故事还能干嘛?" 无法感知产品的长期教育价值。 | **显性化成长轨迹** 词汇量统计、主题变化、成就徽章可视化。 | 提高付费意愿,提供社交货币。 | | **平台** | 用户用完即走,缺乏留存壁垒。 | **沉没成本与情感资产** 积累的记忆越多,越舍不得离开。 | 提升长期留存率 (LTV)。 | --- ## 一、功能模块 ### 1.0 记忆分层模型 #### 层级 1: 核心档案 (Identity Layer) *性质:永久、静态、显性* - **数据**: 姓名、年龄、性别 - **输入**: 家长在 Onboarding 阶段手动输入 - **作用**: 决定故事的基础适龄性和称呼 #### 层级 2: 故事宇宙 (Universe Layer) *性质:长期、动态积累、半显性* - **主角设定**: 姓名、性格特征(勇敢/害羞)、外貌特征(戴眼镜/卷发) - **常驻配角**: 从随机故事中涌现出的固定伙伴(如"爱吃胡萝卜的松鼠奇奇") - **世界观**: 故事发生的背景(魔法森林、未来城市、海底世界) - **成就系统**: 孩子获得的虚拟奖励(勇气勋章、小小探险家) #### 层级 3: 工作记忆 (Working Memory) *性质:短期、自动衰减、隐性* - **关键情节**: 最近 3 个故事的结局和核心冲突 - **情感标记**: 孩子对特定内容的反应(根据"重播"、"跳过"推断) - **新学词汇**: 故事中出现的高级词汇 ### 1.1 孩子档案系统 (Child Profile) | 字段 | 类型 | 说明 | |------|------|------| | 基础信息 | 显式 | 姓名、年龄、性别 | | 兴趣标签 | 显式+隐式 | 恐龙、公主、太空、动物等 | | 成长主题 | 显式 | 当前关注:勇气/分享/独立等 | | 阅读偏好 | 隐式 | 故事长度、风格、复杂度 | | 互动历史 | 隐式 | 喜欢的故事、跳过的故事 | **数据来源**: - 显式: 家长主动填写 - 隐式: 系统从使用行为中学习 ### 1.2 故事宇宙记忆 (Story Universe) 跨故事保持连续性的元素: | 元素 | 说明 | 示例 | |------|------|------| | 主角设定 | 孩子的故事化身 | "小明是个爱冒险的男孩" | | 常驻角色 | 反复出现的配角 | 魔法猫咪"星星"、智慧老树 | | 世界观 | 故事发生的宇宙 | 梦幻森林、星际学院 | | 成就系统 | 主角的成长轨迹 | "学会了勇敢"、"交到新朋友" | **记忆结构字段**: - `protagonist` / `recurring_characters` / `world_settings` / `achievements`(JSON 结构) - “延续上一个故事”默认选最近更新的宇宙(按 `updated_at` 倒序) ### 1.3 主动推送系统 (Proactive Push) | 触发类型 | 条件 | 推送内容 | |----------|------|----------| | 时间触发 | 睡前时段 (19:00-21:00) | "今晚想听什么故事?" | | 事件触发 | 节日/生日 | 主题故事推荐 | | 行为触发 | 3天未使用 | 召回提醒 | | 成长触发 | 年龄变化 | 难度升级建议 | **优先级与抑制**: - 优先级:事件 > 成长 > 行为 > 时间 - 抑制:当天已推送不再触发;静默时段(21:00-09:00)延迟;用户关闭推送则不触发 --- ## 二、用户故事 ### US-1: 创建孩子档案 ``` 作为家长 我想要创建孩子的专属档案 以便系统生成更适合孩子的故事 ``` **验收标准**: - [ ] 可填写孩子基础信息(姓名、年龄、性别) - [ ] 可选择兴趣标签(多选) - [ ] 可设置当前成长主题 - [ ] 支持多个孩子档案切换 ### US-2: 故事角色延续 ``` 作为家长 我想要故事中的角色能在新故事中再次出现 以便孩子感受到故事的连续性 ``` **验收标准**: - [ ] 生成故事时可选择"延续上一个故事" - [ ] 系统自动带入主角设定和常驻角色 - [ ] 新故事引用之前的"成就" ### US-3: 睡前故事提醒 ``` 作为家长 我想要在睡前时段收到故事推荐 以便养成固定的亲子阅读习惯 ``` **验收标准**: - [ ] 可设置提醒时间 - [ ] 推送包含个性化故事建议 - [ ] 可一键进入故事生成 --- ## 三、数据模型 ### 3.1 孩子档案表 (child_profiles) ```sql CREATE TABLE child_profiles ( id UUID PRIMARY KEY, user_id UUID REFERENCES users(id), name VARCHAR(50) NOT NULL, birth_date DATE, gender VARCHAR(10), interests JSONB DEFAULT '[]', growth_themes JSONB DEFAULT '[]', reading_preferences JSONB DEFAULT '{}', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); ``` ### 3.2 故事宇宙表 (story_universes) ```sql CREATE TABLE story_universes ( id UUID PRIMARY KEY, child_profile_id UUID REFERENCES child_profiles(id), name VARCHAR(100) NOT NULL, protagonist JSONB NOT NULL, recurring_characters JSONB DEFAULT '[]', world_settings JSONB DEFAULT '{}', achievements JSONB DEFAULT '[]', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); ``` ### 3.3 推送配置表 (push_configs) ```sql CREATE TABLE push_configs ( id UUID PRIMARY KEY, user_id UUID REFERENCES users(id), child_profile_id UUID REFERENCES child_profiles(id), push_time TIME, push_days INTEGER[], -- 0-6 表示周日到周六 enabled BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT NOW() ); ``` ### 3.4 推送事件表 (push_events) ```sql CREATE TABLE push_events ( id UUID PRIMARY KEY, user_id UUID NOT NULL, child_profile_id UUID NOT NULL, trigger_type VARCHAR(20) NOT NULL, -- time/event/behavior/growth sent_at TIMESTAMP NOT NULL, status VARCHAR(20) NOT NULL, -- sent/failed/suppressed reason TEXT ); ``` ### 3.5 记忆条目表 (memory_items) 用于存储“可解释、可控”的记忆条目(兴趣偏好、成长主题、常驻角色、关键事件等),并支持时序衰减。 ```sql CREATE TABLE memory_items ( id UUID PRIMARY KEY, child_profile_id UUID NOT NULL, universe_id UUID, type VARCHAR(50) NOT NULL, -- interest/growth/character/event等 value JSONB NOT NULL, -- 结构化内容 base_weight FLOAT DEFAULT 1.0, -- 初始权重 last_used_at TIMESTAMP, -- 最近使用时间 created_at TIMESTAMP DEFAULT NOW(), ttl_days INTEGER -- 可选:过期天数 ); ``` --- ## 四、API 设计 ### 4.1 孩子档案 API | 方法 | 路径 | 说明 | |------|------|------| | GET | `/api/profiles` | 获取当前用户的所有孩子档案 | | POST | `/api/profiles` | 创建孩子档案 | | GET | `/api/profiles/{id}` | 获取单个档案详情 | | PUT | `/api/profiles/{id}` | 更新档案 | | DELETE | `/api/profiles/{id}` | 删除档案 | ### 4.2 故事宇宙 API | 方法 | 路径 | 说明 | |------|------|------| | GET | `/api/profiles/{id}/universes` | 获取孩子的故事宇宙列表 | | POST | `/api/profiles/{id}/universes` | 创建新宇宙 | | GET | `/api/universes/{id}` | 获取宇宙详情 | | PUT | `/api/universes/{id}` | 更新宇宙设定 | | POST | `/api/universes/{id}/achievements` | 添加成就 | ### 4.3 推送配置 API | 方法 | 路径 | 说明 | |------|------|------| | GET | `/api/push-configs` | 获取推送配置 | | PUT | `/api/push-configs` | 更新推送配置 | --- ## 五、Prompt 工程 ### 5.1 带记忆的故事生成 Prompt ``` 你是一个专业的儿童故事作家。请为以下孩子创作一个故事: 【孩子档案】 - 姓名: {child_name} - 年龄: {age}岁 - 兴趣: {interests} - 当前成长主题: {growth_theme} 【故事宇宙】 - 主角设定: {protagonist} - 常驻角色: {recurring_characters} - 世界观: {world_settings} - 已获成就: {achievements} 【本次创作要求】 - 关键词: {keywords} - 延续之前的故事世界观 - 让主角在故事中有新的成长 请创作一个适合{age}岁儿童的故事,约{word_count}字。 ``` ### 5.2 智能开场白 (Memory Injection) 在生成新故事时,Prompt 必须包含一段"记忆唤醒"指令: - **示例**: "小明,还记得上周我们帮小松鼠找回了松果吗?今天,小松鼠带来了一位新朋友..." - **策略**: 提取权重最高的 Top 3 记忆注入 Prompt ### 5.3 成就提取 Prompt ``` 请分析以下故事,提取主角获得的成长/成就: 【故事内容】 {story_content} 请以JSON格式返回: { "achievements": [ {"type": "勇气", "description": "克服了对黑暗的恐惧"}, {"type": "友谊", "description": "帮助了迷路的小兔子"} ] } ``` --- ## 六、前端设计 ### 6.1 孩子档案页面 ``` ┌─────────────────────────────────────┐ │ 我的宝贝 [+添加] │ ├─────────────────────────────────────┤ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │ 👦 │ │ 👧 │ │ + │ │ │ │小明 │ │小红 │ │添加 │ │ │ │5岁 │ │3岁 │ │ │ │ │ └─────┘ └─────┘ └─────┘ │ └─────────────────────────────────────┘ ``` ### 6.2 档案详情页 ``` ┌─────────────────────────────────────┐ │ ← 小明的档案 [编辑] │ ├─────────────────────────────────────┤ │ 基础信息 │ │ 姓名: 小明 年龄: 5岁 性别: 男 │ ├─────────────────────────────────────┤ │ 兴趣爱好 │ │ [恐龙] [太空] [机器人] │ ├─────────────────────────────────────┤ │ 成长主题 │ │ ○ 勇气 ● 分享 ○ 独立 ○ 友谊 │ ├─────────────────────────────────────┤ │ 故事宇宙 │ │ ┌─────────────────────────────┐ │ │ │ 🌟 星际冒险 │ │ │ │ 主角: 小明船长 │ │ │ │ 伙伴: 机器人小七、外星猫咪 │ │ │ │ 成就: 3个 │ │ │ └─────────────────────────────┘ │ └─────────────────────────────────────┘ ``` ### 6.3 故事生成时选择档案 ``` ┌─────────────────────────────────────┐ │ 为谁创作故事? │ ├─────────────────────────────────────┤ │ ● 小明 (5岁) │ │ ○ 小红 (3岁) │ │ ○ 不使用档案 │ ├─────────────────────────────────────┤ │ 选择故事宇宙 │ │ ● 星际冒险 (延续上次) │ │ ○ 创建新宇宙 │ ├─────────────────────────────────────┤ │ [下一步: 输入关键词] │ └─────────────────────────────────────┘ ``` --- ## 七、技术实现要点 ### 7.1 隐式偏好学习 ```python # 基于用户行为更新偏好 async def update_implicit_preferences( child_id: UUID, story: Story, interaction: Interaction # 完整阅读/跳过/重复播放 ): profile = await get_child_profile(child_id) if interaction == "completed": # 增加相关标签权重 for tag in story.tags: profile.reading_preferences[tag] = \ profile.reading_preferences.get(tag, 0) + 1 elif interaction == "skipped": # 降低相关标签权重 for tag in story.tags: profile.reading_preferences[tag] = \ profile.reading_preferences.get(tag, 0) - 0.5 ``` ### 7.2 成就自动提取 故事生成完成后,异步调用 LLM 提取成就(以 `type + description` 去重): ```python @celery.task async def extract_achievements(story_id: UUID, universe_id: UUID): story = await get_story(story_id) universe = await get_universe(universe_id) achievements = await llm.extract_achievements(story.content) universe.achievements.extend(achievements) await save_universe(universe) ``` ### 7.3 推送调度 使用 Celery Beat 定时检查推送: ```python @celery.task def check_push_notifications(): current_time = datetime.now().time() current_day = datetime.now().weekday() configs = PushConfig.query.filter( PushConfig.enabled == True, PushConfig.push_time <= current_time, current_day.in_(PushConfig.push_days) ).all() for config in configs: send_push_notification.delay(config.user_id, config.child_profile_id) ``` **执行约束**: - 同一孩子每天最多 1 次推送 - 推送前查询 `push_events` 去重,成功/抑制均需记录 ### 7.4 时序衰减与记忆评分 **目标**:让“越新的记忆影响越大”,避免旧偏好长期干扰。 **默认实现(推荐)**:查询时动态计算分数,不直接修改数据库。 - 记忆分数:`score = base_weight × decay(Δt)` - 衰减示例(分段):0-7 天 1.0,8-30 天 0.7,31-90 天 0.4,90 天后 0.2 - 读取时按 `score` 排序,选 Top N 进入 Prompt **可选实现**:定期批处理降权 - 每日/每周批量更新 `base_weight` - 适合数据量大、读多写少的场景 **RAG 场景的衰减用法**: - 语义相似度分数 × 时间衰减 - 可加时间窗口过滤(如仅取最近 90 天) **删除策略(默认不删)**: - 默认只降权,不主动删除 - 可选:对低权重且 180 天未使用的条目执行 TTL 清理 --- ## 八、关键功能特性 ### 8.1 成长时间轴 (Growth Timeline) 一个可视化的 H5 页面或 App 模块,以时间轴形式展示里程碑: - 🌟 **初次相遇**: 创建角色的第一天 - 📖 **阅读打卡**: 累计阅读 10/50/100 本 - 🏅 **获得成就**: 获得"诚实勋章" - 🧠 **能力解锁**: 第一次阅读"科幻"题材 ### 8.2 成就仪式感 (Achievement Ceremony) - **触发**: 故事生成并分析后,如果获得新成就 - **表现**: 弹窗动画 + 音效 + "恭喜获得 [勇气] 徽章" - **分享**: 允许生成带二维码的成就海报 --- ## 九、记忆类型扩展 | 类型 Key | 描述 | 来源 | 过期策略 | |---------|------|------|---------| | `recent_story` | 最近读过的故事梗概 | 阅读事件 | 30天衰减 | | `favorite_character` | 孩子喜欢的角色 | 重播/高评分 | 长期有效 | | `scary_element` | 孩子害怕/不喜欢的元素 | 跳过/负反馈 | 长期有效 (避雷) | | `vocabulary_growth` | 新掌握的词汇 | 故事分析 | 90天衰减 | | `emotional_highlight` | 高光时刻 (如: 特别开心的情节) | 互动数据 | 60天衰减 | --- ## 十、里程碑 ### Phase 1: 基础建设 (v0.3.0) - [x] 数据库 `MemoryItem` 表 (已存在) - [ ] 扩展 `MemoryItem` 类型字段,支持更多维度 - [ ] 优化 `_build_memory_context`,支持更自然的 Prompt 注入 - [ ] 前端:简单的"近期回忆"展示列表 ### M1: 孩子档案基础 - [ ] 数据库模型 - [ ] CRUD API - [ ] 前端档案管理页面 - [ ] 故事生成时选择档案 ### M2: 故事宇宙 - [ ] 宇宙数据模型 - [ ] Prompt 集成 - [ ] 成就自动提取 - [ ] 前端宇宙管理 ### M3: 主动推送 - [ ] 推送配置 API - [ ] Celery Beat 调度 - [ ] 推送通知集成 (Web Push / 微信) ### M4: 隐式学习 - [ ] 行为埋点 - [ ] 偏好学习算法 - [ ] 推荐优化 ### Phase 2: 可视化与成就 (v0.4.0) - [ ] 实现"成就提取器" (Achievement Extractor) 的闭环通知 - [ ] 前端:开发"我的成就"和"成长时间轴"页面 - [ ] 增加故事开场白的动态生成逻辑 ### Phase 3: 深度智能 (v0.5.0+) - [ ] 引入向量数据库,实现基于语义的记忆检索 (不仅是时间最近) - [ ] 情感分析模型:分析用户行为推断情感倾向 --- ## 十一、风险与应对 | 风险 | 影响 | 应对 | |------|------|------| | 隐私合规 | 高 | 儿童数据加密存储,家长授权机制 | | 推送骚扰 | 中 | 默认关闭,用户主动开启 | | 记忆膨胀 | 低 | 定期清理旧数据,限制宇宙数量 | --- ## 十二、相关文档 - [孩子档案数据模型](./CHILD-PROFILE-MODEL.md) - [故事宇宙记忆结构](./STORY-UNIVERSE-MODEL.md) - [主动推送触发规则](./PUSH-TRIGGER-RULES.md)