You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

30 KiB

记忆中心(Memory Center)设计与开发文档

版本:v0.1 草案  日期:2026-08-31 范围:apps/services(后端)、apps/client(Flutter)、apps/admin(后台)、百炼 Agent 配置 状态:设计评审中,未开工


一、背景与目标

App 现有的「代办」页(TodoTab)只是一个日历壳子:数据来自 12 条写死的演示数据加上 EMAI 助手落下来的闹钟,全部存在本地 GetStorage,服务端没有任何对应存储。

本次要把它升级成**「记忆」页**——用户一天里发生的各类事情的统一入口,并围绕它形成「录入 → 提醒 → 复盘 → 问答」的闭环。

六项目标需求

# 需求 关键约束
1 记忆页展示多类事项:闹钟、灵感记忆、花销、待办,分类可扩展 一天多件事,按分类组织
2 每日首次登录,自动弹窗展示当天事项并语音播报,播报可随时关闭 播报可中断
3 待办/闹钟提前 5 分钟提醒,语音播报内容 App 未打开时也要触发
4 每周一凌晨生成上周总结:未完成事项、花销合计、灵感汇总,播报后需用户确认 服务端定时生成
5 每月 1 号生成上月总结:完成/未完成情况、开销、灵感汇总 同上
6 上述数据可在 EMAI 助手里随时提问,助手能答 走 MCP 工具

设计原则

  1. 统一模型:一张表承载所有分类,新增分类不改表结构、不加接口。
  2. 服务端为真相源:本地只做缓存与离线兜底,换设备数据要在。
  3. 失败隔离:AI 抽取、总结生成失败不影响主流程,宁可少一条记忆,不可让会议纪要或登录卡住。
  4. 不重复造轮子:allhelp 已有任务体系与 MCP 工具,在其上演进。

二、现状盘点(本设计的地基)

2.1 已有且可直接复用

能力 位置 说明
用户任务表 DBTask allhelp_db.proto task_name/task_desc/task_type/trigger_time/cron_expr/status/extra,存 MySQL 业务库
任务增删改查接口 allhelp 模块 api_addtask/gettasks/canceltask/completetask 已上线
MCP 工具(EMAI 可调) tool_get_user_tasks.go、tool_allhelp_task.go、tool_cancel_user_task.go EMAI 已能查/建/取消任务
异步 AI 总结流水线 allhelp/summary.go Redis 队列 + N worker + doubao.Chat,周报/月报可照搬
每日聊天总结表 DBChatSummary 同上 (uid, summary_date) 唯一,覆盖重算
TTS 播报 tts_service.dart startspeak/speakOnce/speakStream/flushStream/stop,已支持中断
本地通知插件 flutter_local_notifications ^18.0.1 目前只用于录音后台提示
助手端侧指令 assistant_directive_service.dart SET_clock 已落地成提醒
会议纪要生成 echomeet/tasks.go AIProcess summary 已含「四、待办事项」章节

2.2 缺口

缺口 影响需求
DBTask 「服务端仅做记录,不自动触发」(proto 注释原文) 3/4/5
没有分类概念,无法承载灵感/花销 1
花销功能后端完全空白,客户端只有 i18n 文案和 mock 1/4/5
没有周报/月报表与生成任务 4/5
客户端待办数据不落服务端(synced 恒为 false) 全部
会议纪要里的待办是自然语言,无结构化字段 1
本地通知从未用于事项提醒 3

2.3 存储分工(迁移讨论已确认)

数据 库
用户级业务数据(任务、记忆项、报告) MySQL 业务库(per-app 一份)
跨应用共享(会议模板 echomeet_template、产品、授权码) PostgreSQL 公共库
缓存与队列 Redis

阿龙测试机 8.133.166.29 上 PostgreSQL 是自建 postgres:16 容器(库 starpivot_console),与第三方无关。


三、核心模型:记忆项(MemoryItem)

3.1 为什么不直接扩展 DBTask

DBTask 的字段是为「提醒任务」设计的:task_name + trigger_time + cron_expr。要塞进花销金额、灵感正文、会议来源、负责人,只能全丢进 extra JSON,那样查询、统计、排序全部失效——月度「一共花了多少钱」将无法用 SQL 聚合。

