系列文章第 45 篇- 从陪伴人格注入到会话上下文回忆解密早上好背后多组件协同的惊喜体验 专栏信息《从零到一构建跨平台 AI 助手WeClaw 实战指南》专栏专栏定位面向开发者和技术决策者的实战专栏用真实案例和完整代码带你理解如何构建生产级 AI 应用本文是主动陪伴系统延伸篇将带您深入理解早上好惊喜这一用户体验背后的完整技术链路。‍ 作者与项目作者简介翁勇刚 WENG YONGGANG新概念龙虾-WeClaw 开发团队负责人一群专注于跨平台 AI 应用的实践者理念“让 AI 不只是被动工具更是主动关怀用户的生活伙伴” 项目地址https://github.com/wyg5208/weclaw.git 官网地址https://weclaw.link 作者 CSDNhttps://blog.csdn.net/yweng18⭐ 欢迎 Star⭐、Fork、贡献代码 摘要本文结构概览本文从用户一句早上好触发的惊喜回复现象出发逐层剖析背后的四层协同架构陪伴人格层COMPANION_PROMPT_MODULE、主动关怀层CompanionEngine CareTopic、每日任务推送层DailyTaskScheduler TaskAnalyzer、会话上下文记忆层Session ContextCompressor。通过完整代码解读和架构图揭示扫描昨天内容并非专门的扫描逻辑而是多组件各司其职、自然涌现的涌现行为。背景很多用户在使用 WeClaw 时发现当早上对 AI 说早上好系统不仅温暖地回应还能自然地引用昨天的对话内容甚至推送一份精心整理的每日任务清单。这种惊喜感是如何实现的核心问题如何在不增加额外扫描模块的前提下让 AI 在问候场景中自然地回顾历史、个性化回应解决方案四层架构协同——人格注入 主动关怀引擎 每日任务调度 会话上下文持久化各层独立运作最终在 LLM 推理时自然融合。关键成果4 个核心模块各司其职零额外扫描开销15 种关怀主题自动按时段评分触发凌晨 2 点离线分析 早上 7 点智能推送会话上下文支持 500 条消息 智能压缩适合读者有 Python 基础对 AI 助手设计、会话管理、事件驱动架构感兴趣的开发者阅读时长约 18 分钟关键词CompanionEngine、Session上下文、DailyTaskScheduler、COMPANION_PROMPT、主动关怀、涌现行为一、现象还原一句早上好背后的连锁反应1.1 场景重现用户的真实体验想象这个早晨场景用户打开 WeClaw说了一句早上好AI 回复“早上好呀昨天你提到了要准备周五的汇报材料今天要不要先列个大纲另外今天天气不错适合出去走走”紧跟着推送了一份 今日任务清单用户惊讶“它怎么知道昨天聊了什么它是怎么’扫描’昨天的内容的”1.2 真相没有扫描模块只有四层协同反直觉的事实WeClaw 代码中不存在任何早上好扫描昨天的专门模块。这个惊喜效果是四个独立层各司其职、自然融合的结果。┌─────────────────────────────────────────────────────────────────────┐ │ 用户说早上好 │ └───────────────────────────┬─────────────────────────────────────────┘ │ ┌───────────────────┼───────────────────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────────────┐ ┌──────────────────────┐ │ 第一层 │ │ 第二层 │ │ 第三层 │ │ 人格注入 │ │ 主动关怀引擎 │ │ 每日任务推送 │ │(始终生效) │ │(morning_greeting)│ │(DailyTaskScheduler) │ └────┬─────┘ └────────┬─────────┘ └──────────┬───────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────┐ │ 第四层会话上下文 │ │ session.messages含昨天的完整对话历史 │ └────────────────────────┬────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ LLM 推理融合 │ │ System Prompt(人格) 上下文(记忆) 用户输入(触发) │ │ → 生成引用昨天内容 温暖问候的个性化回复 │ └─────────────────────────────────────────────────────────┘核心洞察所谓扫描昨天不是扫描而是 LLM 通过 session 中天然存在的对话历史在人格 Prompt 的引导下自然地引用了过去的信息。这是一种涌现行为Emergent Behavior。1.3 为什么不用专门的晨间摘要模块初学者可能会想专门写一个早上扫描昨天对话、生成摘要、注入 Prompt的模块不是更可控吗答案是过度工程化会破坏 LLM 的自然推理能力。方案优点缺点专用晨间摘要模块可控性强额外 API 调用成本、延迟高、摘要可能丢失细节四层协同涌现零额外开销、自然流畅、信息完整回复质量依赖 LLM 能力RAG 检索历史精确可控架构复杂、检索质量不稳定WeClaw 选择了四层协同方案因为LLM 本身就有强大的上下文理解和回忆能力我们要做的是提供正确的上下文 恰当的引导。二、四层架构详解 —— 每一层做了什么2.1 第一层人格注入 —— COMPANION_PROMPT_MODULE核心思想始终在 System Prompt 中注入陪伴人格让 AI 以朋友而非客服的身份交流。┌─────────────────────────────────────────┐ │ CORE_SYSTEM_PROMPT │ │ 工具使用指南、规则、决策树 │ ├─────────────────────────────────────────┤ │ COMPANION_PROMPT_MODULE │ │ 始终注入陪伴人格 关怀规则 │ ├─────────────────────────────────────────┤ │ 按需模块assembly/mcp/pwa... │ ├─────────────────────────────────────────┤ │ 最终 System Prompt │ └─────────────────────────────────────────┘关键代码src/core/prompts.py# 主动陪伴模式 Prompt 模块 — 始终注入COMPANION_PROMPT_MODULE ## 主动陪伴模式 你具备主动关怀能力。当系统触发陪伴事件时你将以自然、温暖的方式与用户交流。 关键规则: - 语气亲切自然像朋友而非客服 - 已知信息不再重复询问善于从上下文推断 - 如果用户明显忙碌或不想聊礼貌退出 - 收集到的信息自动调用 user_profile 工具保存 - 语音模式下回复控制在30字以内 - 每次只关注一个话题不要同时追问多件事 构建流程build_system_prompt_from_intentdefbuild_system_prompt_from_intent(intent_result:IntentResult,request_source:strlocal)-str:parts[CORE_SYSTEM_PROMPT]# ✅ 关键始终注入陪伴模块 — 陪伴角色是 WeClaw 的核心身份parts.append(COMPANION_PROMPT_MODULE)# PWA 手机端特殊规则ifrequest_source.startswith(pwa:):parts.append(PWA_CONTEXT_PROMPT)# 按需注入 assembly/mcp 模块ifassemblyinintent_result.prompt_modules:parts.append(ASSEMBLY_TASK_PROMPT)ifmcpinintent_result.prompt_modules:parts.append(MCP_TOOL_GUIDE_PROMPT)result\n\n.join(parts)# 动态替换日期和项目根路径resultresult.replace({generated_date},today)resultresult.replace({project_root},project_root_escaped)returnresult为什么始终注入是关键因为无论用户说什么包括早上好COMPANION_PROMPT_MODULE 都在 System Prompt 中生效。它告诉 LLM“你是朋友善于从上下文推断”。这正是 LLM 主动引用昨天对话的驱动力。2.2 第二层主动关怀引擎 —— CompanionEngine核心思想预定义 15 种关怀主题通过七层评分系统智能决策何时触发什么关怀。┌─────────────────────────────────────────────────────┐ │ CompanionEngine │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌───────────┐ │ │ │CooldownManager│ │MoodDetector │ │Opportunity│ │ │ │(防骚扰冷却) │ │(情绪检测) │ │Detector │ │ │ │ │ │ │ │(时机检测) │ │ │ └──────┬───────┘ └──────┬───────┘ └─────┬─────┘ │ │ │ │ │ │ │ └─────────────────┼────────────────┘ │ │ ▼ │ │ ┌─────────────────────┐ │ │ │InteractionOrchestrator│ │ │ │(交互编排 EventBus) │ │ │ └─────────────────────┘ │ │ │ │ ┌──────────────────────────────────┐ │ │ │ CareTopicRegistry │ │ │ │ morning_greeting (早安问候) │ │ │ │ mood_check (心情关怀) │ │ │ │ health_checkin (健康打卡) │ │ │ │ birthday_remind (生日提醒) │ │ │ │ ... 15 种关怀主题 │ │ │ └──────────────────────────────────┘ │ └─────────────────────────────────────────────────────┘早安问候主题定义src/core/companion_topics.pyCareTopic(topic_idmorning_greeting,name早安问候,categorylifestyle,priority5,# 中等优先级min_interval_hours24,# 最少间隔 24 小时best_time_slots[morning],# 最佳时段早晨prompt_template早上好呀今天{weather_hint}{schedule_hint}有什么计划吗)七层评分算法calculate_interaction_scoredefcalculate_interaction_score(self,topic:CareTopic)-float:计算主题此刻的执行分数0-100。scoretopic.priority*10# 基础分优先级 × 10# 1. 时段匹配度 0~20ifcurrent_slotintopic.best_time_slots:score20# 2. 冷却期硬性检查不到24小时直接返回0ifhourstopic.min_interval_hours:return0# 3. 紧急度加成 0~30urgency_bonusmin((cooldown_ratio-1)*15,30)scoreurgency_bonus# 4. 特殊紧急情况如生日临近 30# 5. 用户空闲度 0~20空闲5分钟1015分钟10# 6. 情绪调节 ±15根据 MoodDetector 结果# 7. 每日预算检查配额用完则返回0returnmax(0,min(100,score))定时调度循环每 30 分钟扫描一次asyncdef_scheduler_loop(self)-None:whileTrue:awaitasyncio.sleep(30*60)# 每30分钟current_slotget_time_slot()# morning/afternoon/eveningtopicsself._topic_registry.get_by_time_slot(current_slot)fortopicintopics:scoreself.calculate_interaction_score(topic)ifscore30:# 超过阈值awaitself.on_cron_trigger(topic.topic_id)break# 每次只触发一个避免骚扰2.3 第三层每日任务推送 —— DailyTaskScheduler核心思想凌晨 2 点离线分析用户数据早上 7 点推送个性化任务清单。时间线 02:00 07:00 用户打开 │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │TaskAnalyzer│ │ 推送 │ │check_and_push │ │多维度分析 │────────→│ 任务 │ │_on_startup() │ │·待办事项 │ │ 清单 │ │启动时补推(6-10点) │ │·家庭成员 │ └──────────┘ └──────────────────┘ │·对话记录 │ │·健康数据 │ └──────────┘TaskAnalyzer 的四大分析维度src/core/task_analyzer.py任务智能分析引擎 — 多维度分析用户信息生成每日任务推荐。 分析维度 1. 待办事项分析 — 优先级排序、截止时间压力、时间周期匹配 2. 家庭成员关联分析 — 生日提醒、纪念日、子女课程接送 3. 对话记录分析 — NLP提取潜在任务、用户承诺事项 4. 健康与上下文分析 — 用药提醒、运动计划、天气影响 推送消息的格式化_format_recommendation_messagedef_format_recommendation_message(self,rec)-str:lines[f 今日任务清单{date}{weekday},]# 按来源分组显示ifoverdue_tasks:lines.append(⚠️ 过期任务)iftoday_tasks:lines.append( 今日到期)iffamily_tasks:lines.append(‍‍ 家庭相关)ifother_tasks:lines.append( 推荐任务)lines.append( 回复「确认任务」开始今日计划)return\n.join(lines)2.4 第四层会话上下文 —— Session ContextCompressor核心思想持久化存储完整对话历史LLM 自然具备回忆能力。┌──────────────────────────────────────────────┐ │ SessionManager │ │ │ │ Session { │ │ id: session_001 │ │ title: 关于周五汇报的讨论 │ │ messages: [ │ │ {role: user, content: 早上好}, │ ← 今天 │ {role: assistant, content: ...}, │ ← 今天 │ ─ ─ ─ ─ ─ 昨天 ─ ─ ─ ─ ─ │ │ {role: user, content: 帮我准备周五汇报},│ ← 昨天 │ {role: assistant, content: 好的...}, │ ← 昨天 │ ... │ │ ] │ │ } │ │ │ │ 最大消息数: 500 │ │ 压缩策略: 辅助LLM摘要早期消息 │ └──────────────────────────────────────────────┘会话持久化配置src/core/session.py# 默认最大消息数硬上限# 【v2.31.1 提升】100 → 500适配 DeepSeek 1M 等大上下文模型DEFAULT_MAX_MESSAGE_COUNT500dataclassclassSession:id:strtitle:str新对话created_at:datetimefield(default_factorydatetime.now)messages:list[dict[str,Any]]field(default_factorylist)关键设计决策特性实现为什么消息数量上限500 条适配大上下文模型128K智能截断保留完整对话轮次不拆散 userassistant 配对上下文压缩辅助 LLM 生成摘要比简单截断保留更多信息持久化存储SQLite应用重启后不丢失历史三、完整链路追踪 —— 从早上好到惊喜回复3.1 请求处理全流程用户输入: 早上好 │ ▼ [1] 意图识别 (detect_intent_with_confidence) │ 早上好 是 casual_chat 低权重关键词 │ 不会单独触发 casual_chat需组合匹配 │ 意图置信度: 0.0无明确工具意图 │ ▼ [2] System Prompt 构建 (build_system_prompt_from_intent) │ parts [ │ CORE_SYSTEM_PROMPT, ← 工具指南 规则 │ COMPANION_PROMPT_MODULE, ← 始终注入的陪伴人格 │ ] │ ▼ [3] 获取会话上下文 (session.messages) │ messages session_manager.get_messages( │ max_tokensmodel_cfg.context_window │ ) │ 包含昨天的对话 今天的早上好 │ ▼ [4] LLM 推理 │ System Prompt 告诉 LLM │ 语气亲切自然像朋友 善于从上下文推断 │ │ LLM 看到 messages 中昨天的内容 │ 用户昨天说帮我准备周五的汇报材料 │ │ LLM 自然推理 │ 我应该提到昨天的话题表示我记得 │ ▼ [5] 生成回复示例 │ 早上好呀昨天你提到要准备周五的汇报材料 │ 今天要不要先列个大纲早晨空气清新 │ 思路会比较清晰哦 │ ▼ [6] 并行每日任务推送 │ DailyTaskScheduler 在 07:00 或启动时 │ 通过 CompanionEngine.send_daily_task_message() │ 推送 今日任务清单 到对话栏 │ ▼ 用户感受AI 帮我扫描了昨天的内容太惊喜了3.2 关键代码片段为什么早上好不会触发闲聊模式在意图识别系统中早上好被归类为casual_chat的低权重关键词# Phase 6: casual_chat 低权重关键词不直接参与匹配CASUAL_LOW_WEIGHT_KEYWORDS{你好,在吗,早上好,晚上好,最近怎么样,谢谢你,感谢,辛苦了,做得好,...}# 在关键词匹配时低权重关键词被过滤掉forintent_name,keywordsinINTENT_CATEGORIES.items():ifintent_namecasual_chat:effective_keywords[kwforkwinkeywordsifkwnotinCASUAL_LOW_WEIGHT_KEYWORDS]设计意图单说早上好不应该触发casual_chat意图那样会限制工具使用而是让 LLM 在通用模式下自由回应结合 COMPANION_PROMPT_MODULE 的人格引导产出温暖且个性化的回复。3.3 并行触发每日任务如何恰好出现DailyTaskScheduler 的启动检查机制asyncdefcheck_and_push_on_startup(self)-bool:应用启动时检查是否需要推送。nowdatetime.now()hournow.hour# 只在早上 6-10 点之间检查用户可能刚起床ifhour6orhour10:returnFalse# 今天已推送过则跳过ifself._last_push_datetoday:returnFalse# 执行推送awaitself._push_recommendations()returnTrue时间窗口设计6:00-10:00 的推送窗口确保不会在凌晨打扰用户不会在下午推送今日任务已经过了半天应用启动时自动检查无需定时任务四、防骚扰机制 —— 惊喜不等于打扰4.1 冷却管理器的三重保护classCooldownManager:daily_budget:int5# 每日最多 5 次主动交互min_budget:int2# 最少 2 次不能太低max_budget:int8# 最多 8 次不能太高consecutive_limit:int2# 连续忽略 2 次就暂停rejection_penalty_hours:int4# 被拒绝后冷却 4 小时三重保护机制┌─────────────────────────────────────────────────┐ │ 可以主动交互吗 │ ├─────────────────────────────────────────────────┤ │ │ │ [检查1] 每日配额用完了 │ │ daily_count daily_budget → 拒绝 │ │ │ │ [检查2] 被拒绝后的惩罚期 │ │ now last_rejection 4h → 拒绝 │ │ │ │ [检查3] 连续被忽略了 │ │ consecutive_ignores 2 → 拒绝 │ │ │ │ 全部通过 → ✅ 允许交互 │ └─────────────────────────────────────────────────┘4.2 预算自适应调节defadjust_budget(self,user_response:str,consecutive_ignores:int):根据用户反馈动态调整配额。ifuser_responsepositive:# 正面反馈 没有被忽略 → 增加配额ifconsecutive_ignores0:self.daily_budgetmin(self.daily_budget1,self.max_budget)elifuser_responsenegativeorconsecutive_ignores2:# 负面反馈或多次忽略 → 减少配额self.daily_budgetmax(self.daily_budget-1,self.min_budget)核心原则越喜欢互动的用户得到越多的主动关怀越反感的用户得到越少的打扰。五、性能优化与最佳实践5.1 为什么不用 RAG 检索历史方案延迟成本复杂度效果RAG 检索2~5sEmbedding API 费用高片段化直接注入 messages0ms无额外费用低完整自然摘要后注入1~2s辅助 LLM 费用中信息压缩WeClaw 的策略近期对话最近 500 条直接注入 messagesLLM 自然回忆更早的历史ContextCompressor 用辅助 LLM 生成摘要替代简单截断跨会话搜索通过chat_history工具按需检索5.2 上下文窗口管理策略# 智能截断保留完整对话轮次defget_messages(self,max_tokens:int)-list[dict]:获取消息列表自动截断以适配上下文窗口。 策略 1. 保留 system prompt始终 2. 保留最近消息从后往前填充 3. 不截断 tool_calls 和对应 tool 结果保证配对完整 4. 不拆散 userassistant 对话轮次 5.3 最佳实践总结Do’s推荐做法✅ 始终在 System Prompt 中注入人格模块让 LLM 有记忆动机✅ 持久化完整对话历史让 LLM 有记忆素材✅ 用冷却机制控制主动交互频率避免骚扰✅ 用定时任务离线分析早上推送结构化任务清单✅ 将低权重问候词排除在意图识别之外保持回复自由度Don’ts避免做法❌ 不要为每种问候场景写专门的处理器过度工程化❌ 不要把历史对话截断得太激进丢失上下文❌ 不要无条件推送主动消息骚扰用户❌ 不要在 System Prompt 中写死引用昨天内容的指令太僵硬黄金法则让 LLM 做 LLM 擅长的事理解上下文、自然回忆让工程系统做工程擅长的事定时调度、冷却控制、持久化存储。六、总结与展望6.1 核心要点回顾本文揭示了早上好惊喜背后的四层协同架构4 个关键层人格注入层COMPANION_PROMPT_MODULE 始终生效赋予 AI 朋友人格主动关怀层CompanionEngine 通过七层评分决策何时触发 morning_greeting任务推送层DailyTaskScheduler 凌晨分析 早上推送结构化清单上下文记忆层Session 持久化 500 条消息LLM 自然回忆1 个核心洞察早上好惊喜 人格引导 对话历史 LLM推理能力 定时推送没有专门的扫描模块是多组件协同的涌现行为。6.2 可扩展方向短期优化在 ContextCompressor 中增加昨日摘要缓存减少 Token 消耗为 morning_greeting 增加更丰富的上下文变量天气 API、日程 API长期演进引入向量数据库实现跨会话长期记忆基于用户反馈训练个性化的关怀回复模型多模态关怀语音 表情 桌面宠物联动6.3 互动环节思考题如果用户每天说早上好的时间不固定有时 6 点有时 10 点冷却机制应该如何适配如果 LLM 的上下文窗口只有 8K Token四层架构需要做哪些调整讨论话题你认为 AI 助手的主动性边界在哪里太多的主动关怀会变成打扰太少又显得冷漠。你的产品是怎么平衡的附录 A核心文件清单文件路径行数作用src/core/prompts.py1896System Prompt 构建 意图识别 陪伴人格模块src/core/companion_engine.py1439主动陪伴核心引擎五大组件 七层评分src/core/companion_topics.py439关怀主题定义15 种预定义主题src/core/daily_task_scheduler.py434每日任务调度凌晨分析 早上推送src/core/task_analyzer.py727任务智能分析四维度 NLP 分析src/core/session.py1100会话管理持久化 智能截断 压缩总代码量约 6,035 行关键组件6 个核心模块协作关系EventBus 事件驱动 SQLite 状态持久化附录 B关联文章第 21 篇《主动陪伴引擎实战五大组件如何协力决策何时和说什么》第 22 篇《拒绝不是失败防骚扰冷却机制如何让陪伴更懂用户》第 23 篇《从工具调用推断用户档案无感建档系统的分阶段采集策略》第 30 篇《会话管理系统的演进从内存字典到 SQLite 持久化》版权声明本文为 CSDN 博主「yweng18」的原创文章遵循 CC 4.0 BY-SA 版权协议转载请附上原文出处链接及本声明。