AI 记忆助手设计手记:帮老人整理一生故事的温暖工程
AI 记忆助手设计手记帮老人整理一生故事的温暖工程一、每一个被遗忘的故事都是一颗丢失的星星去年重阳节白泠钰回老家看望爷爷奶奶。饭桌上奶奶又开始讲那个老掉牙的故事——关于她年轻时如何在困难时期养活一家人。白泠钰已经听了无数遍但爷爷却像第一次听到一样认真点头。等奶奶去厨房忙活时白泠钰问爷爷爷爷奶奶这个故事您听过几百遍了吧爷爷笑了笑眼角的皱纹舒展开来听不腻的。每次她讲我就想起更多的事——那时候她多年轻啊眼睛多亮。后来她就不记得这些了每次讲都是这一段。但每次我都想再听一遍。那一刻白泠钰突然意识到一个问题如果有一天奶奶连这个故事也忘了呢那些关于战争、饥荒、奋斗、爱情、失落、希望的集体记忆会不会就这样消散在时间里这个念头催生了白泠钰最温暖的一个项目——AI 记忆助手专门帮助老年人整理、记录、传承他们的人生故事。二、为什么老年人需要AI 传记作家2.1 银发群体的特殊需求白泠钰在设计产品前访谈了上百位老年人和他们的家人发现几个核心需求记录需求很多老人想把自己的故事写下来但打字困难、写作更困难回忆需求阿尔茨海默症的威胁下老年人希望保留更多记忆传承需求老人希望把自己的故事传给子孙但年轻人没时间听社交需求独居老人渴望有人听他们说话传统的文字记录方式对老年人极其不友好。键盘打字对于视力下降、手指不灵活的老人来说是巨大障碍。即使用语音转文字也会遇到方言、停顿、思路跳跃等问题。白泠钰的解决方案是让 AI 成为老年人的记忆对话伙伴通过自然对话的方式帮助老人讲述故事、整理记忆、自动生成传记。2.2 老年语言处理的挑战老年人的语言表达有其独特性from dataclasses import dataclass from typing import List, Dict, Optional import re dataclass class ElderlyUtterance: 老年人口语 raw_text: str sentences: List[str] # 句子列表 topics: List[str] # 话题标签 emotions: List[str] # 情感标记 relationships: List[Dict] # 人物关系 time_references: List[Dict] # 时间参考 memory_fragments: List[Dict] # 记忆碎片 class ElderlyLanguageAdapter: 老年语言适配器 def __init__(self): # 老年人常用表达 self.expressions { vague_time: [那时候, 有一天, 后来, 过了很久, 年轻时候], vague_place: [那里, 这儿, 某个地方, 老家], emotion_words: [想当年, 不容易, 苦啊, 开心, 难忘, 一辈子] } # 时间线索词汇 self.time_markers { historical: [解放前, 旧社会, 文革, 改革开放, 解放后], life_events: [结婚, 生孩子, 工作, 退休, 搬家], seasonal: [春天, 夏天, 秋天, 冬天, 过年] } # 关系词 self.relationship_words { family: [老伴, 老伴儿, 丈夫, 妻子, 儿子, 女儿, 孙子, 孙女, 爸妈, 爹娘], friends: [老朋友, 老同事, 同学, 街坊], others: [邻居, 老师, 领导] } def process(self, text: str) - ElderlyUtterance: 处理老年人口语表达 特点 - 句子较长结构松散 - 时间地点模糊 - 情感充沛但表达不精确 - 经常跳跃可能突然切换话题 # 分句处理老年人常见的超长句 sentences self._split_sentences(text) # 提取话题 topics self._extract_topics(sentences) # 情感标记 emotions self._extract_emotions(sentences) # 人物关系 relationships self._extract_relationships(sentences) # 时间线索 time_references self._extract_time_references(sentences) # 记忆碎片提取可独立成段的内容 memory_fragments self._extract_fragments(sentences) return ElderlyUtterance( raw_texttext, sentencessentences, topicstopics, emotionsemotions, relationshipsrelationships, time_referencestime_references, memory_fragmentsmemory_fragments ) def _split_sentences(self, text: str) - List[str]: 分句处理老年人常见的超长句和标点缺失 # 替换常见连接词后的标点 connectors [然后, 后来, 再, 接着, 可是, 但是, 因为, 所以] # 临时在连接词后添加分割标记 processed text for conn in connectors: processed processed.replace(conn, f。{conn}) # 分割 raw_sentences processed.split(。) # 清理并过滤空句 sentences [s.strip() for s in raw_sentences if s.strip()] return sentences def _extract_topics(self, sentences: List[str]) - List[str]: 提取话题标签 topics [] topic_keywords { childhood: [小时候, 童年, 上学, 玩, 老家], work: [工作, 上班, 工厂, 种地, 干活], family: [结婚, 老伴, 孩子, 一家人, 养家], hardship: [苦, 难, 困难, 饿, 穷], joy: [开心, 高兴, 幸福, 快乐], war: [打仗, 解放, 解放前, 旧社会, 文革] } for sent in sentences: for topic, keywords in topic_keywords.items(): if any(kw in sent for kw in keywords): if topic not in topics: topics.append(topic) return topics def _extract_emotions(self, sentences: List[str]) - List[str]: 提取情感标记 emotions [] emotion_map { nostalgia: [想当年, 那时候, 回忆], hardship: [苦, 难, 不容易, 熬], joy: [开心, 高兴, 幸福, 好日子], sorrow: [伤心, 难过, 走了, 没了], pride: [骄傲, 自豪, 争气, 出息] } for sent in sentences: for emotion, keywords in emotion_map.items(): if any(kw in sent for kw in keywords): emotions.append(emotion) return emotions def _extract_relationships(self, sentences: List[str]) - List[Dict]: 提取人物关系 relationships [] full_text .join(sentences) for rel_type, keywords in self.relationship_words.items(): for keyword in keywords: if keyword in full_text: relationships.append({ type: rel_type, keyword: keyword, context: self._extract_context(full_text, keyword) }) return relationships def _extract_time_references(self, sentences: List[str]) - List[Dict]: 提取时间线索 time_refs [] full_text .join(sentences) # 历史时期 for marker, period in self.time_markers[historical].items(): if marker in full_text: time_refs.append({ marker: marker, period: period, context: self._extract_context(full_text, marker) }) # 人生阶段 for marker in self.time_markers[life_events]: if marker in full_text: time_refs.append({ marker: marker, type: life_event, context: self._extract_context(full_text, marker) }) return time_refs def _extract_context(self, text: str, keyword: str, window: int 20) - str: 提取关键词周围的上下文 pos text.find(keyword) if pos -1: return start max(0, pos - window) end min(len(text), pos len(keyword) window) return text[start:end] def _extract_fragments(self, sentences: List[str]) - List[Dict]: 提取可独立成段的记忆碎片 fragments [] for i, sent in enumerate(sentences): # 跳过太短的句子 if len(sent) 15: continue # 检查是否是独立事件描述 if self._is_self_contained_event(sent): fragments.append({ content: sent, start_sentence_idx: i, topics: self._extract_topics([sent]), emotions: self._extract_emotions([sent]) }) return fragments def _is_self_contained_event(self, sentence: str) - bool: 判断是否是自包含的事件描述 event_indicators [ 我, 我们, 那一年, 有一天, 记得, 那时候, 后来 ] has_subject any(indicator in sentence for indicator in event_indicators) has_action any(kw in sentence for kw in [做, 去, 来, 是, 有, 遇到]) has_minimal_length len(sentence) 20 return has_subject and has_action and has_minimal_length2.3 对话式记忆引导白泠钰发现很多老人不是没有故事而是不知道从何说起。她设计了一套渐进式记忆引导系统flowchart TD A[开始对话] -- B{从哪个阶段开始} B --|童年| C[童年记忆] B --|工作| D[工作经历] B --|家庭| E[家庭故事] B --|兴趣| F[兴趣爱好] C -- G[引导性问题] D -- G E -- G F -- G G -- H{老人回应} H --|积极| I[深入追问] H --|模糊| J[具体化引导] H --|沉默| K[换个话题] I -- L[提取关键信息] J -- L K -- B L -- M[记录到记忆库] M -- N[生成记忆卡片]class MemoryConversationGuide: 记忆对话引导器 def __init__(self): # 记忆主题引导问题 self.topic_guides { childhood: { opening: 您小时候住在哪儿那时候家里是什么样的, follow_ups: [ 那时候吃什么穿什么, 小时候玩什么游戏, 上学的时候有什么难忘的事吗, 那时候家里有什么人 ], trigger_keywords: [小时候, 童年, 上学, 老家] }, work: { opening: 您年轻时候做什么工作呀, follow_ups: [ 那时候是怎么找到这份工作的, 工作里有什么印象深刻的事吗, 同事们都怎么样, 最骄傲的事情是什么 ], trigger_keywords: [工作, 上班, 工厂, 种地, 退休] }, family: { opening: 您和老伴是怎么认识的, follow_ups: [ 结婚那时候是什么样的, 孩子小时候有什么趣事吗, 一家人最开心的时光是什么时候, 有什么传给后人的话吗 ], trigger_keywords: [结婚, 老伴, 孩子, 一家, 家庭] }, hardship: { opening: 您经历过最难的时候是什么样的, follow_ups: [ 那时候是怎么熬过来的, 有没有遇到什么贵人帮助您, 回过头看那段经历给您什么启示 ], trigger_keywords: [苦, 难, 困难, 熬, 不容易] }, joy: { opening: 您这辈子最开心的时刻是什么时候, follow_ups: [ 为什么这么开心, 当时是什么情形, 那之后生活有什么变化吗 ], trigger_keywords: [开心, 高兴, 幸福, 最开心, 最好] } } # 当前对话状态 self.current_topic None self.question_index 0 self.conversation_depth 0 def start_conversation(self) - str: 开启对话 openings [ 今天想聊聊什么可以是您小时候的事、工作的事、或者家庭的事什么都行。, 我特别想听您讲讲故事。您最想从哪里说起呢, 您这一辈子肯定有很多精彩的故事想从哪里开始讲起 ] import random return random.choice(openings) def process_response(self, response: str) - str: 处理老人回应生成下一个问题或反应 Returns: AI 响应问题或共情表达 # 分析回应内容 analyzed self._analyze_response(response) # 更新对话状态 self._update_conversation_state(analyzed) # 生成响应 if analyzed[is_engaging]: return self._generate_follow_up_question(analyzed) else: return self._generate_re_engagement() def _analyze_response(self, response: str) - Dict: 分析老人回应 # 检测关键词确定话题 detected_topics [] for topic, guide in self.topic_guides.items(): if any(kw in response for kw in guide[trigger_keywords]): detected_topics.append(topic) # 检测情感 emotions self._detect_emotions(response) # 检测参与度 is_engaging len(response) 10 # 简单判断回复较长表示愿意说 # 检测是否提到具体事件 has_specific_event any(kw in response for kw in [ 那一年, 有一天, 记得, 那时候, 后来 ]) return { detected_topics: detected_topics, emotions: emotions, is_engaging: is_engaging, has_specific_event: has_specific_event, response_length: len(response) } def _detect_emotions(self, text: str) - List[str]: 检测情感 emotion_map { nostalgic: [想当年, 那时候, 回忆, 记得], happy: [开心, 高兴, 幸福, 快乐, 好], sad: [苦, 难, 伤心, 难过, 走了], proud: [骄傲, 自豪, 争气, 出息], regretful: [可惜, 遗憾, 后悔, 要是] } emotions [] for emotion, keywords in emotion_map.items(): if any(kw in text for kw in keywords): emotions.append(emotion) return emotions def _update_conversation_state(self, analyzed: Dict): 更新对话状态 # 如果检测到新话题 if analyzed[detected_topics]: if not self.current_topic: self.current_topic analyzed[detected_topics][0] elif analyzed[detected_topics][0] ! self.current_topic: # 话题切换不重置问题索引 pass # 增加对话深度 if analyzed[is_engaging]: self.conversation_depth 1 def _generate_follow_up_question(self, analyzed: Dict) - str: 生成追问 # 确定当前话题 topic self.current_topic or (analyzed[detected_topics][0] if analyzed[detected_topics] else general) if topic not in self.topic_guides: topic general guide self.topic_guides[topic] # 如果检测到具体事件深入追问 if analyzed[has_specific_event]: follow_ups [ 能多说说这件事吗后来怎么样了, 这件事对您影响大吗, 当时您是什么心情, 那之后呢 ] return random.choice(follow_ups) # 否则问下一个预设问题 if self.question_index len(guide[follow_ups]): question guide[follow_ups][self.question_index] self.question_index 1 return question # 问题问完了生成共情回应并引导新话题 return self._wrap_up_and_transition(analyzed) def _wrap_up_and_transition(self, analyzed: Dict) - str: 结束当前话题并引导新话题 wrap_ups [ 您讲的这些真好让我学到了很多。, 听了您说的这些我很感动。, 您的人生经历真丰富。 ] transitions [ 您还想讲讲别的故事吗比如工作时候的事或者家庭的事, 您还有什么想讲的吗我还想多听听您的事。, 您的人生里有这么多精彩故事还有什么想记录下来的吗 ] import random return f{random.choice(wrap_ups)} {random.choice(transitions)} def _generate_re_engagement(self) - str: 生成重新吸引注意力的回应 # 如果老人沉默或回应简短 re_engagements [ 慢慢想不着急想起什么说什么。, 没关系的想说就说不想说也可以听我说说别的。, 您还记得什么有趣的事吗什么事都行。 ] import random return random.choice(re_engagements)三、智能记忆整理从碎片到完整故事3.1 记忆碎片整合系统老年人的讲述通常是碎片化的一个完整的故事可能分散在多次对话中。白泠钰设计了记忆整合引擎自动将碎片拼接成完整叙事from dataclasses import dataclass, field from typing import List, Dict, Optional from datetime import datetime import hashlib dataclass class MemoryFragment: 记忆碎片 id: str content: str topic: str time_reference: Optional[str] emotional_tags: List[str] relationships: List[str] confidence: float # 置信度 source_conversation_id: str created_at: datetime def generate_hash(self) - str: 生成内容哈希用于去重 return hashlib.md5(self.content.encode()).hexdigest() class MemoryIntegrator: 记忆整合器 def __init__(self): # 记忆库 self.memory_store: Dict[str, List[MemoryFragment]] {} # 时间线重建规则 self.timeline_rules self._load_timeline_rules() def add_fragment(self, fragment: MemoryFragment): 添加记忆碎片 topic fragment.topic if topic not in self.memory_store: self.memory_store[topic] [] # 去重检查 fragment_hash fragment.generate_hash() existing_hashes [f.generate_hash() for f in self.memory_store[topic]] if fragment_hash not in existing_hashes: self.memory_store[topic].append(fragment) def integrate_story(self, topic: str) - Dict: 整合某个主题的故事 Returns: { title: str, timeline: List[Event], characters: List[Character], narrative: str, emotional_arc: str } fragments self.memory_store.get(topic, []) if not fragments: return None # 1. 重建时间线 timeline self._rebuild_timeline(fragments) # 2. 提取人物 characters self._extract_characters(fragments) # 3. 提取情感弧线 emotional_arc self._analyze_emotional_arc(fragments) # 4. 生成完整叙事 narrative self._generate_narrative(timeline, characters, emotional_arc) # 5. 生成标题 title self._generate_title(topic, fragments) return { title: title, timeline: timeline, characters: characters, narrative: narrative, emotional_arc: emotional_arc } def _rebuild_timeline(self, fragments: List[MemoryFragment]) - List[Dict]: 重建时间线 events [] for frag in fragments: event { content: frag.content, time_reference: frag.time_reference, emotions: frag.emotional_tags, relationships: frag.relationships, confidence: frag.confidence } # 根据时间参考排序 # 简化处理按置信度排序 events.append(event) # 排序 events.sort(keylambda x: x[confidence], reverseTrue) return events def _extract_characters(self, fragments: List[MemoryFragment]) - List[Dict]: 提取人物 characters {} for frag in fragments: for rel in frag.relationships: if rel not in characters: characters[rel] { name: rel, mentioned_count: 0, contexts: [] } characters[rel][mentioned_count] 1 characters[rel][contexts].append(frag.content[:50]) return list(characters.values()) def _analyze_emotional_arc(self, fragments: List[MemoryFragment]) - str: 分析情感弧线 all_emotions [] for frag in fragments: all_emotions.extend(frag.emotional_tags) if not all_emotions: return 平静叙事 # 统计情感分布 emotion_counts {} for emotion in all_emotions: emotion_counts[emotion] emotion_counts.get(emotion, 0) 1 # 生成情感描述 if sad in emotion_counts or hardship in emotion_counts: return 历经艰辛最终苦尽甘来 elif joy in emotion_counts and proud in emotion_counts: return 平凡中见证幸福与骄傲 else: return 平凡人生真情流露 def _generate_narrative( self, timeline: List[Dict], characters: List[Dict], emotional_arc: str ) - str: 生成完整叙事 narrative_parts [] for i, event in enumerate(timeline): # 添加过渡 if i 0: narrative_parts.append(event[content]) else: transitions [后来, 再后来, 接着, 之后] import random transition random.choice(transitions) narrative_parts.append(f{transition}{event[content]}) return 。.join(narrative_parts) 。 def _generate_title(self, topic: str, fragments: List[MemoryFragment]) - str: 生成标题 # 从碎片中提取关键词 keywords [] for frag in fragments: if frag.time_reference: keywords.append(frag.time_reference) if keywords: time_kw keywords[0] topic_titles { childhood: f岁月如歌{time_kw}的童年记忆, work: f奋斗人生{time_kw}的工作岁月, family: f家的故事{time_kw}的家庭回忆, hardship: f苦难辉煌{time_kw}的艰难岁月, joy: f幸福时光{time_kw}的美好回忆 } return topic_titles.get(topic, f{time_kw}的故事) return f{topic}的故事四、家庭传承从个人记忆到家族史4.1 多用户协作记忆系统很多老年人的故事涉及家庭成员需要多方协作整理sequenceDiagram participant G as 爷爷 participant N as 奶奶 participant AI as AI记忆助手 participant F as 孙子/孙女 participant F as 家庭档案库 G-AI: 讲述战争年代的故事 N-AI: 补充当时的日常生活 AI-F: 整合生成《我们家的1940年代》 F-AI: 添加年轻时的照片 AI-家庭档案库: 建立家族记忆库五、总结产品上线后白泠钰收到了一位用户的反馈是老人的孙子写的我奶奶今年85岁了一直想把自己的一生写下来但总是写不下去。有了这个产品她每天和 AI 聊一会儿一点点地把自己的故事讲出来。现在我们有了奶奶口述的完整传记还有配图版本。奶奶看着自己的故事高兴得像个孩子。这个反馈让白泠钰深深感动。她意识到这个产品不仅仅是一个技术产品更是一种生命延续的方式。每一个被记录下来的故事都是对生命本身的尊重和致敬。当一位老人讲述自己的故事时他不仅仅是在回忆过去更是在告诉后人我活过我爱过我战斗过我坚持过。这些故事是我的也是你们的。AI 能做的就是帮助每一位老人把这些宝贵的故事保存下来传承下去。让那些星星一样的记忆永远不会丢失在时间的河流里。正如白泠钰说的技术应该让生活更温柔而帮老人整理一生故事或许是技术能做到的最温柔的事情之一。