搭建心源性猝死预警Agent:架构、代码与风险

2026年5月,22岁巴西健美网红 Gabriel Ganley 因肥厚型心肌病(HCM)猝死。他的死因不是训练过度,而是遗传性心脏结构异常——这类问题在年轻运动员中常被忽视,直到心脏停跳。

这件事对开发者的冲击是:我们正在构建的健康AI产品,有没有可能提前一天、一小时甚至十分钟预警? 如果没有,我们的“AI健康助手”最多是个聊天玩具。

本文不讨论健身补剂或悲剧本身。我将拆解一个可解释的心源性猝死预警Agent的完整架构,从心率数据采集到警报下发,附带一个基于HRV(心率变异性)的简化规则引擎实现,并重点分析三类陷阱:数据噪声、假阳性心理伤害、法律问责。读完你可以立刻开始搭建一个原型,并清楚知道哪些地方可能会害死人。


1. 为什么需要预警Agent,而不是单次检测?

猝死不是瞬间事件。心脏骤停前数小时到数天,身体会发出微弱信号:心率变异性(HRV)骤降、夜间心率异常升高、活动后恢复时间延长。这些信号在单次静息心电图里很难捕捉,但连续监测能看出趋势。

传统可穿戴设备(Apple Watch、Garmin)已经提供基础心律报警,但问题是:

  • 误报率极高:运动中的心率波动被当成房颤,用户很快关掉通知。
  • 缺乏上下文融合:不知道用户昨天是否熬夜、今天是否生病、训练强度是否异常。
  • 没有多步推理:只做单点阈值判断,不会根据历史趋势和外部数据做综合决策。

这正是Agent的用武之地:规划 → 感知 → 推理 → 执行

agent planning loop wearable health data flow


2. Agent 架构拆解

我把预警系统分成四个模块,每个模块对应Agent的一个能力:

模块 对应Agent能力 输入 输出
数据采集 & 清洗 感知(工具调用) 心率、加速度、GPS、睡眠 规整的时间序列
特征工程 & 趋势分析 短期记忆 + 推理 时间序列窗口 风险指标(HRV、恢复指数)
混合决策引擎 规划(含反思) 风险指标 + 用户上下文 动作标签(正常/警告/警报)
警报路由 & 解释 执行(工具输出) 动作标签 + 证据 通知 / 呼叫 / 日志

与传统ML pipeline的区别在于:决策引擎内部可以调用多个子工具(大模型、规则、分类器)并执行失败重试。比如当HRV低于阈值时,Agent不是直接报警,而是先查询用户今天的睡眠时长、血氧,再决定是否升级。


3. 核心模块细节与代码

3.1 数据采集:小心苹果的隐私墙

大部分可穿戴设备通过HealthKit或Google Fit暴露数据,但采样频率被限制(HRV通常每5分钟一个点)。为了获取更高频数据,需要BLE直接对接设备(如Polar H10),但用户授权门槛极高。

简易方案:用heartpy库从PPG或ECG信号计算HRV。以下是从CSV读取心率并计算时域HRV的代码:

python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
import heartpy as hp
import pandas as pd

def compute_hrv_from_ecg(ecg_signal, sample_rate=250):
    """
    ecg_signal: list of raw ECG voltage values
    sample_rate: Hz
    返回: {'bpm':..., 'rmssd':..., 'sdnn':...}
    """
    wd, m = hp.process(hp.scale_data(ecg_signal), sample_rate)
    return {
        'bpm': m['bpm'],
        'rmssd': m['rmssd'],  # 短期变异,交感/副交感平衡
        'sdnn': m['sdnn']     # 整体变异
    }

# 示例:读取5分钟窗口
window = pd.read_csv('ecg_5min.csv')['voltage'].values
hrv = compute_hrv_from_ecg(window)
print(hrv)

踩坑:运动中ECG容易因肌肉电噪声而失真,必须加滤波器(带通5-40Hz)。多数公开数据集的信号质量标签不可用,导致假阳线。

3.2 特征工程:多窗口趋势 + 上下文