决策:新建 memory_item 表作为唯一真相源,DBTask 作为历史链路保留并迁移(见 §9.1)。

3.2 表结构 memory_item(MySQL 业务库)

CREATE TABLE memory_item (
  id            BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  uid           VARCHAR(50)  NOT NULL,
  category      VARCHAR(16)  NOT NULL,   -- alarm/todo/idea/expense/…(可扩展)
  source        VARCHAR(16)  NOT NULL,   -- meeting/assistant/manual/device
  source_id     VARCHAR(64)  DEFAULT '', -- 会议记录 id、指令 id 等

  title         VARCHAR(200) NOT NULL,   -- 主文案(所有分类通用)
  detail        TEXT,                    -- 补充说明 / 灵感正文

  happen_date   DATE         NOT NULL,   -- 归属日期(日历定位用,永不为空)
  happen_time   VARCHAR(5)   DEFAULT '', -- HH:mm,无具体时间则空
  date_certain  TINYINT      DEFAULT 1,  -- 0=日期是推断的(如落在会议当天)
  due_raw       VARCHAR(64)  DEFAULT '', -- 截止时间原文(「下周三前」)

  repeat_rule   VARCHAR(16)  DEFAULT '', -- once/daily/weekly/weekdays/weekend/monthly
  repeat_raw    VARCHAR(64)  DEFAULT '', -- 重复规则原文
  weekday       TINYINT      DEFAULT 0,  -- weekly 时 1-7

  amount        DECIMAL(12,2) DEFAULT 0, -- 花销金额(category=expense)
  currency      VARCHAR(8)   DEFAULT 'CNY',
  owner         VARCHAR(64)  DEFAULT '', -- 负责人原文(会议待办)

  state         TINYINT      DEFAULT 0,  -- 0待办 1完成 2废弃
  remind_ahead  INT          DEFAULT 5,  -- 提前提醒分钟数,0=不提醒
  remind_at     DATETIME     NULL,       -- 计算好的提醒时刻(服务端算,客户端直接用)

  user_edited   TINYINT      DEFAULT 0,  -- 用户改过 → 重新生成时不覆盖
  gen_round     INT          DEFAULT 0,  -- 第几轮 AI 生成
  extra         VARCHAR(2000) DEFAULT '',

  create_time   BIGINT, update_time BIGINT, finish_time BIGINT,

  INDEX idx_uid_date (uid, happen_date),
  INDEX idx_uid_cat  (uid, category, happen_date),
  INDEX idx_remind   (remind_at, state)
);

3.3 字段设计要点

happen_date 永不为空——这是记忆页能工作的前提。日历按日期排,没有日期的项根本渲染不出来。会议待办抽不出截止日期时,落在会议当天并置 date_certain=0,卡片上用 due_raw 标注「下周三前」,用户可改期。

category 是字符串不是枚举——新增分类(如 health、travel)只加常量、不改表、不迁移。代价是无法在 DB 层约束取值,靠服务端白名单校验。

amount 用 DECIMAL 不用 float——月度金额聚合,浮点误差不可接受。

remind_at 由服务端算好——重复规则展开、时区换算、提前量扣减都在服务端做一次,客户端拿到就是一个绝对时刻,不重复实现容易出错的日期逻辑。

user_edited + gen_round——会议重新总结时,删掉上一轮 user_edited=0 的项,保留用户勾过改过的。不做这个,用户点一次「重新生成」就会丢掉自己的修改。

3.4 分类与字段的对应关系

分类 必填 主要用到 不用
todo 待办 title, happen_date owner, due_raw, state, remind_* amount, repeat_*
alarm 闹钟 title, happen_date, happen_time repeat_rule, repeat_raw, weekday, remind_* amount, owner
idea 灵感 title, happen_date detail amount, remind_*, repeat_*
expense 花销 title, happen_date, amount currency, detail remind_*, repeat_*, owner

统一表的代价是每行有约一半字段为空。以本项目的数据量级(单用户日均个位数条目)完全可以接受,换来的是新增分类零成本。

3.5 周期报告表 memory_report

