← 返回白皮书

版本变更记录

中医正气评估系统 · 项目白皮书附录 — 预警体系历次变更与迭代教训
V15.6 → V15.40 变更条目 17 条 体系设计原则 34 条 2026-11
本页由 whitebook.html 拆分而来:主白皮书为控制单页体积,把各预警项的历次变更记录与体系设计原则移到本页。主白皮书中出现的「见第 11.x 条 / 第 12.x 条」等引用,即指向本页对应条目;带 id 的条目(bp-v1535 / bp-v1535b / glucose-v1536 / baseline-v1537 / calib-v1538 / drink-v1539 / glucose-v1539)可直接用锚点访问,主白皮书的校准说明亦已改为跳转到本页。

📑 条目索引

  1. V15.10(2026-09-24)surge 阈值回退 45 → 34
  2. V15.12(2026-09-29)显示名由「久坐提醒」→「运动提醒」
  3. V15.23(2026-10-09)最短告警时长上移到 3 小时
  4. V15.24(2026-10-09)组合判据候选集限定为 bouts
  5. V15.11(2026-09-24)为何补判据 B
  6. V15.26(2026-10-09)加「尾部体动门」——只报「窗末仍在持续的那一段」
  7. ★ V15.32 修复效果
  8. V15.19(2026-10-08)修复
  9. ★★ 11.1 V15.34 未标定路径标「非测量值」且不给分级结论(重要变更)
  10. ★★ 11.2 V15.35 校准值改为「锚点 + 有界偏移」——校准值不再是常数(重要变更)
  11. ★★ 11.3 V15.35b 校准偏移「限幅」而非「归零」+ 危急值判定回退袖带锚点(修复 11.2 的偏移恒为 0)
  12. ★ V15.34
  13. ★★ 12.1 V15.36 校准血糖改「锚点 + 有界偏移」+ 补齐血糖新鲜度门(修复血糖恒等于上传值、陈旧值永久告警)
  14. ★★★ V15.37 校准值语义升级为 baseline——参考值是系统偏差观测点,不是输出底座(血压 + 血糖同步)
  15. ★★★ V15.38 校准改为 exp_decay 指数衰减(含 V15.37b 修复)——逐渐吸收、逐渐遗忘,自动退场
  16. ★★★ V15.39 傍晚饮酒判据 B 重写 + 「疑似饮酒信号·证据累积中」提示档
  17. ★★★ V15.39 血糖酒精混杂抑制 glucose.confound
  18. ★★★ V15.40 血压 Δln 改「比值(尺度不变量)口径」+ 血糖「现在」改短时滞窗
  19. 附:体系设计原则(34 条,V15.6 → V15.40)

A 预警体系历次变更记录

下列条目原位于主白皮书 §4.12「AI 预警体系」各预警项的说明列表内,现按所属预警项分组汇集于此。每条记录都写明现象 → 根因 → 改法 → 实测 → 一键回退,可直接作为变更审阅材料。

10|酒精影响 sym_alcohol_impact

15|运动提醒 sym_sedentary(V15.12 前称「久坐提醒」)

16|疲劳驾驶风险 sym_driving_fatigue(V15.16 新增,唯一不使用 PPG 生理量作为唯一输入的预警项)

1|饮酒信号 realtime_drinking(判据 A 窗 30 分钟 / 判据 B 用请求时刻 18–23 时段)

3|运动提醒 realtime_sedentary(窗 4 小时;V15.12 前称「久坐提醒」)

5|急性胸闷 realtime_chest_tightness(窗 30 分钟,有效样本不足时回退最近 900 拍;★ V15.32 重写判据)

10|疲劳驾驶风险 realtime_driving_fatigue(V15.16 新增)

11|血压危急值 realtime_blood_pressure_crisis(V15.30 新增;★ V15.34 未标定不给分级结论;★★ V15.35 校准值改「锚点 + 有界偏移」;★★★ V15.37 / V15.38 校准语义 baseline → exp_decay)

