Lock health recording behind confirm-only state machines, reject public publishes for the health category, and ship the 14-day experiment Page Data templates with tests. Co-authored-by: Cursor <cursoragent@cursor.com>
51 KiB
MeMind Health 架构与通道设计
日期:2026-09-02 状态:架构设计稿。未改动业务代码、未碰生产、未读写用户数据。 适用范围:MeMind H5、微信服务号、MindSpace、Page Data、Memory V2、Agent Gateway
0. 一句话定位
MeMind Health 不是「另一个健康 App」,而是:
持续理解本人健康基线,并在长期变化中发现「偏离」的个人健康 Agent。
核心数据链路:
本人 → 录入/设备/报告 → Health Timeline → Personal Baseline
→ 偏离事件 → Agent 推理 → 行动建议 → 医疗资料沉淀
与传统健康产品的根本差异:
| 传统健康 App | MeMind Health |
|---|---|
140/90 → 标红 |
该用户 90 天基线 119–126/70–77,近 14 天持续漂移 +8% |
| 数据看板 | 「最近和以前不一样」的事件叙事 |
| 用户自己盯曲线 | 只在偏离时介入,无事静默 |
| 单次录入 | 时间序列 + 关联假设 + 长期学习 |
MVP 验证命题:
MeMind 能不能比我自己更早发现:我最近和以前不太一样?
若成立,血压计只是传感器;Personal Baseline + Health Timeline + Event Engine 才是产品。
1. 已确认的产品决策(不可随意推翻)
以下决策已确认,后续实现必须遵守。变更需重新评审本文档。
D1 单人模型:只监测账号本人
- 监测对象 默认且仅为账号本人,
HealthProfile与user_id严格 1:1。 - 不做
FamilyGroup/ 多Subject/ 子女代录代管。 - 理由:录入标准、测量情境、回顾深度必须统一,否则 Personal Baseline 失真(「参差不齐」)。
- 未来若做「关注家人」,只能是 本人主动授权只读分享摘要(P4),录入权永远在本人。
D2 他人健康数据走辅轨,不进引擎
用户说「我妈上周体检血压 150/95」这类内容:
- 写入 Memory V2(
fact/experience)或普通备忘,Agent 可对话召回。 - 禁止进入
HealthObservation、Baseline、Trend、Event Engine。 - Agent 话术须明确告知:「这不会进入你的健康分析」。
D3 存储走 Page Data(P0 决策)
- 结构化健康数值存入 用户隔离的 PostgreSQL schema(Page Data 体系,
private_data_execute建表 +private_data_register_dataset注册)。 - 复用现成的用户级 schema 隔离、dataset 授权、操作日志、导出、软删除恢复能力。
- P1 若基线/趋势聚合出现性能瓶颈,再评估迁移到专用表;迁移方案见 §12.3。
D4 服务号允许规则命中 + 强制确认
- 自由文本先走确定性规则(正则/关键词);命中即进入对应流程。
- 规则未命中 → 回交互式菜单,不让 LLM 硬猜。
- 所有由识别/解析得到的数值,一律经用户确认后才落库。
D5 健康会话完全独立
- 健康会话与普通聊天会话完全隔离(独立 session、独立工具白名单)。
- 普通聊天中识别到健康意图,只做引导跳转,给入口链接/按钮。
- 绝不在普通聊天里直接落库健康数据。
2. 四条不可违背的工程原则
- 健康通道是「锁定态会话」,不是「聊天里聊健康」。进入后 skill 被 pin,意图分类器不再参与判断。
- 拍照/上传不直接落库,一律「抽取 → 确认 → 提交」三段式。未确认数据不进基线引擎。
- 意图不明确时不猜,直接给选项。 菜单式交互在健康场景比自然语言理解更精准、更快、更可审计。
- 健康区数据默认加密,无口令不允许发布。 服务端硬阻断,不靠前端自觉。
配套的分层职责:
规则判断事实 → Rule Engine(确定性、可审计)
算法发现趋势 → Trend Engine(统计、可复现)
LLM 负责解释 → Agent(不可作为 primary detector)
禁止的反模式:血压 128/85 → LLM → "你觉得危险吗?"
3. 系统总览
MeMind Health(本人)
│
┌───────────────────┼───────────────────┐
│ │ │
Health Connector Health Timeline Medical Documents
(P2: Apple/蓝牙) (结构化时序) (报告 OCR + 归档)
│ │ │
└───────────────────┼───────────────────┘
↓
Personal Baseline Engine
↓
┌───────────────────┴───────────────────┐
↓ ↓
Rule Engine Trend Engine
(医学阈值 / 漏测 / 药物变化) (个体偏移 / 变异性 / 联动)
│ │
└───────────────────┬───────────────────┘
↓
Event Engine
(Health Event Cluster)
↓
MeMind Agent(解释 + 追问 + 建议)
↓
提醒 / 复测 / 就医建议 / 就诊摘要 / Memory 沉淀
3.1 与现有 MeMind 能力的映射
| 设计层 | 复用的现有能力 | 关键文件 |
|---|---|---|
| 通道锁定不漂移 | selectedChatSkill 短路 + enforceSelectedSkillRuntime |
chat-intent-router.mjs、agent-run-routes.mjs |
| 结构化存储 | Page Data 用户隔离 PG schema | page-data-service.mjs、mindspace-userdata-postgres.mjs |
| 健康区与发布策略 | h5_space_categories(visibility/ai_access/publish_policy) |
mindspace.mjs(SYSTEM_CATEGORIES) |
| 加密发布与口令 | 发布 access_mode + password_hash |
mindspace-pages.mjs、page-data-public-service.mjs |
| 私有页不被收录 | INDEXABLE_ACCESS_MODE = 'public',非 public 一律 noindex |
mindspace-index-policy.mjs |
| 报告原文件存储 | MindSpace 资产(h5_assets)+ 分区归属 |
mindspace.mjs |
| 服务号图文/语音接入 | msgType 分流 + eventKey 菜单事件 |
wechat-mp.mjs |
| 图片轮次隔离 | 带图轮次摘掉 read_image、污染触发会话轮换 |
chat-image-turn-scope.mjs |
| 用药/复诊提醒 | h5_schedule_items + schedule-assistant |
schedule-service.mjs |
| 长期关联假设 | Memory V2 candidate → promote | memory-v2.mjs、memory-v2-lifecycle.mjs |
| 灰度 / fail-open | 现有 canary + fail-open 模式 | memory-v2-runtime.mjs 等 |
3.2 需要新增的模块(隔离在健康域内)
health-channel-state.mjs 通道状态机(纯函数,可单测)
health-observation-service.mjs Observation 读写 + 合理性校验 + 幂等去重
health-extraction.mjs 图片/报告结构化抽取 + confidence 归一
health-baseline-engine.mjs 滚动基线计算(P1)
health-event-engine.mjs Rule + Trend + Event 聚合(P1)
health-document-service.mjs 报告归档 + 指标映射
health-share-service.mjs 就诊摘要快照与令牌(P3)
skills/health-assistant/ skill 定义
src/pages/health/* H5 健康入口页面
4. 入口设计:H5 主入口 + 服务号轻入口
两个入口共用同一个 Health Channel 内核,只是壳不同。
┌──────────────────────────┐
H5 首页 ──────→│ 健康助手入口(卡片 / Tab) │
└────────────┬─────────────┘
│
服务号菜单 / 关键词 ─────────→│
「健康助手」 │
↓
┌────────────────────────────┐
│ Health Channel 内核 │
│ (skill pin + 状态机) │
└────────────┬───────────────┘
↓
┌────────────┬────────┴───────┬────────────┐
↓ ↓ ↓ ↓
健康录入 健康评估 报告归档 健康档案
(值/照片) (基线/趋势) (OCR→档案) (MindSpace 健康区)
4.1 H5 主入口(功能完整,主战场)
H5 是主入口,因为需要结构化表单、数值键盘、Timeline 图表、可编辑确认卡、档案浏览。
建议做成独立页面而非普通聊天里的一个 skill 按钮:
/health 健康首页(今日录入状态 + 最近趋势 + 待确认项)
/health/chat 健康助手会话(锁定通道)
/health/records Health Timeline
/health/documents 报告档案
/health/profile 基线 / 既往史 / 长期用药
/health/chat 使用独立会话空间,不与普通聊天会话混用(见 §7)。
4.2 服务号轻入口(随手录入,主打拍照/语音)
服务号的价值是随手:量完血压直接拍照发送。
进入方式两条,均有现成钩子:
- 自定义菜单点击 →
msgType === 'event'+eventKey === 'MEMIND_HEALTH' - 关键词命中 → 文本命中「健康助手」「健康」「录血压」等
进入后回复固定菜单(服务号仅文本/图文,用数字选择):
已进入【健康助手】专用通道
本通道只处理健康相关内容,数据自动归入你的健康档案。
请回复数字:
1 健康录入(血压/心率/体重/血氧/体温/睡眠/症状)
2 上传报告(直接发送照片即可)
3 健康评估(看看最近和平时比有什么变化)
4 查看健康档案
0 退出健康通道
关键约束:
- 进入后所有消息(含图片)只走健康链路,直到用户回复
0或超时。 - 建议 30 分钟无交互自动退出,退出时必须明确告知,避免用户以为还在通道内。
- 通道状态与现有 canary/stable 会话钉选逻辑并存,不改动现有分流。
5. 防漂移三层保障
这是本设计的核心,对应用户最关心的「不允许漂移,要精准」。
5.1 第一层:Skill Pin(复用现有短路)
现有 chat-intent-router.mjs 已具备完整短路能力:
readSelectedChatSkillId(message)读取metadata.memindRun.selectedChatSkillbuildSkillSelectionClassification()返回route: agent_orchestration、confidence: 1、reason: '用户已选择 skill'- 结果:LLM 意图分类器根本不会被调用
健康通道发消息时携带:
{
"metadata": {
"memindRun": {
"selectedChatSkill": "health-assistant",
"healthChannel": {
"sessionKind": "health",
"step": "await_value",
"pendingDraftId": "drf_...",
"metricSet": "blood_pressure"
}
}
}
}
服务号侧从会话状态读出「当前在健康通道」,注入相同 metadata。
agent-run-routes.mjs 的 enforceSelectedSkillRuntime 进一步固定 toolMode / taskType / requiredExecutor,保证工具集不越界。
这一层解决「会不会被路由到别的 skill」。
5.2 第二层:Channel 状态机(解决「这句话是什么意思」)
Pin 住 skill 不够 —— 用户说「137」,是血压还是体重?必须有显式状态机,不靠 LLM 猜。
IDLE
│ 选择「健康录入」
↓
AWAIT_METRIC_TYPE ──→ 展示可录入项(血压/心率/体重/血氧/体温/睡眠/症状/用药)
│ 选择「血压」
↓
AWAIT_CONTEXT ──────→ 晨起 / 睡前 / 服药后 / 其他(可跳过取默认)
│
↓
AWAIT_VALUE ────────→ 期望数值;接受手输 / 拍照 / 语音
│
↓
CONFIRM ────────────→ 结构化确认卡(可编辑)
│ 确认
↓
COMMITTED ──────────→ 写入 Observation + 返回 Timeline 即时反馈
完整状态转移表:
| 当前状态 | 期望输入 | 事件 | 下一状态 |
|---|---|---|---|
IDLE |
菜单选择 / 规则命中文本 / 图片 | select_action |
对应流程首状态 |
IDLE |
无法高置信解析 | ambiguous |
AWAIT_ACTION_CHOICE |
AWAIT_ACTION_CHOICE |
1/2/3/4 | choose |
对应流程首状态 |
AWAIT_METRIC_TYPE |
指标名 | pick_metric |
AWAIT_CONTEXT |
AWAIT_CONTEXT |
情境 / 跳过 | pick_context |
AWAIT_VALUE |
AWAIT_VALUE |
数值 / 图片 / 语音 | submit_value |
CONFIRM |
AWAIT_VALUE |
无关输入 | unexpected |
AWAIT_VALUE(回提示,不猜) |
CONFIRM |
确认 | commit |
COMMITTED |
CONFIRM |
修改 | revise |
AWAIT_VALUE |
CONFIRM |
放弃 | discard |
IDLE |
| 任意 | 0 / 「退出」 |
exit |
通道退出 |
| 任意 | 30 分钟无交互 | timeout |
通道退出(告知用户) |
状态机每一步都有明确的期望输入类型。用户在 AWAIT_VALUE 说「137/82」语义完全确定,不存在歧义。
若在某状态收到完全无关输入,通道不猜测,回:
当前正在录入「血压」。
- 直接发送数值,如 137/82
- 或拍照上传血压计读数
- 回复「取消」放弃本次录入
- 回复「0」退出健康通道
状态机应实现为纯函数(health-channel-state.mjs),输入 (state, event) 输出 (nextState, actions),便于完整单测覆盖。
5.3 第三层:意图不明时强制选择(D4)
IDLE 状态自由发言的判定顺序,确定性优先:
1. 确定性规则匹配(正则 / 关键词)→ 命中即执行,不调 LLM
2. 规则未命中 → LLM 做候选动作分类,要求返回 top-2 + confidence
3. confidence < 0.75 或 top-2 差距 < 0.15 → 不执行,返回选择卡
4. 用户选择后 → 进入状态机,此后无歧义
选择卡内容:
我不太确定你想做什么,请选择:
1 记录健康数据
2 查看健康评估
3 上传 / 归档报告
4 查看健康档案
规则库设计(示例,需持续维护并单测):
| 意图 | 规则示例 | 落地动作 |
|---|---|---|
| 血压录入 | (\d{2,3})\s*[//]\s*(\d{2,3}),或含「血压」+ 两个数 |
metric_set=blood_pressure → CONFIRM |
| 体重录入 | 含「体重」+ (\d{2,3}(\.\d)?) |
metric_set=weight |
| 心率录入 | 含「心率/脉搏」+ (\d{2,3}) |
metric_set=heart_rate |
| 血氧 | 含「血氧/SpO2」+ (\d{2,3}) |
metric_set=spo2 |
| 体温 | 含「体温/发烧」+ (3\d(\.\d)?) |
metric_set=temperature |
| 睡眠 | 含「睡了」+ 时长表达 | metric_set=sleep |
| 症状 | 含「头晕/胸闷/乏力/心慌/疼」 | metric_set=symptom |
| 评估 | 「最近怎么样」「帮我看看」「有没有异常」 | 评估流 |
| 档案 | 「我的档案」「历史记录」「报告」 | 档案流 |
关键原则:宁可多问一次,也不要错记一条。错误的 Observation 会污染 Personal Baseline,代价远高于多一次交互。
歧义值必须强制确认,例如「体重 137」显然异常但格式合法 → 走合理性校验(§6.2)标记 suspect。
6. 拍照精准记录设计
最易漂移的环节,单独设计。
6.1 先分清两类图片
| 类型 | 内容 | 归属 |
|---|---|---|
| 设备读数照 | 血压计、体重秤、血氧仪、体温计屏幕 | → HealthObservation(数值) |
| 医疗报告 | 体检报告、化验单、影像报告、处方 | → HealthDocument(档案)+ 抽取指标 |
判定策略分层,成本递增:
- 用户已在
AWAIT_VALUE(先选「血压」再拍照)→ 类型已确定,直接按血压解析。这是最精准路径,产品应主推。 IDLE直接发图 → 轻量视觉判断「设备屏幕 vs 文档」,然后回确认:「这看起来是血压计读数,要记录为血压吗?」- 判断不确定 → 直接给选项:「这张图是:1 设备读数 2 体检/化验报告 3 其他」
产品引导上把「先选类型再拍」做成主路径:
健康录入 → 选「血压」 → 「请输入数值或拍照上传」 → 拍照
先验极强,几乎不可能错。
6.2 设备读数:抽取 → 确认 → 提交
绝不允许「拍照即入库」。
图片
↓
① 图片指纹(内容 hash)去重 ← 防止同一照片重复录入
↓
② 结构化抽取(视觉模型 + 强约束 schema)
↓
③ 合理性校验(Rule Engine,确定性)
↓
④ 生成 ObservationDraft(草稿态,不进基线)
↓
⑤ 用户确认卡(H5 可编辑表单;服务号文本 + 回复确认)
↓
⑥ 确认后 → HealthObservation(正式)+ 原图存档 + 抽取留痕
第 ② 步要求模型输出严格 schema:
{
"metric_set": "blood_pressure",
"systolic": 137,
"diastolic": 82,
"pulse": 72,
"device_time": "2026-09-02 07:20",
"confidence": { "systolic": 0.97, "diastolic": 0.95, "pulse": 0.88 },
"unreadable": []
}
第 ③ 步校验规则(确定性,不经 LLM):
| 校验 | 规则 | 不通过处理 |
|---|---|---|
| 量程 | 收缩压 60–260;舒张压 40–160;脉搏 30–200;SpO₂ 50–100;体温 33–43 | 标记 unreadable,要求重拍或手输 |
| 逻辑 | 收缩压 > 舒张压 | 提示可能识别颠倒,要求确认 |
| 基线偏离 | 与个人基线偏离 > 50% | 标记 suspect,强制人工确认 |
| 置信度 | 任一字段 confidence < 0.9 |
该字段标记待确认,高亮展示 |
第 ⑥ 步的留痕至关重要:raw_payload 保留原始抽取 JSON、图片引用、用户是否修改过。将来审计「这条 137 是怎么来的」可完整回溯,也是 Event Engine evidence chain 的基础。
6.3 时间戳:隐藏的漂移源
「什么时候测的」与「值是多少」同样重要,且极易出错。优先级:
1. 设备屏幕显示时间(OCR 得到) ← 最准
2. 图片 EXIF 拍摄时间 ← 次准
3. 用户手动指定 ← 兜底
4. 消息到达时间 ← 最后手段,必须提示用户
若只能用第 4 种,确认卡必须明确写:「测量时间按当前时间记录,如非刚测请修改」。
必须支持补录改时间 —— 否则 Timeline 全错,基线随之失真。
6.4 报告类:归档与指标抽取分离
报告图片 / PDF
↓
① 归档(必做,成功率高)
→ HealthDocument:类型、机构、报告日期、原文件、OCR 全文
→ 原文件落入 MindSpace 健康分区资产
↓
② 指标抽取(尽力而为,允许失败)
→ 化验项映射:血脂 / 血糖 / 肝功 / 肾功 / 血常规 ...
→ 每项带 confidence + 参考范围
→ 高置信项 → ObservationDraft(待确认)
→ 低置信项 → 仅存 OCR 文本,不入结构化
归档必须成功,抽取允许失败。 即使指标识别不出,用户报告也已安全存进档案随时可查 —— 这是产品底线价值。
6.5 与现有视觉守卫的兼容(硬约束)
docs/regression-guards/vision-turn-read-image-isolation.md 的守卫必须继续生效:
- 带图轮次必须摘掉
read_image - 工具图片污染必须触发会话轮换
健康通道的图片处理必须走同一套 chat-image-turn-scope.mjs,禁止另开绕过守卫的路径。健康通道只是在其之上叠加「结构化 schema 约束 + 确认闸门」,底层图片轮次隔离不变。
7. 会话隔离(D5)
「不影响现有功能」的关键。
普通会话 健康会话
───────── ─────────
sessionKind: 'chat' sessionKind: 'health'
完整 skill 集 仅 health-assistant + 白名单工具
Memory V2 全量 resolve 健康上下文 + 有限 profile
可发布任意分区页面 仅健康区(强制加密)
具体隔离点:
- 会话独立:健康会话使用独立
session_id命名空间。普通聊天历史不注入健康会话;健康数据不会出现在普通聊天上下文。 - 工具白名单:健康会话内由
enforceSelectedSkillRuntime限定工具集 —— 仅允许健康数据读写、文档归档、健康区页面生成。不允许edit_file写非健康区路径,不允许公开发布。 - Memory 分轨:Observation 走独立数据面;仅「本人对睡眠敏感」这类关联假设晋升 Memory V2,带
health_correlation标记。他人健康数据只进备忘(D2)。 - 引导跳转:普通聊天识别到健康意图时,只回引导,不落库:
你想记录健康数据吗?健康数据需要在健康助手通道里录入,
这样才能保证记录准确并纳入你的健康基线分析。
[进入健康助手 →]
- 服务号状态:健康通道状态存于服务号会话状态,与现有 canary/stable 钉选并存。
8. 数据模型(Page Data 落地,D3)
8.1 分层存储决策
| 数据 | 存储 | 理由 |
|---|---|---|
| 健康数值(Observation) | Page Data 用户隔离 PG schema | 结构化、可聚合、已有隔离与审计 |
| 报告原文件(图片/PDF) | MindSpace 健康分区资产(h5_assets) |
Page Data 不适合大文件 |
| 报告元数据 + OCR 全文 | Page Data(PG) | 需检索与关联 |
| 基线 / 事件 | Page Data(PG),P1 | 由引擎写入 |
| 关联假设 | Memory V2 | 需对话召回 |
| 提醒 / 复诊 | h5_schedule_items |
复用现有提醒链路 |
注意:报告文件与其元数据分离存储,通过 asset_id 关联。
8.2 表设计(PostgreSQL,用户隔离 schema)
-- 健康档案(本人,1 行)
CREATE TABLE IF NOT EXISTS health_profile (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
birth_year INT NULL,
sex TEXT NULL,
height_cm NUMERIC(5,1) NULL,
chronic_conditions JSONB NOT NULL DEFAULT '[]'::jsonb,
long_term_medications JSONB NOT NULL DEFAULT '[]'::jsonb,
notes TEXT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- 原子观测(所有体征 / 行为 / 主观状态的唯一写入格式)
CREATE TABLE IF NOT EXISTS health_observations (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
observed_at TIMESTAMPTZ NOT NULL, -- 测量时刻,非录入时刻
metric_type TEXT NOT NULL, -- bp_systolic | bp_diastolic | hr | spo2 | weight | temperature | sleep_minutes | symptom | ...
value_num NUMERIC(10,2) NULL,
value_text TEXT NULL, -- 症状等枚举/文本
unit TEXT NULL,
context TEXT NULL, -- morning | evening | post_medication | fasting | other
source TEXT NOT NULL, -- manual | photo | voice | ocr_report | apple_health | ble_device
source_ref TEXT NULL, -- 图片 hash / asset_id / 设备标识
time_source TEXT NOT NULL, -- device_screen | exif | user_specified | message_arrival
confidence NUMERIC(4,3) NULL,
quality_flag TEXT NULL, -- ok | suspect | user_corrected
raw_payload JSONB NULL, -- 原始抽取结果 + 审计留痕
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMPTZ NULL
);
CREATE INDEX IF NOT EXISTS idx_health_obs_metric_time
ON health_observations (metric_type, observed_at DESC);
-- 幂等:同一图片 + 同一指标 + 同一测量时刻不重复入库
CREATE UNIQUE INDEX IF NOT EXISTS uq_health_obs_dedup
ON health_observations (metric_type, observed_at, source_ref)
WHERE source_ref IS NOT NULL AND deleted_at IS NULL;
-- 待确认草稿(不进基线引擎)
CREATE TABLE IF NOT EXISTS health_observation_drafts (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
draft_key TEXT NOT NULL UNIQUE,
metric_set TEXT NOT NULL, -- blood_pressure | weight | spo2 | ...
extracted JSONB NOT NULL, -- 抽取结果 + confidence
validation JSONB NOT NULL, -- 校验结果 + 标记
status TEXT NOT NULL DEFAULT 'pending', -- pending | committed | discarded | expired
channel TEXT NOT NULL, -- h5 | wechat
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMPTZ NOT NULL,
committed_at TIMESTAMPTZ NULL
);
-- 医疗资料档案
CREATE TABLE IF NOT EXISTS health_documents (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
doc_type TEXT NOT NULL, -- checkup | lab | imaging | prescription | discharge | other
report_date DATE NULL,
institution TEXT NULL,
title TEXT NOT NULL,
asset_id TEXT NULL, -- MindSpace 健康分区资产引用(原文件)
ocr_text TEXT NULL,
extracted_metrics JSONB NOT NULL DEFAULT '[]'::jsonb,
extraction_status TEXT NOT NULL DEFAULT 'pending', -- pending | partial | done | failed
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMPTZ NULL
);
-- 个人基线(P1,引擎写入)
-- 注意:基线必须按 context 分层(见 §15 O3)。晨间与晚间血压生理上不同,
-- 混算基线会同时掩盖晨峰异常并制造假偏离。
CREATE TABLE IF NOT EXISTS health_baselines (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
metric_type TEXT NOT NULL,
context TEXT NOT NULL, -- morning | evening | any(不分层指标用 any)
window_days INT NOT NULL, -- 7 | 30 | 90
computed_at TIMESTAMPTZ NOT NULL,
sample_count INT NOT NULL,
mean_val NUMERIC(10,2) NULL,
std_val NUMERIC(10,2) NULL,
p25_val NUMERIC(10,2) NULL,
p75_val NUMERIC(10,2) NULL,
typical_low NUMERIC(10,2) NULL,
typical_high NUMERIC(10,2) NULL,
maturity TEXT NOT NULL, -- cold | weak | stable
UNIQUE (metric_type, context, window_days)
);
-- 健康事件(P1)
CREATE TABLE IF NOT EXISTS health_events (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
event_type TEXT NOT NULL, -- threshold_breach | baseline_drift | missed_measurement | symptom_cluster | correlation_hypothesis
severity TEXT NOT NULL, -- info | watch | alert
detected_at TIMESTAMPTZ NOT NULL,
rule_id TEXT NULL, -- 可审计:哪条规则触发
metrics_involved JSONB NOT NULL DEFAULT '[]'::jsonb,
evidence_observation_ids JSONB NOT NULL DEFAULT '[]'::jsonb,
agent_summary TEXT NULL, -- LLM 生成,不可作为 detection 依据
status TEXT NOT NULL DEFAULT 'open', -- open | acknowledged | resolved | dismissed
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- 关联假设(P1;晋升到 Memory V2 后记录 memory_item_id)
CREATE TABLE IF NOT EXISTS health_correlations (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
factor_a TEXT NOT NULL, -- sleep_deterioration
factor_b TEXT NOT NULL, -- bp_elevation
confidence NUMERIC(4,3) NOT NULL,
occurrence_count INT NOT NULL DEFAULT 1,
first_seen_at TIMESTAMPTZ NOT NULL,
last_seen_at TIMESTAMPTZ NOT NULL,
user_confirmed BOOLEAN NOT NULL DEFAULT FALSE,
memory_item_id TEXT NULL
);
设计要点:
health_observations是唯一写入格式。血压拆成bp_systolic/bp_diastolic两行,便于统一基线计算;确认卡在 UI 层合并展示。- 所有含软删除的表都带
deleted_at(Page Datasoft_delete硬要求)。 - 唯一索引实现幂等:重复发送同一张照片不会产生重复观测。
time_source显式记录时间来源,用于后续数据质量分析。
8.3 Dataset 注册
每个表独立注册 dataset,遵守 page-data-collect 的「一任务一表一 dataset」原则。
{
"name": "health_observations",
"table": "health_observations",
"description": "MeMind Health 个人健康观测记录",
"actions": ["read", "insert", "update", "softDelete"],
"columns": {
"read": ["id", "observed_at", "metric_type", "value_num", "value_text", "unit", "context", "source", "quality_flag", "created_at"],
"insert": ["observed_at", "metric_type", "value_num", "value_text", "unit", "context", "source", "source_ref", "time_source", "confidence", "quality_flag", "raw_payload"],
"update": ["observed_at", "value_num", "value_text", "context", "quality_flag"]
}
}
关键安全约束:raw_payload、source_ref、ocr_text 不得出现在任何公开页的 read 白名单中(见 §9.4)。
8.4 写入路径(重要澄清)
Page Data 有两条 API:公开页 API 与 Owner Admin API。健康数据的写入不走公开页 API:
H5 健康录入 / 服务号录入
→ 平台内登录态请求
→ health-observation-service.mjs
→ Owner 侧 Page Data 访问(/api/admin/page-data/* 或服务端直连 dataset 授权)
→ 用户隔离 PG schema
MindSpace 健康区页面(Timeline / 档案展示)
→ 走公开页 API,但仅 read
→ 且只读「摘要快照 dataset」,不直连原始 observations(见 §9.4)
这样原始健康数据永不通过公开页 API 暴露。
9. MindSpace 健康区:强制加密
9.1 新增系统分区
在 mindspace.mjs 的 SYSTEM_CATEGORIES 增加一项(设计,尚未实现):
{
code: 'health',
name: '健康档案区',
visibilityPolicy: 'private',
aiAccessPolicy: 'explicit_asset_grant', // AI 需显式授权才能读具体资料
publishPolicy: 'password_required', // 新增策略值
sortOrder: 30,
}
h5_space_categories.publish_policy 是 VARCHAR(64),新增枚举值不需要改表结构。
现有系统分区(oa / public / draft / archive)策略保持不变。
9.2 发布闸门(服务端硬阻断)
publish(pageId, accessMode, password)
↓
category = resolveCategory(pageId)
↓
if (category.publishPolicy === 'password_required') {
if (accessMode === 'public') → 拒绝:健康区禁止完全公开
if (!password && !hasExistingPasswordHash) → 拒绝:必须设置口令
if (accessMode not in ['password', 'login_required']) → 拒绝
}
↓
继续现有发布流程(不改动其他分区行为)
必须是服务端阻断,不是前端禁用选项。前端仅额外做「不展示完全公开选项」的体验优化。
口令须满足现有平台约束:≥ 6 位,bind 时必须传入并写入 password_hash。禁止只改 access_mode 不写 password_hash。
9.3 访问体验:本人免密,外部必密
访问健康页
↓
是 owner 且已登录?
├─ 是 → 直接放行(不要求输口令)
└─ 否 → 要求口令 → 校验 → 发 page-data token → 放行
- 健康区默认
password模式(可分享给医生)。 - owner 登录态访问短路口令校验。
- 口令可重置、令牌可撤销,复用现有能力:
POST /api/admin/page-data/policies/:pageId/password/resetPOST /api/admin/page-data/policies/:pageId/tokens/revoke
9.4 分享安全:快照而非直连(关键设计)
password 模式无法区分访客身份 —— 拿到口令的人能读该页授权的所有行。因此:
禁止健康区公开页直接 read health_observations / health_documents。
正确做法:为分享场景生成只读摘要快照 dataset:
CREATE TABLE IF NOT EXISTS health_share_snapshots (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
snapshot_key TEXT NOT NULL UNIQUE,
scope TEXT NOT NULL, -- clinic_summary | trend_30d | lab_selected
period_start DATE NOT NULL,
period_end DATE NOT NULL,
payload JSONB NOT NULL, -- 已脱敏、已聚合的展示数据
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMPTZ NULL,
revoked_at TIMESTAMPTZ NULL
);
- 分享页只
readhealth_share_snapshots,且columns.read仅含payload等必要字段。 - 快照由用户显式生成,范围、时间窗、包含项由用户勾选。
- 快照可设过期时间、可撤销。
- 原始
observations/ocr_text/raw_payload永不进入任何公开页授权。
这解决了「分享给医生」与「数据最小暴露」的矛盾。
9.5 SEO 自动安全(无需改动)
mindspace-index-policy.mjs 中 INDEXABLE_ACCESS_MODE = 'public',isPublicationIndexable() 要求 accessMode === 'public'。
健康区强制 password / login_required 后 → 自动 noindex,无需额外改 SEO 逻辑。
此行为落在现有回归守卫 docs/regression-guards/mindspace-seo-geo.md 保护范围内,改动健康区时须一并跑 npm run verify:seo-geo。
9.6 健康区内容结构
健康档案区/
timeline/ 健康时间线页(加密,owner 免密)
documents/ 报告归档
2026-08-体检报告/
2026-09-血脂化验/
assessments/ 评估摘要
shares/ 就诊摘要快照页(口令 + 可撤销 + 可过期)
10. Health Timeline 与 Personal Baseline
10.1 Health Timeline(日聚合视图,非存储层)
2026-09-01
BP 128/76
HR 68
Weight 67.2kg
Sleep 6h32m
Symptom none
2026-09-02
BP 137/82 ↑ vs 30d baseline +9.8%
HR 72
Weight 67.4kg
Sleep 5h10m ↓ vs 30d baseline -17%
7-day trend:
BP baseline deviation +9.8%
Sleep baseline deviation -17%
实现:health_observations 按日 rollup。P0 用查询时聚合;数据量增长后再引入物化视图或定时 job。
10.2 Personal Baseline(P1)
滚动窗口,每日凌晨重算 7 / 30 / 90 天基线。
冷启动策略(maturity 字段):
| 阶段 | 样本量 | maturity | 行为 |
|---|---|---|---|
| 冷启动 | < 7 个有效点 | cold |
只展示原始值,不产生偏离事件 |
| 弱基线 | 7–29 | weak |
可产生 info 级提示,不发 alert |
| 稳定 | ≥ 30 | stable |
全量启用 Trend Engine |
这条很重要:基线未成熟就报警会摧毁用户信任。
有效点定义:quality_flag != 'suspect' 且 deleted_at IS NULL。suspect 只是待裁决状态 —— 用户确认后必须落到 ok 或 user_corrected,不得长期停留,否则真实的恶化会被永久过滤掉。
样本量按 context 分层计算(O3 决策的直接后果):晨间血压基线只统计 context='morning' 的观测。这意味着若用户每天只测一次晨间血压,达到 stable 需 30 天;若晨晚各一次,两条基线各自独立计数,不会因为总数翻倍而提前成熟。
weight、sleep_minutes 等本身不分晨晚的指标使用 context='any'。
10.3 Rule Engine(确定性)
| 规则类 | 示例 | 严重度 |
|---|---|---|
| 绝对阈值 | SpO₂ < 90% | alert |
| 绝对阈值 | 收缩压 ≥ 180 或 舒张压 ≥ 110 | alert |
| 漏测 | 连续 3 天无晨间血压 | watch |
| 新症状 | 连续 3 天报告同一症状 | watch |
| 药物变化 | 新增/停用药物后 7 天内加强监测 | info |
输出 health_events(event_type='threshold_breach', rule_id=...)。
10.4 Trend Engine(统计,不用 LLM)
| 检测项 | 方法 |
|---|---|
| 基线漂移 | 近 14 天均值 vs 90 天基线,偏离 > 阈值且持续 ≥ N 天 |
| 变异性增大 | 近 7 天 std > 历史 std × 1.5 |
| 多指标联动 | 睡眠 ↓ + 静息 HR ↑ + BP ↑ 同期发生 → cluster |
输出 health_events(event_type='baseline_drift' | 'symptom_cluster')。
10.5 Event Engine → Agent
Event Engine 合并 Rule + Trend 结果,去重、分级、聚合为 Cluster,然后才调用 Agent。
Agent 的输入是结构化 Event,不是原始时序:
{
"cluster_id": "...",
"window": "14d",
"baseline_maturity": "stable",
"findings": [
{ "metric": "bp_systolic", "deviation": "+8%", "baseline": "119-126", "recent": "132-138", "days_above": 5 },
{ "metric": "sleep_minutes", "deviation": "-17%" }
],
"open_questions": ["recent_insomnia", "medication_change", "alcohol", "stress"]
}
Agent 职责:
- 用自然语言解释「发生了什么变化」(不是诊断)
- 提出 1–2 个高价值追问
- 给出行动建议:复测计划 / 记录给医生 / 何时就医
- 将用户回答与关联假设写入
health_correlations→ 满足条件后晋升 Memory V2
Agent 不能反向修改 Event 严重度 —— 那是 Engine 的职责。
理想输出示例:
过去 30 天整体生命体征较稳定。最近 7 天晨间收缩压较过去 90 日个人基线上升约 8 mmHg,其中 5 天高于近期常态;同期睡眠时间有所下降。建议未来 7 天按规范继续早晚测量,如持续偏高,可将趋势记录提供给医生评估。
10.6 关联假设的长期学习
第一次失眠期 → BP +7%
第二次失眠期 → BP +9%
第三次失眠期 → BP +8%
↓
occurrence_count = 3, confidence ↑
↓
晋升 Memory V2(label: health_correlation)
↓
"这个人的血压可能对睡眠变化比较敏感"
术语纪律:必须称「关联假设」,禁止表述为医疗诊断或因果结论。
11. 零侵入保证与灰度
11.1 四条保证
- 全局 Feature Flag:
MEMIND_HEALTH_ENABLED=false时,健康入口不展示、路由不注册、服务号关键词不生效,现有链路行为不变。 - 只做加法:意图路由不改判定逻辑,健康会话天然携带
selectedChatSkill,走的是已存在的短路分支。 - 发布闸门只对
health分区生效:其他分区publish_policy不变,现有发布行为不受影响。 - fail-open:抽取/基线服务不可用时,退化为「仅归档原图 + 提示稍后重试」,不阻塞会话、不影响普通聊天。
11.2 灰度
沿用仓库既有 canary 模式:按 user_id 灰度,先内部账号 → 小流量 → 全量。健康引擎(P1)应支持 off / shadow / active 三态,shadow 模式下只记录会产生哪些事件、不实际通知用户。
11.3 必须遵守的既有守卫
改动触及以下路径时,按 AGENTS.md 规则必跑对应 verify:
npm run verify:mindspace-publish-guards
npm run verify:mindspace-publish-guards:full
npm run verify:seo-geo
npm run verify:seo-discovery
npm run verify:page-data
特别注意:
chat-image-turn-scope.mjs— 带图轮次read_image隔离mindspace-index-policy.mjs— 私有页 noindexmindspace-page-sync-service.mjs— remote 模式也必须 sync public HTML
11.4 新增测试
health-channel-state.test.mjs 状态机全转移覆盖 + 无关输入不猜测
health-extraction.test.mjs schema 约束 / 量程校验 / 置信度门限
health-observation-service.test.mjs 幂等去重 / 时间来源优先级 / suspect 标记
health-baseline-engine.test.mjs 冷启动 maturity / 有效点过滤
health-event-engine.test.mjs 规则触发 + evidence chain 完整性
health-publish-guard.test.mjs 健康区禁止 public 发布(硬阻断)
health-share-snapshot.test.mjs 分享页不得授权原始 observations
12. 合规与产品边界
- 非医疗器械声明:MeMind Health 是健康记录与趋势提醒,不提供诊断。
- 关联假设 ≠ 诊断:Agent 输出统一附 disclaimer 模板。
- Evidence chain 可追溯:每条 alert 可展开到
evidence_observation_ids+rule_id。监管与客诉必备。 - 数据分级:健康观测为敏感数据。分享须用户显式生成快照、可过期、可撤销。
- LLM 边界:detection 层零 LLM;explanation 层 LLM 输入仅为结构化 Event。
- 删除权:用户可删除任意 Observation / Document;删除后基线须重算。
12.1 隐私默认值
- 健康区默认
private,aiAccessPolicy: explicit_asset_grant。 - Agent 读取具体报告内容需显式授权,不默认全量注入上下文。
- 健康数据不参与 SEO/GEO 收录(§9.5 自动保证)。
12.2 数据保留
复用 Memory V2 生命周期思路:Observation 长期保留(健康趋势需要长历史);但抽取中间产物(原始视觉输出)可设较短保留期。
12.3 P1 存储迁移预案
若 Page Data 聚合性能不足,迁移到专用表的前提:
- 保持
health_observations列结构不变,仅换存储位置 - 提供双写 + 校验期
- 迁移前后 Timeline 与基线结果必须一致(回归对账脚本)
13. 分阶段路线
P0 — 验证入口与录入精度(不做引擎)
- H5
/health入口 + 通道状态机 - 手动录入 + 拍照录入(三段式确认)
- Health Timeline 展示
- MindSpace 健康区(强制加密)+ 报告归档
- 服务号:关键词/菜单进入 + 拍照上传 + 确认落库
health-assistantskill v0(读 Timeline 摘要回答「最近怎么样」)
不做:基线、Event Engine、设备接入、分享。
验证指标:
- 拍照识别经确认后准确率 ≥ 98%
- 通道内漂移事件(被路由到非健康 skill)= 0
- 健康区无法以
public模式发布(自动化测试保证) - 连续 14 天录入完成率
P1 — Personal Baseline + Event Engine(核心命题验证)
- Baseline Engine(7/30/90 天 + maturity)
- Trend Engine + Rule Engine v1
- Event Engine + Agent 解释
- 关联假设 v0 → Memory V2 晋升
验证方式:回溯已有 30 天数据,Event Engine 能否在用户主观感知前 3–7 天产生 watch 事件;并访谈「这条提醒有用吗?会不会太吵?」
P2 — 设备接入与提醒
- Apple Health / 蓝牙设备 Connector(设备可信 → 免确认路径,但异常值仍标
suspect) - 分级通知策略(
info静默 /watch日摘要 /alert即时)
P3 — 医疗纵深
- 用药 Timeline(整合
schedule-assistant) - 检验指标长期趋势
- 就诊摘要加密分享页(§9.4 快照机制)
P4 — 授权分享
- 本人授权家人/医生只读摘要(非代录、非原始数据)
- 机构侧只读接口(如有需求)
14. P0 前置最小实验(先做,成本极低)
在写任何平台代码前,用 14 天人工实验验证核心假设。
完整可执行方案见 memind-health-p0-experiment.md,此处仅摘要。
参与者:8–10 人(最低 5 人);有意纳入更可能出现波动的人群
工具: 现有 Page Data 匿名问卷页(方案 A),无需新代码
D1–D7 : 基线建设期,每日录入晨间 BP + 睡眠 + 症状 + 扰动因素
D8 : 手工计算 7 天基线(Excel 即可)
D8–D14: 继续录入,研究者每日手工标记偏离(不告知参与者)
D14 : 盲态访谈(必须在揭盲前完成)
主结局 H1(一定可测):14 天晨测完成率 ≥ 80% 的参与者 ≥ 3/5。
次结局 H2(可能不可判定):手工偏离标记早于主观察觉 ≥ 3 天的参与者 ≥ 3/5。
关键设计取舍:
- H1 是主结局,不是 H2。 若用户坚持不下来,再精妙的基线算法都无意义;此时正确反应是把设备自动同步提到最高优先级,而不是优化算法。
- 14 天内可能无人偏离,这是最可能的失败模式,方案中已预设无偏离处理路径,不得因 H2 无结论就否定项目方向。
- 漏检比误报更值得研究:用户明确感到变化而基线检测不到,说明指标组合或窗口有问题。
- 顺带产出照片校验集:参与者同时提供设备屏幕照片 + 手工录入值,形成
(图片 → 正确值)标注对,直接用作 P0 拍照识别的回归用例。这是很难另外获得的资产。
15. 已决事项(O1–O6)
以下六项已决策,实现必须遵守。变更需重新评审本章。
O1 症状录入:固定枚举 + 严重度 + 可选备注
决策:采用固定枚举,附三级严重度,允许自由备注,但备注不参与结构化分析。
枚举(可多选;无症状必须显式选「无」):
无 / 头晕 / 头痛 / 胸闷 / 心慌心悸 / 乏力 / 气短 / 下肢水肿 / 失眠 / 其他
严重度(每个勾选项必填):
轻 = 1 / 中 = 2 / 重 = 3
自由备注:可选,存 value_text,仅供 Agent 解释时参考
理由:symptom_cluster 检测需要可比较的离散值。自由文本会产生「有点晕」「头晕晕的」「晕」等语义漂移,无法计数、无法判断「连续 3 天同一症状」。
存储:每个症状一行 health_observations,metric_type='symptom',value_text= 枚举码,value_num= 严重度。这样症状严重度也可做趋势(如「头晕从轻转中」)。
「无症状」必须显式记录,不能靠「没有记录」推断 —— 否则无法区分「今天没症状」与「今天忘了记」。
O2 语音录入:必须确认,不得直接落库
决策:语音识别结果一律进入 CONFIRM 状态,禁止跳过确认。
理由:数字类语音识别错误率显著高于文本,且错误形态危险 —— 「一百三十七比八十二」可能识别为「137、82」也可能是「130、782」。血压场景一次错记就污染基线。
附加要求:语音录入的确认卡必须同时展示识别原文,让用户能判断是识别错了还是自己说错了:
听到:「血压一百三十七比八十二」
识别:收缩压 137,舒张压 82
确认保存 / 修改 / 重说
O3 血压强制记录情境,且基线按情境分层
决策:血压录入强制记录情境,三选一,按测量时刻自动预选,用户可改。
morning 晨间(默认:测量时刻 < 10:00)
evening 晚间(默认:测量时刻 ≥ 18:00)
other 其他(10:00–18:00 默认,或用户手动指定)
这不只是一个字段 —— 基线必须按 context 分层计算(已反映到 §8.2 health_baselines 的 UNIQUE (metric_type, context, window_days))。
理由(这是本次评审中最重要的修正):晨间血压与晚间血压生理上是不同指标,个体内可差 10–20 mmHg。若混算基线:
- 晨峰升高会被晚间的低值稀释 → 漏掉最有临床意义的异常
- 用户某天只测了晚间 → 与混合基线比较 → 产生假偏离
两种错误方向相反,但都由同一个原因造成。因此分层是必需的,不是优化项。
代价:达到 stable 所需天数不因多测而减少(见 §10.2)。这个代价可以接受 —— 宁可基线成熟慢,不要基线本身是错的。
other 情境的观测记录但不参与晨/晚基线计算,仅在 Timeline 展示。
O4 报告 OCR:复用现有图片/文件分析链路,不新建 OCR 服务
决策:健康侧不实现独立 OCR。复用仓库现有的图片与文件分析能力(服务号侧 media analysis、Agent 侧图片/文件读取),健康域只在其之上叠加两层:
现有图片/文件分析链路(不改动)
↓
health-extraction.mjs
├─ 强约束输出 schema(metric_set + 字段 + confidence)
└─ 合理性校验(量程 / 逻辑 / 基线偏离 / 置信门限)
↓
ObservationDraft(待确认)
理由:重复实现 OCR 会造成两套图片处理路径,直接威胁 chat-image-turn-scope.mjs 的回归守卫(带图轮次 read_image 隔离、工具图片污染触发会话轮换)。健康通道必须走同一条底层路径。
实施前置检查:动工前需确认现有链路对「多页 PDF」「长图化验单」的支持程度。若不支持,应作为独立需求补齐通用能力,而不是在健康域内私建分支。
O5 alert 通知:不承诺推送,主机制为「下次进入即见」
决策:alert 触达不作为产品承诺。核心机制是进入即见,推送为 best-effort 补充。
分级策略:
| 严重度 | 触达方式 |
|---|---|
info |
静默,仅健康首页与 Timeline 可见 |
watch |
进入即见 + 可选日摘要(用户须主动开启) |
alert |
进入即见(置顶未读)+ 48 小时内有交互时发服务号客服消息 + 已订阅者发订阅通知 |
理由:服务号客服消息受 48 小时交互窗口限制,订阅通知需用户主动订阅且有频次场景限制;H5 无主动推送能力。恰恰是长期不互动的用户最需要提醒,而这类用户技术上最难触达。
因此产品措辞必须修正:
禁止:「异常时我们会通知你」
应为:「异常会记录在你的健康档案,并在你下次进入时优先展示」
实现要求:任何入口进入健康通道时(无论何种原因),必须先展示未读 alert,且未读状态在用户明确确认前不清除。
同时:应引导用户主动订阅服务号通知,并在引导文案中说明原因,而不是默认用户已可触达。
O6 偏离阈值:P0 不定死,由实验数据标定
决策:不在设计阶段固化阈值。P0 采用下列初始建议值,并在前置实验与 P0 数据积累阶段完成标定。
初始建议值(仅供实验期手工判定与 P1 起点,非最终值):
| 指标 | 单日标记 | 持续偏离(触发事件) |
|---|---|---|
| 晨间收缩压 | dev% ≥ +5% 或 z ≥ +1.5 |
连续 ≥ 2 天同向 → watch;≥ 5 天或 dev% ≥ +10% → alert 候选 |
| 晨间舒张压 | 同上 | 同上 |
| 睡眠时长 | dev% ≤ -15% 或 z ≤ -1.5 |
连续 ≥ 3 天 → 参与 cluster 判定 |
| 静息心率 | dev% ≥ +10% 或 z ≥ +1.5 |
连续 ≥ 3 天 → 参与 cluster 判定 |
| 体重 | 7 日内变化 ≥ 1.5kg | 直接 watch |
双重判定(相对偏差 OR 标准分)的理由:相对偏差直观但忽略个体变异性 —— 变异大的人频繁误报;z 分数考虑变异性但小样本下 std 不稳定。两者取「或」,宁可多标记后人工/规则复核,也不要漏检。
标定流程:
前置实验(14 天,手工判定)
→ 记录首次偏离日 vs 主观察觉日
→ 计算不同阈值下的提前天数与误报数
→ 选择「提前 ≥ 3 天且误报可接受」的阈值组合
→ 写回本节,作为 P1 Trend Engine 初始配置
阈值必须可配置,不得硬编码在检测逻辑中 —— 后续需按真实数据持续调整。
16. 相关文档
- memind-health-p0-experiment.md — P0 前置 14 天实验可执行方案
- ENGINEERING_WORKFLOW_RULES.md
- PRODUCTION_RELEASE_RULES.md
- page-data-api-usage.md
- schedule-reminder-design.md
- memory-v2/README.md
- ai-mind-memind-integration-architecture.md
- regression-guards/vision-turn-read-image-isolation.md
- regression-guards/mindspace-seo-geo.md
- regression-guards/README.md