CREATE TABLE memory_report (
  id           BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  uid          VARCHAR(50) NOT NULL,
  period_type  VARCHAR(8)  NOT NULL,   -- week/month
  period_key   VARCHAR(16) NOT NULL,   -- 2026-W35 / 2026-08
  period_start DATE, period_end DATE,

  stat_json    TEXT,        -- 结构化统计(见下)
  summary      TEXT,        -- AI 生成的播报文案
  state        TINYINT DEFAULT 0,  -- 0待生成 1生成中 2完成 3失败
  error_msg    VARCHAR(500),

  confirmed    TINYINT DEFAULT 0,  -- 用户是否已确认(需求4)
  confirm_time BIGINT,

  create_time  BIGINT, update_time BIGINT,
  UNIQUE KEY uk_uid_period (uid, period_type, period_key)
);

stat_json 是服务端用 SQL 算出来的确定性统计,不经过 LLM:

{
  "todo_total": 12, "todo_done": 8, "todo_undone": 4,
  "undone_items": [{"id":123,"title":"跟进 A 客户","happen_date":"2026-08-26"}],
  "expense_total": 1280.50, "expense_count": 15,
  "expense_by_day": {"2026-08-25": 120.00},
  "idea_count": 3,
  "idea_items": [{"id":456,"title":"做一个会议纪要转待办的功能"}],
  "alarm_total": 7
}

金额与完成数绝不能让 LLM 算——它只负责把 stat_json 组织成一段自然、适合朗读的话。数字算错比话说得干巴严重得多。


四、服务端接口

新建 memory 模块(apps/services/modules/memory/),由 home 服务装载。按反射注册约定,方法签名满足 func (c *apiComp) X(session comm.IUserSession, req *pb.XReq) (*pb.XResp, *pb.ErrorData) 即自动注册为 memory_x。

接口 用途 关键参数
memory_list 拉取记忆项 start_date/end_date/categories[]/states[]
memory_today 当天全部事项(需求 2 弹窗直接用) date(客户端本地日期)
memory_add 新增 整个 item
memory_update 修改(自动置 user_edited=1) id + 变更字段
memory_del 删除 ids[]
memory_complete 标记完成 ids[]
memory_upcoming 拉未来 N 天待提醒项(客户端排本地通知用) days(默认 7)
memory_getreport 取周报/月报 period_type/period_key
memory_confirmreport 用户确认报告(需求 4) report_id
memory_stats 即时统计(EMAI 问答与页面头部用) 时间范围 + 分类

memory_today 单独开一个接口而不是复用 memory_list:登录弹窗是启动路径上的强依赖,要能一次拿全(含当天报告待确认标记),且便于单独做缓存和降级。

4.1 时区

happen_date 是用户本地日期,不是 UTC 日期。客户端请求时带上 tz(如 Asia/Shanghai)与本地日期字符串,服务端不做时区推断。跨时区旅行时以客户端当前时区为准——这是刻意选择:用户"今天"的定义应该跟着人走。


五、定时与触发

这是需求 2/3/4/5 的核心,也是现在完全空白的部分。三类触发分别放在不同的地方,不要试图用一套机制全包。

5.1 提前 5 分钟提醒(需求 3)→ 客户端本地调度

必须在客户端做,因为 App 未打开、甚至无网时也要响。服务端推送做不到(无 APNs/FCM 通道,且国内厂商推送要逐家接)。

登录/前台恢复 → memory_upcoming(days=7)
   → flutter_local_notifications.zonedSchedule() 逐条排期
   → 到点系统通知(带内容)
   → 用户点击进 App → TtsService 播报 title + detail

要点:

  • 每次拉取先取消旧排期再重排,避免改期后旧通知还在。
  • Android 需 SCHEDULE_EXACT_ALARM 权限(Android 13+),iOS 需通知授权。未授权时降级为「打开 App 才提醒」,不要阻塞主流程。
  • 排期上限按平台限制(iOS 最多 64 条待处理通知),只排最近 7 天、按时间取前 N 条。
  • 通知点击进来才播报,不在通知里直接播声音——锁屏状态下强行出声是骚扰。

5.2 每日登录播报(需求 2)→ 客户端