12|血糖偏高 realtime_blood_sugar_high(V15.30 新增;V15.31 基线口径修正;★ V15.34 未标定不给分层结论;★★ V15.36 校准血糖改「锚点 + 有界偏移」+ 补齐新鲜度门;★★★ V15.37→V15.38 校准语义 baseline → exp_decay;★★★ V15.39 饮酒窗口停用三项偏移)

附:体系设计原则(从历次迭代中提炼,也是后续新增预警项的强制自检清单)

  1. 判据可达性自检:任何加权和门槛都必须能被某些真实组合达到。V14.11 把胸闷阈值收紧到 0.55 的同时留下 0.30 + 0.20 = 0.50 < 0.55 的结构,使该项在数学上永不触发(实测 23/23 台 0 次)。此后每次调整权重都必须列出「可达触发组合表」。
  2. 信号质量门先于一切判定:PW 类量必须先过滤佩戴伪迹,否则「HR↑ AND PW↓」不是两条独立证据,而是同一物理事件(佩戴松脱)的两次读数。
  3. 语境门不可省:同一指标在不同语境下含义相反(运动时 HR 140 正常、静息时 HR 140 异常;睡眠中体动低正常、白天体动低才是久坐)。缺语境门的判据会系统性地把 A 场景的常态当成 B 场景的异常。
  4. 新增时间窗不得与既有校验路径相交:V15.6 首版因 19–22 时与既有夜间校验窗口重叠,出现「新路径 +1 反而让既有结果 −1」的抵消。
  5. 宁可漏报不可误报:这是全局门与各级「≥ 2 路信号」的共同出发点;但每一项的已知局限必须写进文档,未标定项不得当作已验证准确率。
  6. 阈值来源要分开标注:来自同行评审文献的阈值(如前述 6 条风险规则)与来自本系统人群分位标定或产品语义选择的阈值(如久坐 bout 门槛在近失样本 44.5 min 处仍维持 45 min)必须可区分,不得混为一谈。
  7. 「不可比 ⇒ 回退」而非「截断」(V15.30 提炼):代理指标的可信量程必须显式设界,且超出量程时的动作是回退到可解释的基准值,而不是把超界值钳到边界——后者会输出一个看似精确、其实无意义的数字。与之配套:任何新代理指标上线前,必须做「固定数据、只扫参数」的结论稳定性扫描(V15.30 即通过只扫 lookback_hours 发现同一份健康数据可得出 Δln = 0.0 与 0.625 两种矛盾结论)。
  8. 估算型预警的 confidence 不得复用症状预警的门(V15.30 提炼):估算型项的 confidence 语义是「估算可信度」而非「异常概率」(血糖上限仅 0.35),若沿用 0.50 的全局门会永远无法输出。因此必须:① 豁免全局门;② 各自设定 crisis_confidence_gate;③ 降级/受限必须显式告知调用方(本次为 blood.calibration_hint),否则会被当成功能故障。
  9. 新增「任何情况下都应存在」的字段,其计算必须放在所有早退分支之前(V15.30:min_beats 早退之前先算好 vitals,以保证顶部三个字段始终存在)。
  10. 衍生量不得与自身取差(V15.31 提炼):用于「偏移量」计算的基线,必须与当前窗口严格不相交。「在同一批样本上取基线」会让差值恒为零——不报错、不崩溃,只是静默退化成一个常数,且因为结果仍落在合理区间而极难发现。V15.31 的血糖就是如此:si_ref ≡ si_now、hrv_ref ≡ hrv_now,三项代理里两项报废。因此:① 差值类指标必须显式校验基线索引与窗口无交集;② 基线的取用口径必须作为结果字段回传(*_ref_mode + baseline_n_beats),供回归测试「断言走的是哪条路」。
  11. 回落口径必须带衰减,不可比量宁可停用(V15.31 提炼):当个人基线不可得、只能回落到群体参考时,系数要乘一个远小于 1 的权重(population_weight = 0.30),因为个体绝对值受探头位置/指围影响极大;而不同条件或不同设备之间根本不可比的量(HRV),正确动作是整项停用而不是硬凑。这与第 7 条「不可比 ⇒ 回退」同源,但更强调「回退也要按可信度打折」。
  12. 输出精度要与「需要分辨的差异」匹配(V15.31 提炼):量化位数是一种信息损失,而不是「看上去更干净」。血糖中枢本身只有 4.9~5.5,用 1 位小数会把 4.95~5.15 全部归并成同一读数——既看不出窗口间变化,也让「偏高」的判断失去分辨率。正确做法是先想清楚「这个量需要区分多大的差异」,再定小数位。
  13. 同一证据族的两个指标不得当独立证据线性相加(V15.32 提炼):HR↑ 与 PW↓ 常被写成两项「独立证据」再线性相加,但全语料实测 corr(hr_dev, pw_dev) = +0.602(n=10821)、corr(hr_med, pw_med) = −0.492。相加的后果是双临界边缘命中恒定拿到同一个分数(V15.32 处为 0.5+0.08+0.07 = 0.650),使置信度门形同虚设。正确做法是对同一证据族取 max()(与日报侧 min_signal_families 的「按族计数」一致):相关量各自可弱、但至少一个要够强。
  14. 阈值形式必须匹配指标的离散度(V15.32 提炼):对高离散指标禁止使用「固定比值」式阈值。日间静息 pw_front 的 IQR 达中位的 2.1×,中位 × 0.72 实际落在 p32 —— 阈值本身就会被约 32% 的正常静息样本穿过,这不是「敏感」,是阈值形式选错了。离散度大的量应改用个人分位阈值(如 pw_percentile = 10),并为其设最小样本量(pw_pctl_min_beats)以便不足时回退。
  15. 「中位数式」门控对双峰分布失明(V15.32 提炼):V15.32 的旧活动门取「窗口内 ma_act_1m 的中位数 < 5」,而触发窗口的真实形态是「一半静息 + 一半运动」的双峰分布 —— 中位数只有 2.1,门照样放行;实测该门在 10821 个窗口中命中 8631(80%),几乎不筛除。凡是「占比/成员资格」有意义的场景,都应该直接使用状态分类器的占比(静息/久坐占比 ≥ 0.80),而不是再拿一个连续量的人工阈值去近似它。注意前提:改动前后必须做「固定数据、只改规则」的影子普查(落盘原始量 → 离线对所有候选规则求值),才能得到逐窗口可比的修复前后对照,否则只能靠零散样本推测。
  16. 「两项都异常 ⇒ 更可信」只在不同物理机制下成立(V15.32 补充):HR↑ 与 PW↓ 会同时出现,是因为它们是同一个物理事件(佩戴松脱)的两次读数——光学通路断裂既压塌 PW,又制造假 R 峰抬高 HR。此时「两条都异常」不增加可信度,反而说明同一次伪迹被计了两遍。判据的可信度必须来自不同物理机制的证据族;同一机制内的多个量只能互为一致性检查,不能互为独立佐证。
  17. 入参校验不得把「可选背景量」升级为硬门槛(V15.33 提炼):判断标准是「这个量参与告警触发吗」。age 只影响 HRmax 与血压人群参考锚点,不参与任何检查器的触发门槛,缺失时的正确行为是回落默认值照常分析(本次即回落 35),并把「是否回落」回显给调用方(age_used / age_source),而不是返回 400 ——因为 400 惩罚的是终端用户(整次预警消失、界面上什么都看不到),而送错数据的是上游网关。实测量级:最近 500 条真实请求中 17 条(3.4%) 带 age=0,全部被旧守卫拒绝,即每天都有一批用户在「没有任何预警」的界面上。同类缺陷还包括:字符串年龄 "35" 被判非法、age=200 无上限(max_hr = 208 − 0.7×200 = 68,相对门限被压得过低 ⇒ 静息判定崩塌)。完整证据链与复现步骤见《预警系统说明文档》§10.37。
  18. 数字入参校验必须先排除 bool(V15.33 提炼):isinstance(True, int) is True,旧守卫因此把 age=true 静默算成 age=1(报告基于「1 岁」生成而不报错)。凡是「接受数字」的入口都必须先写 if isinstance(x, bool): 视为非法。
  19. 「静默失效」类缺陷只能靠审计日志发现,且必须能双侧配对(V15.33 提炼):本次缺陷不来自任何用户投诉,而是在回答另一个问题、读线上 API 审计时顺手发现的——它的症状是「什么都没有」,前端与服务端都没有异常痕迹。发现的关键是请求侧与响应侧日志可按时间戳逐条配对:17 条 age=0 与 17 条 400 一一对应,才把「上游送坏值 → 服务端丢结果 → 用户看不到预警」连成完整因果链;只有单侧日志时,这类缺陷通常会被误判为「上游没送数据」或「功能未上线」。
  20. 单特征单自由度的线性放大器永远会显得「plausible」(V15.34 提炼):血压代理模型自报 plausible = true、confidence = 0.6,却与袖带差 −30 / −26 mmHg。plausible 只证明「没有超出自己设的量程」,完全不证明接近真值。任何「可信度/合理性」标记都必须与外部真值做过对照才有意义,否则它只是在复述自己的假设。
  21. 只看一个量的绝对值时,先问它在时间上的变异系数(V15.34 提炼):pw_front 逐小时 CV ≈ 0.46,而 pw_front/pw_back 只有 0.07(V15.34 当时称 61/61 份文件成立;V15.40 以 63 份历史文件重测:CV(绝对值) 中位 0.458 vs CV(比值) 中位 0.071,63/63 份成立,逐小时极差中位 1.36× vs 1.00×)⇒ 绝对值主要测的是采集尺度,形态信息在比值里。同一 4 h 窗口内 pw_front +16.6% 与 pw_back +18.8% 同步升高就是这类漂移的直接指纹。指标选型应优先选对采集增益不敏感的形式(比值、相对个人分位),并在文档里写明「为什么这个量跨时段可比」。
  22. 误差方向比误差幅度更重要:不要把「测不到」输出成结论(V15.34 提炼):真值 DBP 91(1 级高血压)被报成「正常血压」——「正常」是一个临床结论,会把测不到固化成假阴性,而假阴性比假阳性危险得多。正确处理是:数字照给(供趋势参考),但结论不给,并用显式字段(measurement = false、display_label_cn、grade_cn_key = "uncalibrated")把「这不是测量值」传给调用方。上线这类标注前必须验证告警链路零影响(本次 crisis 数学上不可达、alert_eligible 恒 false、实测 warnings = [])。
  23. 「收紧参数」必须先量化会不会把间歇性问题变成系统性问题(V15.34 提炼):把 max_plausible_ln 从 0.25 收到 0.10 看上去更「保守」,实测通过率 71.7% → 35.8%,≈64% 窗口会退回人群参考 —— 而 reference_bp(35,'男') = 122/77 本身就被分级为「正常血压」,所以收紧只是换来一个更稳定、更系统的假阴性。「更保守的阈值」不等于「更安全的结果」,必须按输出结论而不是按参数方向评估。
  24. 顶层布尔若是多个子标记的 AND,就是「保守语义」,必须显式写明,且前端要用逐项标签(V15.34 提炼):measurement 只在血压与血糖都标定时为 true(宁可少声明)。因此只给血压校准时 bp_measurement = true 而顶层仍为 false;若前端拿顶层文案去描述某一个指标,就会把「已标定的实测血压」标成「非测量值」。逐项数值旁边必须用逐项文案(bp.display_label_cn / glucose.display_label_cn)。
  25. 注释、文案与回归期望值必须从实现里重新推导,不能凭记忆写(V15.34 提炼):本次用脚本重算注释里的每一个数字,当场发现 4 处不一致;回归测试里手抄的分级期望值(normal)与实现的真实输出(high_normal)不符而报错。正确做法是:① 文档/注释中的数字由脚本从真实管线算出;② 测试期望调用被实现的那个纯函数(grade_bp_cn(...) / grade_glucose(...))再比较,而不是另抄一份表。
  26. 「沿用同一常数」必须先检查推导前提是否还成立(V15.35 提炼):k_sbp = 150 是从 ΔP ≈ 100·Δln 反推的,而该式的前提是主动脉脉搏波传导时间;本项目的 pw_front 是手指 PPG 上升支,混入血管张力、体温、接触压力、探头位置。k 的作用本就是吸收这些未建模干扰,绝不能继续取「理论值」。判断依据只能来自实测离散度:pw_front 逐小时 CV ≈ 0.46 vs pw_front/pw_back 0.07 ⇒ 绝对值主要测的是采集尺度,故把 k 从 150/75 降到 50/30(约 1/3)并加 ±15 mmHg 限幅。校准点不是「把模型锁死」,而是「把模型钉在一个已知坐标上」——钉死(整值替换)会让输入失去意义,正确做法是锚点 + 有界偏移。
  27. 「用户给了真值」不等于「真值可以替代模型」(V15.35 提炼):V15.30 的整值替换看起来「尊重用户输入」,实际是把连续测量退化成一次静态快照——同一份 PPG 配不同校准值输出就整体平移,同一校准值配不同 PPG 输出完全相同。判别这种退化只需一个测试:固定校准值、换几份不同 PPG,看输出是否变化;若恒等,则输入通路已被短路。上线任何「用户提供参考值」型功能前,都必须跑这个「输入敏感性测试」。
  28. 「未知」与「否」必须是两个不同的值(V15.35 提炼):校准值新鲜度用三态表达——true(已过期)/ false(新鲜)/ null(未提供时间戳,未知)。若把「未知」塌缩成 false,则「未送时间戳」会被当成「刚测过」,正好把最不可信的输入放行;若塌缩成 true,则会静默关闭所有 Excel 式旧客户端的告警。三态还必须配一个显式策略开关(require_measured_at_for_crisis)来声明「未知时向哪边倒」,而不是把这个决策藏在默认值里。
  29. 差值类指标的分子分母必须用同一把尺(V15.35 提炼):Δln = ln(pw_ref / pw_now) 只有在两者取自同一条件时才是「血压变化」。旧实现里 pw_ref 是「全记录日间静息中位」而 pw_now 在静息样本不足时退化为「含运动段的 pw_valid」——同一份文件只把 lookback_hours 从 12h 改成 4h,Δln 就从 0 跳到 −0.836(2.3 倍 pw 比,非生理)。这与 V15.31 的「基线不得与窗口相交」是同一族缺陷的两面:一个防「自己减自己」,一个防「不同尺子相减」。凡输出「差值/变化」的模块,都必须把两端的取值口径作为结果字段回传(本次为 ref_pw_src / pw_base_out_ms / n_base_out_beats),以便回归测试断言走的是哪条路。
  30. 参考值是「偏差观测点」,不是「输出底座」(V15.37 提炼):当模型本身有绝对标定时,校准值的正确用法是测出系统偏差、然后平移整个模型(baseline 语义),而不是「废掉模型绝对值、只留相对变化量」(锚点语义)。一次校准只能确定一个自由度(截距),不能同时确定截距和量程——后者会人为压缩模型的动态范围,把真实的生理波动削平。判断依据:固定参考值、换不同时段的 PPG,看输出变化幅度是否与模型自身动态范围同量级;若被压成窄带,说明量程被吃掉了。
  31. 校准影响必须能自动退场(V15.38 提炼):常数偏移(baseline)会把一次不准的读数永久作用于后面所有输出,且无法自动清除。任何「用户提供的参考值」型功能都必须回答两个问题:① 它怎么衰减(本次 λ_hourly 0.05,半衰期 13.5 h);② 它怎么被取代(新校准覆盖旧 offset₀)。另:一次性观测不应全额归因给模型(α = 0.5 收缩估计)——用户设备也有测量误差。此外,「同一时刻的模型值」必须用同一个取数口径:V15.37b 的缺陷就是 model(t0) 取窗口均值、model(t) 取当刻值,导致 t0 处不收敛。
  32. 「时效门」不得把累计证据偷换成近期证据(V15.39 提炼):tail_slack_minutes 的初衷是「防次日回溯」,但它被施加在累计证据上,等价于要求「最近 45 分钟内就要凑齐 90/150/240 分钟」——后者结构性不可达。正确分解:防回溯用「请求时刻门」(现在是不是 18–23 时),证据用「累计量」(过去这段时间累计多少分钟)。凡看到「滑动窗 / 时效 / 新鲜度」类门限,都要问一句:它想约束的是「什么时候」还是「有多少」?两者混在一道门里,就会把慢积累的信号全部静默掉。另:分段长度、门槛数值等参数变更前,必须先做「固定数据、只扫该参数」的证伪测试(V15.39 即扫 min_length = 1800/900/450/300,结果逐字节相同 ⇒ 参数无关)。
  33. 提前告警只能靠「分层」,不得靠「下调门槛」(V15.39 收口提炼):用户口径「7 点半报的是非运动期间心率升高,饮酒信号延迟一小时」——要更早出声,正确的动作是增设低一档 severity + 不确定措辞(本次 hint:40 min 播报「疑似饮酒信号 · 证据累积中」),而不是把告警门槛下移。理由是可量化的余量红线:提示门 40 min 对最紧负对照(864249079484364-未饮酒 累计上限 29.9 min)只剩 10.1 min 余量;若再加一档 30 min,该负例距命中只剩 0.1 min,会把「确实没饮酒」立刻打成正例。分层只改变「说什么」(措辞/等级),不改变「何时说」(门槛),因此可以在零特异度代价下把首命中提前到 19:20 / 20:00 / 21:00;而任何下调提示或立案门槛的改动,都必须先证明全部负例余量 ≥ 10 分钟。配套两条规格性核查:① 立案档必须做可达性核查(tiers[3]=240 相对实测正例峰值 153.3 min 属预留上限档,现有语料从未触发——保留原值以免改变已验证的 0.62/0.70 映射,但必须在文档中标为「可达性未验证」);② 若某条负例的唯一拦截者是单一门(本次日间对照门:驾驶负例原始累计 203.9 min 高于真阳性峰值 153.3),则该门是单点依赖,必须显式标注、并禁止「放宽/关闭/改口径」这类看似无害的调整。
  34. 混杂变量按「机制」归因,排除靠「正交证据」(V15.39 提炼):用户质疑「开车有定位可以区分」——正确答案不是「把混杂项改名叫驾驶」,而是让两个正交机制各管一件事:混杂项保留 alcohol 语义(它描述的是生理机制:酒精 → 交感激活 → 代理量同向偏移);定位证据负责行为排除(把「可证驾驶/移动」的时段区间扣除)。机制决定判据,证据决定排除——若把两者混成一个「开车或饮酒」布尔,则两个原因都不能被单独验证,也无法分别回退。同时:混杂判定的门槛应与告警门槛故意不同值(本次 40 min vs 60 min)——抑制决策只需确认「效应是否仍在」(门槛宜低,且本窗口不产生任何用户可见结论),告警则要求「现在是否仍处于上升段」(门槛宜高);合并为一个值会把其中一侧推到错的位置。
「法于阴阳,和于术数,食饮有节,起居有常,不妄作劳。」——《黄帝内经·上古天真论》

中医正气评估系统 · 版本变更记录(白皮书附录)
本页为主白皮书 whitebook.html 的拆分页, 与主白皮书同步随代码变更更新

← 返回白皮书