单点HRV没有意义,需要看滚动变化率。我设计三个窗口:

  • 短期(5分钟 vs 1小时均值)→ 即时异常
  • 中期(过去24小时 vs 过去7天基线)→ 日趋势
  • 长期(本周 vs 上月)→ 基线迁移(可能提示心肌病变)

同时引入外部上下文:天气(气压变化诱发心梗)、睡眠时长、当天的运动负荷(来自GPS/加速度)。用TF-IDF风格给每个因素赋权,但权重要基于医学证据而非纯统计——这一点LLM做不到,需要领域专家。

python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
def risk_score(hrv_now, hrv_baseline, sleep_hours, training_load, age, sex):
    # 基于文献的简易加权
    # 来源:Romagnoli et al. 2020, JACC
    score = 0
    # HRV drop > 30% from baseline: +40 points
    if hrv_now < 0.7 * hrv_baseline:
        score += 40
    # sleep < 5h: +20
    if sleep_hours < 5:
        score += 20
    # training load > 2x usual: +15
    if training_load > 2 * baseline_load:
        score += 15
    # age > 45: +10 (男性)
    if age > 45:
        score += 10
    return score  # 0-100

这个函数是「固定规则」,但Agent可以在规则输出边界值时(如得分在55-65之间),主动调用LLM分析用户的社交网络抱怨(“昨晚没睡好”“压力大”),做一次上下文增强。

3.3 混合决策引擎:规则 + ML + LLM 的三层管道

为了平衡速度和解释性,我设计了三层管道。

第一层:规则过滤器(延迟毫秒级)

  • 如果心率 > 220-age 且持续 >30秒 → 直接紧急警报
  • 如果HRV < 硬阈值(rmssd < 10ms)→ 进入第二层

第二层:LightGBM 分类器(延迟百毫秒级)

  • 输入:20维特征(HRV时域/频域、心率、运动状态等)
  • 输出:风险概率 + SHAP解释值
  • 如果概率 >0.8 → 警报;如果0.5~0.8 → 第三层

第三层:LLM 作为二次验证(延迟1-3秒)

  • 输入:最近24小时的心率曲线、用户自述、天气、事件摘要
  • Prompt 设计强制要求 LLM 输出三个信号:
    1. 紧急程度(low/medium/high)
    2. 关键证据(引用特征)
    3. 建议行动(如“立即静息并监测15分钟”)

这里的关键是第三层不能独立决策,它只提供建议和解释。最终警报由规则引擎根据所有层的分数加权触发。我设置了一个人类在环选项:如果高分警报且用户是第一次出现,Agent不直接发警告,而是发一条“请确认是否感觉异常”的交互消息。

three-layer decision pipeline for cardiac risk

3.4 执行:警报路由的细分

不同风险等级对应不同的执行工具:

等级 示例分值 执行行为
绿色 <30 无操作或存入日志
黄色 30-60 推送建议“今天减少强度,多睡眠”
橙色 60-80 推送 + 询问用户状态,15分钟后复测
红色 >80 推送 + 自动拨打紧急联系人(需用户预授权)

注意:对于年轻人(如Gabriel的年龄),橙色级的规则要更保守,因为HCM的首次表现就是猝死,没有渐进过程。实际上,现有医学证据表明HCM患者运动时发生恶性心律失常的风险显著升高,但HRV的变化并非特异性。所以我的系统对22岁健美选手会额外标记为“高风险体质”,即使HRV正常也定期做心电图复查提醒。


4. 简化版动手实现:一个能跑的HRV预警Agent

这里我提供一个最小可复现的Python Agent,基于LangGraph框架(或纯函数管道)。它读取模拟的5分钟ECG数据,计算HRV,执行规则并输出警报。

python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
# 简化版:省略了LLM和ML,仅规则
import time
import numpy as np
import heartpy as hp
from typing import Dict, Optional