App 启动/切前台
  → 判断「今天是否已弹过」(本地存 last_daily_popup_date)
  → 否 → memory_today
  → 弹窗(列表 + 播报按钮,默认自动开始播报)
  → TtsService.startspeak → speakStream 逐条 → flushStream
  → 用户点关闭/返回 → TtsService.stop()

播报文案在客户端本地拼(不调 LLM),格式如:

今天有 3 件事。上午 9 点,项目周会。下午 2 点,跟进 A 客户,负责人王总。另外有一条灵感记录:做一个会议纪要转待办的功能。

stop() 必须真的能打断——TtsService 接口已有该方法,且 speakStream 是队列式播放,停止时要连带清队列,否则会出现「关了还在念下一句」。

5.3 周报/月报生成(需求 4/5)→ 服务端 cron + 异步队列

照搬 allhelp/summary.go 的成熟模式:

lego cron(在 memory 模块 Start 中注册)
  周一 00:30  →  扫描上周有数据的 uid
  1 号 00:30  →  扫描上月有数据的 uid
      ↓ 逐个 uid 建 memory_report(state=0) 并 LPush Redis 队列
  N 个 worker BRPop
      ↓ SQL 算出 stat_json(确定性统计,不过 LLM)
      ↓ LLM 只做一件事:把 stat_json 组织成适合朗读的话 → summary
      ↓ 回写 state=2

要点:

  • cron 只在一个实例上跑。home 是集群服务,多副本会重复生成。用 Redis SET NX EX 抢锁,key 带日期(memory:report:lock:week:2026-W35)。
  • 时间选 00:30 而非 00:00——避开整点其他定时任务,也给跨日数据落库留缓冲。
  • 用户量大时按 uid 分片入队,不要一次性扫全表。
  • 只给「上周期有数据的用户」生成,空报告没有意义还浪费 LLM 调用。
  • 客户端下次打开时 memory_getreport 拉取 → 弹窗播报 → 用户确认 → memory_confirmreport。不做「凌晨推送叫醒用户」。

5.4 为什么不用现有 timer 服务

timer 是独立的集群服务,目前只有 timer_uselog 一个模块,且与 memory 数据不在同一进程,跨服务调用反而增加复杂度。周报/月报 cron 直接放 memory 模块内(lego/sys/cron),与 echomeet 的做法一致。


六、客户端设计

6.1 页面改名与结构

TodoTab → MemoryTab(「记忆」)。i18n key 全量替换,41 个语言文件都要动。

记忆页
├── 日历卡(CalendarCard,复用现有几何/手势逻辑)
├── 分类筛选条(全部 / 待办 / 闹钟 / 灵感 / 花销)  ← 新增
└── 事项列表(MemoryScopeList,由 TodoScopeList 改造)
     ├── 日/周/月范围切换(已有)
     ├── 头部汇总:3 件待办 · 2 条灵感 · 花销 ¥248   ← 扩展
     └── 分类着色的卡片

6.2 数据层

新增 MemoryService(写法参照 AssistantDirectiveService):

  • 服务端为准,本地 GetStorage 做缓存与离线兜底
  • RxList<MemoryItem>,页面 Obx 响应
  • 启动拉取 + 下拉刷新 + 写操作后局部刷新
  • 冲突策略:服务端返回覆盖本地(本地不做离线编辑队列,一期不支持离线改)

CalendarController._rebuildEvents 改为从 MemoryService 单一来源投影成 CalendarEvent:

title       = item.title
description = [item.owner, item.dueRaw].where((e)=>e.isNotEmpty).join(' · ')
date        = item.happenDate
startTime   = item.happenTime
color       = _colorOf(item.category)   // 分类配色
taskStatus  = item.state == 1 ? 2 : 0
amount      = item.amount               // expense 分类

同时删除 mockCalendarEvents()——真实数据上线后,演示数据混在里面会让人以为系统出错。

6.3 助手提醒的迁移

AssistantDirectiveService 保留(它是指令流水日志,有独立价值:排查、统计百炼下发了哪些没实现的指令),但:

  • _handleSetClock 不再写本地 reminders,改为调 memory_add(category=alarm, source=assistant)
  • 本地 reminders 列表在迁移期保留双写,一个版本后移除
  • 老版本本地已有的提醒,首次启动时一次性上传并打标记,避免重复

七、会议总结 → 记忆项

7.1 模板提示词改造(echomeet_template,PostgreSQL 公共库)

General-Meeting 的 template 第四节现在只有一句「梳理会议中明确的后续执行任务,清晰标注任务核心要求」,没要求负责人和截止时间,抽取那一路再强也补不出原文没提炼的信息。

改为:

## 四、待办事项
逐条梳理会议中明确的后续执行任务,每条固定包含「任务内容、负责人、截止时间」三要素,按以下格式输出:
1. 任务内容。负责人:[张三];截止时间:本周五前。
2. 任务内容。负责人:未明确;截止时间:未明确。
- 三要素中任何一项会议原文未明确的,写「未明确」,禁止推测、补全或编造;
- 截止时间原样保留原文表述(如「下周三前」「月底」),不要自行换算成具体日期;
- 只收录会议中明确要求执行的任务;仅在讨论中提及、未拍板的设想不计入;
- 同一件事被多次提及只输出一条,取最终确定的版本;
- 若全程没有任何明确的执行任务,本节只输出一句「本次会议无明确待办事项。」

负责人: / 截止时间: 是给后续抽取用的固定锚点,人读着也自然。「未明确」比留空好——空缺分不清是模型漏了还是原文没有。

只改 template 不改 outline:outline 产出的 overview 是用户在「概览」Tab 直接看的正文(overview_tab.dart:27 按 \n 拆行渲染),改它会破坏已发布客户端的展示。

铺开策略:先只改 zh-CN(id=227)验证效果,确认后再翻译到其余 40 种语言。29 组模板 × 41 语言 = 1189 条,不要一上来就全铺。

7.2 抽取那一路(代码内置 prompt,不放模板)

在 AIProcess 写完 summary/overview、状态置 Completed 之后,起独立 goroutine:

输入:<meeting_date>2026-08-31</meeting_date>
      <summary>…已生成的纪要…</summary>
prompt:代码内置(不放 echomeet_template)
输出:JSON 数组 → 逐条写 memory_item(category=todo, source=meeting, source_id=记录id)

为什么 prompt 放代码不放模板:① 模板有 1189 条,每条是对应语言的提示词,改不动也改不齐;② 各模板 outline 职责本就不同,塞进去会互相干扰;③ 输出要被程序 parse 成 JSON,格式严格性不能交给后台可随手编辑的文本;④ 抽取输入是已提炼的 summary(约千字),成本只是前两路(转写全文可达上万字)的零头,省不出什么。

为什么必须注入 <meeting_date>:现在 AIProcess 拼给模型的只有 <remark> + <transcript>,没有日期。模型不知道今天几号,让它把「下周三前」换算成具体日期就是瞎猜。

服务端必须二次校验 due_date:解析不出合法日期、或早于会议当天的,一律丢弃日期只保留 due_raw,happen_date 落会议当天并置 date_certain=0。参考 SET_clock 已踩过的坑——实测模型把「下午 3:30」的 time 填成 03:30(见 disambiguateAfternoon 的注释)。

失败隔离:抽取失败只记日志,不改 rec.State。用户照样看得到纪要,只是没有自动待办。

7.3 重新总结的幂等

用户点「重新生成」时:

delete from memory_item
 where source='meeting' and source_id=? and user_edited=0 and gen_round < 新轮次

user_edited=1 的一律保留。


八、EMAI / 百炼多模态打通

百炼在两个层面参与,职责必须分清:

8.1 端侧指令(tool_calls)——用户说,助手做

百炼在 RespondingContent 帧的 payload.output.extra_info.tool_calls 下发端侧函数调用,客户端 AssistantDirective.parseFromOutput 解析后分发。

现有 SET_clock(参数 time/date/content/repeat)落地成闹钟。本次要在百炼后台补三个工具:

工具 参数 落地
SET_clock(已有) time, date, content, repeat category=alarm
ADD_todo(新增) content, date, time, owner category=todo
ADD_idea(新增) content category=idea
ADD_expense(新增) content, amount, date category=expense

已知的百炼侧问题(CLAUDE.md 已记录,本次一并解决):

  • 「取消闹钟」和「记一下待办」目前不下发任何指令,模型却回「已经帮你取消了」——后台没配对应工具。这是需求 1「灵感/花销」能否语音录入的前提。
  • SEND_message / MAKE_A_PHONE_CALL_phone_call 本版已无对应能力,要去百炼后台把这两个工具摘掉,否则模型会继续下发无法执行的指令。