class HCMRiskAgent:
    def __init__(self, age=22, baseline_hrv=None):
        self.age = age
        self.baseline_hrv = baseline_hrv or {'rmssd': 40, 'sdnn': 70}
        self.history = []
    
    def perceive(self, ecg_signal, sample_rate=250) -> Dict:
        # 模拟感知
        try:
            wd, m = hp.process(hp.scale_data(ecg_signal), sample_rate)
            return {
                'rmssd': m['rmssd'],
                'sdnn': m['sdnn'],
                'bpm': m['bpm'],
                'timestamp': time.time()
            }
        except Exception as e:
            return {'error': str(e)}
    
    def reason(self, observation: Dict) -> str:
        if 'error' in observation:
            return 'ERROR: signal quality issue'
        self.history.append(observation)
        # 规则:rmssd < 50% baseline → warning
        rmssd_drop_ratio = observation['rmssd'] / self.baseline_hrv['rmssd']
        if rmssd_drop_ratio < 0.3:
            return 'CRITICAL: extreme HRV drop, immediate medical attention'
        elif rmssd_drop_ratio < 0.5:
            return 'WARNING: significant HRV drop, rest and monitor'
        else:
            return 'NORMAL'
    
    def act(self, decision: str):
        if 'CRITICAL' in decision:
            print(f"[ALARM] {decision}")
            # 实际会调用Twilio发送短信
        elif 'WARNING' in decision:
            print(f"[ADVISORY] {decision}")
        else:
            print(f"[SILENT] No action")

# 模拟运行
if __name__ == '__main__':
    agent = HCMRiskAgent(age=22)
    # 生成一段模拟异常ECG(心率低变异性)
    abnormal_ecg = np.sin(np.linspace(0, 100, 1250)) * 0.05 + np.random.normal(0,0.01,1250)
    obs = agent.perceive(abnormal_ecg)
    decision = agent.reason(obs)
    agent.act(decision)

运行后会输出[ALARM] ...[ADVISORY] ...。你可以在GitHub上找到真实ECG数据集(如MIT-BIH)替换abnormal_ecg来测试。


5. 踩坑记录:这些设计可能害死人

5.1 数据噪声:运动伪迹导致的假警报

实测中,手臂摆动产生的加速度能完全淹没ECG信号,使算法误判为极端HRV。解决方案:必须融合加速度计数据,在运动>2MET时禁用HRV分析,只保留心率监测。

5.2 假阳性的心理伤害

如果Agent频繁发出“预警”,用户会产生报警疲劳,甚至出现焦虑障碍。对于健康年轻人,红色警报的每日触发率必须低于0.01%(每万天一次)。这意味着我们的阈值必须足够保守,并且在警报前先询问用户是否感觉异常

5.3 法律问责:谁为错误的警报负责?

如果Agent没有预警(真阴性)导致死亡,还是发出假警报导致不必要的急诊,责任在开发者、设备厂商还是用户?目前美国FDA对这类软件按“医疗设备”监管(SaMD),需要510(k)预通知。你的项目如果面向真实用户,必须获得监管批准。我个人的建议是:不要把Agent设计成诊断工具,而是作为“健康建议助手”,并在UI中明确声明不提供医疗建议

5.4 LLM的幻觉风险

第三层使用LLM时,我曾见过GPT-4基于错误的心率曲线编造“用户可能发生心肌炎”的结论,而实际只是传感器脱落。解决方案:LLM必须引用具体特征值(如“RMSSD从40降至15”),并通过正则校验确保输出格式可控。


6. 对开发者的建议

  1. 领域知识 > 模型复杂度。心源性猝死的病理机制非常清楚,规则引擎往往比任何深度学习都可靠。ML只能辅助覆盖多变量非线性关系。
  2. 不要忽视环境因素。气压变化、感染、饮水不足都会影响心率。你的Agent应该接入天气API和睡眠追踪。
  3. 伦理设计优先。在代码中嵌入“人类在环”(Human-in-the-Loop)逻辑,让用户拥有最终决策权。
  4. 保留原始数据。所有决策都必须可追溯,留下审计日志。一旦出现法律纠纷,这是唯一的保护。

Gabriel Ganley的悲剧提醒我们:技术可以做的比现在更多。但只有清醒地认识到技术边界,我们才能安全地推动边界。如果你现在就想开始,请先下载一个干净的ECG数据集,跑通上面的简化Agent,然后逐步加入你关注的维度。

不要等到事故发生后,才明白预警信号的含义。