解析侧三个已知坑(照现有实现处理,勿改):arguments 是字符串形式 JSON 要二次 parse;参数值是中文自然语言(repeat="周一")不是枚举;finish_reason=command_calls 是纯指令帧,text 为空且不会有 RespondingStarted/Ended,照 text 建气泡会留下永远填不上的空泡。

8.2 MCP 工具(服务端)——用户问,助手查

服务端 MCP 已经跑在 /mcp(streamable HTTP, stateless)与 /sse,带 authFromRequest 鉴权,工具分 GLOBAL/CHINA/OVERSEAS 三组。

新增工具(ToolGroup_GLOBAL):

工具 描述 回答什么问题
get_memory_items 按日期范围/分类查记忆项 「我明天有什么事」「上周记了哪些灵感」
get_memory_stats 统计(花销合计、完成率) 「这个月花了多少钱」「上周有几件事没做完」
get_memory_report 取周报/月报 「上周总结说了什么」
add_memory_item 新增记忆项 「帮我记一下:明天下午three点开会」
complete_memory_item 标记完成 「把跟进 A 客户那件事标记完成」

现有 get_user_tasks / allhelp_task / cancel_user_task 三个工具改为读写 memory_item(见 §9.1),保持工具名不变,避免百炼后台重新配置。

8.3 两条通路的分工

                        ┌──────────────────────────┐
   用户说「记一下…」  →  │  百炼 Agent              │
   用户问「我这月花了…」 │                          │
                        └──┬──────────────────┬────┘
                           │ tool_calls       │ MCP 调用
                           ↓ (端侧执行)        ↓ (服务端执行)
                    客户端 Directive      服务端 memory 模块
                           │                  │
                           └────→ memory_item ←┘

记录走端侧、查询走 MCP 是刻意的:端侧指令随对话即时下发、延迟低、离线也能先落本地;查询需要跨设备的全量数据,必须服务端出。


九、迁移与兼容

9.1 DBTask 的处置

阶段 动作
一期 memory_item 上线;DBTask 停止新增写入;MCP 三个旧工具改读 memory_item
二期 一次性脚本迁移存量 DBTask → memory_item(task_type 映射 repeat_rule,status 映射 state,category 一律 todo)
三期 allhelp 的 task 接口标记废弃,保留只读

不要直接删 DBTask 表——EMAI 侧可能有历史会话引用,且迁移脚本需要回滚余地。

9.2 客户端老版本

老版本客户端不知道 memory_* 接口,继续用本地 GetStorage。服务端不做任何兼容适配——新功能只对新版本开放,老版本行为不变(本地闹钟照常)。

9.3 不向后兼容的点

  • 记忆页改名后,i18n key 变更需 41 个语言文件同步,漏一个语言就显示 key 名
  • mockCalendarEvents() 删除后,无数据用户看到的是空态页——需要设计空态文案与引导

十、闭环全景

   ┌─────────── 录入 ───────────┐
   │                            │
会议录音 → echomeet 转写总结     EMAI 对话 → tool_calls
   │  ↓ AIProcess 第三路抽取      │  ↓ AssistantDirective
   │  (summary + 会议日期)      │  (SET_clock/ADD_todo/…)
   └──────────┬─────────────────┘
              ↓
      ┌──── memory_item ────┐   ← 手动录入(记忆页 +)
      │  todo/alarm/idea/    │
      │  expense…            │
      └──┬────────┬──────┬───┘
         │        │      │
    ┌────┘        │      └────────────┐
    ↓             ↓                   ↓
 记忆页日历    提醒链路            周期复盘
 (分类展示)   ├ 每日登录弹窗+播报   ├ 周一 00:30 cron
              ├ 提前5分钟本地通知   ├ 1号 00:30 cron
              └ TTS 播报(可中断)    ├ SQL 算 stat_json
                                    ├ LLM 组织播报文案
                                    └ 播报 → 用户确认
         ↑                                  │
         └────── MCP 工具 ←── EMAI 提问 ─────┘

十一、分期实施

一期:打通主链路(只读为主)

# 任务 端
1 memory_item 表 + memory 模块骨架 后端
2 memory_list / memory_today / memory_add / memory_update / memory_complete 后端
3 会议抽取第三路 + <meeting_date> 注入 + 日期校验 后端
4 General-Meeting zh-CN 模板第四节改造 后台配置
5 MemoryService + MemoryItem 模型 客户端
6 记忆页改名、分类筛选、_rebuildEvents 换源、删 mock 客户端
7 助手 SET_clock 改写服务端 客户端

验收:开一次会 → 纪要生成 → 待办自动出现在记忆页日历上,标注来源会议与负责人。

二期:提醒与播报

# 任务 端
8 memory_upcoming + remind_at 计算 后端
9 本地通知排期(含权限降级) 客户端
10 每日登录弹窗 + TTS 播报 + 中断 客户端
11 百炼后台补 ADD_todo/ADD_idea/ADD_expense,摘掉电话/短信工具 配置
12 花销分类完整支持(录入 + 统计) 两端

三期:复盘与问答

# 任务 端
13 memory_report 表 + cron + 分布式锁 + 异步 worker 后端
14 stat_json SQL 统计 + LLM 播报文案生成 后端
15 报告弹窗 + 播报 + 确认 客户端
16 5 个新 MCP 工具 + 旧工具改读新表 后端
17 DBTask 存量迁移脚本 后端

十二、风险与待确认

风险

级别 风险 应对
高 相对时间解析不准(「下周三前」→ 具体日期) 注入会议日期 + 服务端二次校验,宁可留空
高 重新总结冲掉用户修改 user_edited + gen_round 双字段
高 cron 多副本重复生成报告 Redis SET NX EX 分布式锁
中 本地通知权限被拒 / 平台限制 降级为打开 App 才提醒,不阻塞
中 LLM 算错金额 统计全部走 SQL,LLM 只组织文案
中 多一路 LLM 调用增加成本 输入用 summary 而非全文;失败不重试
中 41 个语言文件改名遗漏 用 tools/i18n_audit.py 校验
低 统一表半数字段为空 数据量级小,可接受

待确认

  1. 花销录入方式——纯语音(「打车花了 30」)?手动记账页?是否要拍照识别小票?当前设计只保证数据结构支持,录入 UI 未定。
  2. 灵感与「聊天总结」的关系——allhelp 已有 DBChatSummary(每日聊天 AI 总结)。灵感是用户主动说「记一下」,聊天总结是自动提炼,两者要不要合并?建议先分开,灵感是显式的、聊天总结是隐式的。
  3. 报告确认的含义——只是「我看过了」,还是要允许用户在确认时批量处理未完成事项(顺延/放弃)?影响接口设计。
  4. 多设备播报冲突——同一账号在手机和耳机同时在线,谁播报?建议只在当前活跃前台设备播。
  5. 阿龙测试机 NATS 容器 unhealthy(已 3 周)——配置变更广播依赖它,且 stats_global_day 数据停在 20260731。上线前需修复,否则后台改模板要等 10 分钟 cron 兜底。

附录 A:分类配色建议

分类 色值 说明
todo 待办 #5B8DEF 蓝
alarm 闹钟 #22C1A6 青 沿用现有助手提醒色
idea 灵感 #F59E0B 橙
expense 花销 #EC4899 粉

深色模式下需各自校验对比度,不要直接沿用。

附录 B:关键文件索引

用途 路径
会议纪要生成 apps/services/modules/echomeet/tasks.go (AIProcess)
会议模板读写 apps/services/modules/console/api_config.go
已有任务体系 apps/services/modules/allhelp/
异步总结范例 apps/services/modules/allhelp/summary.go
MCP 工具 apps/services/modules/mcp/tool_*.go
助手指令解析 apps/client/lib/data/models/assistant_directive.dart
助手指令分发 apps/client/lib/data/services/assistant_directive_service.dart
日历控制器 apps/client/lib/modules/home/controllers/calendar_controller.dart
待办列表 apps/client/lib/modules/main_tab/views/widgets/todo_scope_list.dart
TTS 接口 apps/client/lib/data/services/tts_service.dart