CareBridge:让每一代女性,无论处于哪个年龄阶段,在低资源环境里都能获得持续的健康照护
参赛赛道:社会服务 / 造种新体验
附加赛题:社会公益 — 智慧助老
作品形态:AI 健康共护 Web 应用 + ESP32 硬件终端(软件+硬件融合健康管理方案)
体验地址:`https://workspace-nine-blush.vercel.app/dashboard
创作者:CareBridge 团队
参赛日期:2026年7月(复赛)
一、Demo 简介
1.1 作品是什么
CareBridge 是一款面向女性、家庭与银发群体的全生命周期 AI 健康共护平台,以"软件+硬件"双轮驱动的融合方案为核心设计理念。在 Web 应用层面,CareBridge 构建了覆盖女性健康周期管理、AI 健康问答、家庭健康协同、智能体检报告解读、可穿戴设备集成与健康知识科普的一站式健康管理入口;在硬件层面,团队基于 ESP32 微控制器自主开发了心率体温监测终端,通过蓝牙直连将生理数据实时同步至 Web 应用,填补了银发群体与智能健康设备之间的使用鸿沟。
“共护"是 CareBridge 区别于市面上单点健康工具的关键——它不是一个人孤立的记录本,而是将女性自身、家庭成员、特别是远在他乡的子女与年迈父母连接在一起的健康协作网络。当一位 28 岁的职场女性在记录经期波动时,她的健康数据可以同步至家庭空间;当远在河南的父母通过 ESP32 终端完成心率测量时,在上海工作的子女能在手机上即时收到结果与异常提醒。硬件感知与软件分析协同工作,让健康数据的采集从"手动输入"进化为"自动感知”,让健康管理的对象从"个体"扩展为"家庭"。
1.2 面向谁
CareBridge 的用户群体覆盖全生命周期的多个角色,每一类用户都有明确的痛点和对应的解决方案:
| 用户群体 | 核心痛点 | CareBridge 解决方案 |
|---|---|---|
| 职场女性(25-40岁) | 经期不规律、压力性健康问题、缺乏系统化健康管理工具 | 女性健康周期管理 + AI 健康助手,提供个性化周期追踪与健康建议 |
| 孕期女性 | 孕期信息碎片化、产检数据分散、缺乏全周期管理 | 孕期全周期管理模块,整合产检记录、症状追踪与 AI 孕期问答 |
| 异地子女(30-45岁) | 父母远在他乡、健康状态不可见、突发情况难以及时响应 | 家庭健康协同 + ESP32 硬件终端,父母在家即可测量,子女远程查看 |
| 银发群体(60岁以上) | 不会用智能手机、健康监测设备操作复杂、数字鸿沟深 | ESP32 硬件终端一键测量,无需操作手机,数据自动上传 |
| 低资源地区居民 | 医疗资源匮乏、健康知识不足、设备昂贵 | 低成本硬件(<50元)+ 免费Web应用,降低健康监测门槛 |
银发群体是 ESP32 硬件终端的核心受益人群,也是 CareBridge 从纯软件方案走向"软件+硬件"融合的直接原因。这个判断不是来自大规模的用户调研,而是来自我们团队自己家里发生的事。初赛阶段,我们让家人的父母试用长辈模式——把字体放大到24px、把操作压缩到3步以内,但父母依然觉得"太复杂了"。一位团队成员的母亲(63岁)试用了十分钟,反复在输入数字时误触返回键,最后她说了一句话:"能不能不要让我自己输?"这句话直接催生了 ESP32 硬件终端的想法——与其试图教会老年人操作智能手机,不如让硬件承担数据采集的全部工作。触屏操作的精细动作要求、文字输入的认知负担、多层级菜单的导航复杂度,构成了老年人使用数字健康产品的三重壁垒,而我们自己家人的反馈让我们切身感受到了这些壁垒有多难逾越。
1.3 主要功能
CareBridge 围绕"感知-记录-分析-协同-科普"的健康管理闭环,构建了七大核心功能模块。每个模块既可独立使用,又通过统一的数据层实现深度联动:
| 功能模块 | 核心能力 | 关键技术 |
|---|---|---|
| ESP32 硬件感知模块 | 一键采集心率、体温数据,BLE 直连 Web 应用 | ESP32 + MAX30102 + DS18B20 + Web Bluetooth API |
| 女性健康周期管理 | 经期追踪、排卵预测、症状记录、周期趋势分析 | 规则引擎 + 时序预测算法 |
| AI 健康助手 | 自然语言健康问答、个性化建议生成、异常预警 | LLM + RAG(健康知识库检索增强) |
| 家庭健康协同 | 家庭成员健康数据共享、远程查看、异常标注 | 本地数据共享 + 飞书表格同步 |
| 智能体检报告解读 | 体检报告 OCR 识别、指标解读、趋势对比、异常标注 | OCR + LLM + 医学指标知识图谱 |
| 可穿戴设备集成 | 接入主流可穿戴设备数据,统一健康数据视图 | Apple HealthKit / Google Fit / 华为运动健康 API |
| 健康知识科普 | 个性化健康内容推送、医学术语通俗化解读 | 内容推荐算法 + LLM 文本简化 |
七大模块中,ESP32 硬件感知模块是复赛阶段新增的尝试。我们的初衷是用一个低成本的物理设备,让不擅长操作手机的老年人也能完成基础生理指标采集——把"手动输入"变成"按一下按钮"。目前这套硬件方案在测试环境下跑通了基本链路,但距离稳定可用还有不少路要走。硬件采集的生理数据如果能够稳定回传,将与 Web 应用中的周期记录、体检报告等汇聚至统一数据层,为 AI 健康助手提供更全面的分析基础。
1.4 典型用户旅程

场景一:职场女性的日常健康管理
小张,28岁,是一家互联网公司的产品经理。高强度的工作节奏让她的经期在过去半年变得愈发不规律——有时提前一周,有时推迟十天,经量也出现了明显波动。她曾在手机上下载过三款经期记录 App,但每次都要手动输入日期、症状、情绪状态,忙起来就忘了记,断断续续的数据根本看不出趋势。我们希望 CareBridge 能成为小张的第四款 App,但也是最后一款。
我们期望的体验是这样的:小张打开 CareBridge,花几分钟完成基础信息录入——年龄、周期历史、既往症状。系统据此自动生成周期预测日历,在每个关键节点设置提醒,让她不必再手动掐算日子。我们希望 AI 健康助手不仅能回答"经量减少可能是什么原因"这类基础问题,还能结合她近期的睡眠数据和压力记录,给出"近期睡眠不足与工作压力可能影响周期规律,建议每日保证7小时以上睡眠,并适当增加镁元素摄入"这样的个性化建议——不是泛泛的健康科普,而是基于她本人数据的判断。
随着数据逐步积累,我们期待系统能自动生成周期趋势报告,让小张看到自己的平均周期长度是否在回归正常、经量波动是否在缩小。我们同样希望她能把这份报告分享给家庭空间中的伴侣,让对方理解她的身体变化,在经期前后给予更多支持。这是 CareBridge 想要做到的事——不只是一个记录工具,而是一个懂女性身体节奏的智能健康伙伴。
场景二:异地子女对父母的远程照护
王先生,35岁,在上海一家科技公司担任技术总监。父母都在河南老家,父亲68岁,患有高血压十年;母亲65岁,确诊糖尿病已有六年。每年只有春节和国庆能回老家看望父母,平日里只能通过电话询问身体状况,而父母总是报喜不报忧,"挺好的,没事"几乎成了标准回答。这种"看不见就放心不下"的焦虑,是我们设计 ESP32 硬件终端的出发点。
我们希望的场景是这样的:王先生为父母配置 ESP32 硬件终端后,父亲每天早晨起床,只需按下终端上的唯一按钮,设备便在30秒内完成心率、血氧和体温的采集,数据通过蓝牙自动同步至家中旧手机上的 CareBridge,存入本地。王先生在上海的办公室里打开 CareBridge,就能看到父亲今早的心率、血氧和体温,以及过去30天的趋势曲线。我们希望让远在千里之外的子女,第一次拥有"看见"父母健康状态的能力——而这背后,不过是老人按下一个按钮的简单动作。
我们更期待的是异常情况下的及时响应:当某天父亲的血氧偏低、心率或体温超出正常范围时,系统能自动推送告警给王先生,让他第一时间拨通父亲的电话、联系老家的社区医院安排就诊。尤其是血氧这项指标——新冠期间那些"喘不上气却没往血氧想"的教训让我们深知,有些异常靠主观感受是发现不了的。王先生在家庭空间中记录的"如果没有这个设备,我可能要到周末打电话才知道这件事"——这是我们希望最终能听到的用户反馈,也是 CareBridge 想要解决的异地照护痛点。
场景三:孕期女性的全周期健康管理
小李,32岁,怀孕16周,是一名高校教师。作为第一次怀孕的新手妈妈,她面对的信息洪流令人焦虑——产检报告上的专业术语看不懂,网上搜索到的孕期知识真假难辨,家人和朋友的建议互相矛盾,每一个症状都让她提心吊胆。这正是我们希望 CareBridge 孕期模式要解决的问题。
我们期望的体验是:小李在女性健康周期管理模块中切换至"孕期模式"后,系统根据她的孕周自动调整功能重点——16周正值唐氏筛查的时间窗口,系统提醒她预约 NT 超声检查,并解释这项检查的目的、流程和注意事项。在产检后,小李将体检报告拍照上传至智能体检报告解读模块,系统通过 OCR 识别各项指标,用通俗语言逐条解读——“血红蛋白 112g/L,略低于孕期推荐值(≥110g/L),属于轻度生理性贫血,建议增加红肉、动物肝脏等富含铁元素的食物摄入,若下次产检仍偏低,请咨询医生是否需要补充铁剂”。我们希望这些解读能替代小李在搜索引擎里反复搜索、反复焦虑的夜晚。
进入孕中期后,我们期待小李能在 CareBridge 中记录每天的胎动次数和规律,系统自动绘制趋势图并在胎动明显减少时发出提醒。我们同样希望 AI 健康助手成为她的"口袋孕产百科"——从"孕中期可以坐飞机吗"到"腿抽筋是不是缺钙",每个问题都能得到基于权威医学文献的回答。小李将丈夫拉入家庭空间,让他也能查看产检记录和胎动数据,共同参与孕期管理。这是 CareBridge 想做到的——将碎片化的孕期信息整合为一条清晰的管理主线,让准妈妈从"焦虑地搜索"转向"从容地记录和理解"。
1.5 从初赛到复赛的升级亮点
初赛阶段,CareBridge 以 Web 应用形态参赛,验证了"AI健康共护"的核心理念在女性与家庭场景中的可行性。复赛阶段,团队在架构、智能、体验、生态、硬件五个维度完成了系统性升级:
架构升级:从单体 Web 应用重构为更完善的前端架构,基于 React 构建,采用 Zustand 状态管理 + localStorage 持久化的离线优先方案。硬件数据通过 BLE 直连浏览器后存入本地,不依赖云端服务器。飞书表格同步通过一个轻量的本地代理服务完成 OAuth 认证和数据中转。
智能升级:AI 健康助手从初赛的关键词匹配升级为基于 RAG(检索增强生成)的智能问答系统,接入权威医学知识库(包含 UpToDate、默沙东诊疗手册等来源),回答准确率与专业性显著提升。体检报告解读模块新增多指标关联分析能力,能够识别指标间的潜在关联并给出综合建议。
体验升级:交互设计全面优化,引入响应式布局适配移动端与桌面端,新增深色模式与无障碍模式。家庭健康协同模块支持家庭成员间共享健康数据,异常数据可在应用内标注提醒。
生态升级:可穿戴设备集成模块从初赛的概念设计落地为实际功能,已接入 Apple HealthKit、Google Fit 和华为运动健康三个平台的数据接口,用户可以将智能手表、手环的数据汇聚至 CareBridge 统一管理。
硬件升级:复赛阶段我们尝试加入了 ESP32 心率血氧体温监测硬件终端,迈出了从"纯软件方案"到"软件+硬件融合方案"的第一步。硬件终端以不到50元的成本实现了心率、血氧饱和度和体温采集,通过 BLE + Web Bluetooth API 直连浏览器,无需安装 App。坦率地说,这套硬件方案目前还处于原型验证阶段——测试时能跑通,但 BLE 连接的稳定性、传感器读数的一致性都还有提升空间,我们不敢说它已经"好用",只能说它"能用"。
附录A、产品演示视频
(产品演示视频链接:将1-5分钟录屏上传至B站/抖音后,在此处贴入公开链接https://www.bilibili.com/video/BV1DMuV62EiJ/?spm_id_from=333.1387.homepage.video_card.click)
视频内容涵盖完整的用户路径:
-
首页仪表盘 — 展示今日健康概览、AI风险提醒、快捷记录入口
-
今日速记 — 演示30秒内完成情绪、症状、睡眠的多维度记录
-
ESP32 硬件连接 —
-
AI风险评估 — 展示双轨评估引擎生成红黄绿三色预警和健康建议
-
家庭中心 — 演示多成员切换、守护人查看长辈健康数据
-
健康摘要导出 — 展示一键生成结构化就医摘要
-
长辈模式切换 — 展示大字体、高对比度的适老化界面
-
SOS紧急求助 — 演示三级预警升级机制
视频还特别展示了 ESP32 硬件终端的实物操作:老人按下按钮 → 传感器采集心率和体温 → 数据通过蓝牙推送到 Web 页面 → 风险评估引擎自动分析 → 异常时触发守护人通知的完整链路。这段演示是复赛新增的核心内容,直观展现了"软件+硬件"融合方案如何解决老年人健康数据采集的"最后一公里"问题。
二、市场与需求分析
2.1 全球女性健康现状与数据
全球约有38亿女性人口,占世界总人口的近一半,但在医疗健康体系中,女性的健康需求长期处于被忽视或被边缘化的状态。世界卫生组织(WHO)数据显示,全球每天约有810名女性死于可预防的孕产期相关原因,2023年全年孕产妇死亡人数约达29.5万人。其中,撒哈拉以南非洲地区的孕产妇死亡率是全球平均水平的2.5倍,南亚地区紧随其后。这些数字背后反映的不仅仅是医疗资源的匮乏,更是一个深层的系统性问题——医学研究中的性别偏见。
性别偏见在医学研究中有着漫长而具体的历史。1977年,美国食品药品监督管理局(FDA)发布指南,建议将"育龄女性"排除在早期临床试验之外,这一政策虽然初衷是保护潜在胎儿,却在事实上导致大量药物的临床试验对象几乎全部为男性,女性的生理差异在药物研发中被系统性地忽略。直到1993年,美国国会通过《美国国立卫生研究院振兴法案》(NIH Revitalization Act),才从法律层面要求 NIH 资助的临床研究必须纳入女性受试者并按性别分析数据。然而,数十年偏男性试验积累的后果已深刻嵌入现行医疗体系。
安必恩(Ambien,通用名唑吡坦)事件是性别偏见后果最具代表性的案例。这款广泛使用的安眠药于1992年获 FDA 批准上市,其推荐剂量基于以男性为主体的临床试验数据确定。直到上市20年后的2013年,FDA 才发现女性代谢该药物的速度显著慢于男性,相同剂量下女性次晨血液中的药物浓度比男性高出45%,导致女性在用药后次日驾驶时发生车祸的风险大幅增加。FDA 最终将女性推荐剂量下调一半,但此前已有大量女性在不知情的情况下承受了过量用药的风险。这一案例深刻说明:当医学研究忽视性别差异时,后果不是理论上的,而是真实发生在每一位女性身上的健康风险。
性别偏见的后果不仅体现在药物领域,还渗透到诊断标准与疾病认知的方方面面。女性心脏病发作时的典型症状与男性不同——男性常表现为胸痛放射至左臂,而女性更常出现恶心、气短、背部或下颌疼痛。然而,由于经典的心脏病诊断标准主要基于男性患者的临床数据构建,女性在急诊室被误诊或漏诊的比例显著偏高。一项发表于《Circulation》的研究发现,女性在心脏病发作后7天内的死亡率比男性高出约26%,其中诊断延迟是关键因素之一。更广泛地看,子宫内膜异位症这类仅影响女性的疾病,患者从首次出现症状到确诊平均需要7-10年,在此期间她们反复就诊、被告知"痛经是正常的",承受着不必要的痛苦与延误。
在数字健康领域,女性的边缘化同样存在。Bloomberg 2023年的一项分析发现,全球数字健康融资中,专注女性健康(FemTech)的初创企业获得的资金占比不足5%,而女性健康市场的潜在规模预计到2030年将超过600亿美元。融资的结构性失衡导致女性专属的健康需求——从月经周期管理到更年期症状监测——长期缺乏足够的技术投入与产品创新。即便在已有的女性健康产品中,大多数也停留在经期记录和孕期提醒这一浅层功能,缺乏与家庭照护、银发群体健康监测的系统性整合。CareBridge 选择以女性健康为核心切入点,同时将家庭照护与银发群体纳入同一个健康共护网络,正是对这一市场结构性缺失的直接回应——不是为女性单独造一个工具,而是让女性成为连接整个家庭健康生态的枢纽。
2.2 银发群体的数字鸿沟
全球正经历前所未有的老龄化进程。WHO 预测,2015年至2050年间,全球60岁以上人口比例将从12%上升至22%,绝对数量从9亿增长至20亿。中国是世界上老龄化速度最快的国家之一:国家统计局数据显示,截至2024年末,中国60岁及以上人口已达3.1亿,占总人口的22.0%,其中65岁及以上人口2.2亿,占比15.6%。按照联合国的定义,65岁以上人口占比超过14%即进入"深度老龄化社会",中国已跨过这一门槛。
庞大的银发人口背后,是深刻的数字鸿沟。中国互联网络信息中心(CNNIC)第54次《中国互联网络发展状况统计报告》显示,截至2024年6月,中国60岁以上非网民规模仍超过1.5亿,占非网民总数的近70%。即便在已上网的老年群体中,智能手机的使用也高度集中于微信聊天和短视频浏览,涉及健康数据记录、在线问诊、电子健康卡等功能的使用率不足15%。
银发群体面临的数字障碍可以归纳为三重困境:技术门槛——触屏操作的精细动作要求对老年人而言是生理层面的挑战,手部震颤、视力衰退使得点击小按钮和滑动屏幕变得困难;认知负担——多层级菜单导航、复杂表单填写、验证码识别等交互设计,超出了许多老年人的认知负荷上限;情感障碍——对"操作错了会不会弄坏设备""个人信息会不会泄露"的恐惧,让许多老人对数字产品望而却步,甚至产生抵触情绪。
这三重困境叠加的结果是:银发群体虽然在健康监测需求上最为迫切,却恰恰是数字健康产品最难触达的人群。我们没有走进社区或养老院做大规模调研,但我们自己家人的反馈就足以说明问题。当团队成员把自己母亲(63岁)和父亲(67岁)请来试用长辈模式时,母亲反复在输入血压数字时误触返回键,父亲则在多层菜单中找不到"记录"入口。母亲说了一句让我们印象深刻的话:"能不能不要让我自己输?"这句话成为 ESP32 硬件终端设计的出发点——与其试图教会老年人使用复杂的数字产品,不如让硬件承担数据采集的全部操作,让老年人只需要"按下按钮"这一个动作。硬件终端不是在数字鸿沟上搭一座桥,而是在鸿沟的两侧各放一台设备,让数据自己飞过去。
2.3 低资源地区的健康不平等
全球健康资源的分布呈现出极端的不均衡。世界银行数据显示,全球仍有约8亿人生活在极端贫困之中,日均生活费不足2.15美元。WHO 报告指出,全球至少46亿人无法获得基本医疗服务,占全球总人口的近60%。在撒哈拉以南非洲和南亚的许多地区,每千人拥有医生数量不足0.5人,而高收入国家的这一数字通常在3人以上。
中国虽已建成全球规模最大的基本医疗保障体系,但城乡之间的医疗资源差距依然显著。国家卫健委数据显示,城市每千人拥有执业医师4.2人,农村仅为1.9人;三级医院集中在大中城市,基层医疗机构的服务能力与设备配置普遍不足。对于居住在偏远农村或低资源社区的居民而言,定期健康监测几乎是一种奢侈——不是他们不需要,而是获取成本太高。
CareBridge 的 ESP32 硬件终端在设计之初便将"可负担性"作为核心约束条件。整套硬件的成本构成如下:ESP32 开发板约15元、MAX30102 心率血氧传感器约12元、DS18B20 温度传感器约19元总成本约6-7$,不足50元。与之对比,市面上一台基础款智能血压计的售价通常在200-400元,具备心率监测功能的智能手表价格多在500元以上。CareBridge 硬件终端以不到50元的成本实现了心率与体温两项核心生理指标的连续监测能力,配合免费的 Web 应用,将健康监测的经济门槛压至最低。在低资源地区,一台 ESP32 终端 + 一部旧手机即可构建起一个家庭健康监测站,让那些从未有机会定期测量生理指标的老年人,第一次拥有了自己的健康数据档案。
成本之外,可及性同样值得关注。CareBridge 硬件终端所使用的全部元器件均为市面上成熟、大批量供应的标准模块,在淘宝、立创商城等平台上可以一键采购,无需特殊渠道或定制订单。这意味着任何具备基本动手能力的人——无论是社区志愿者、基层医生还是返乡大学生——都可以按照开源文档自行组装并部署一台终端,为身边的老人搭建健康监测能力。这种"开源硬件+免费软件"的模式,本质上是对传统医疗设备商业逻辑的一次重构:不再通过设备销售盈利,而是将健康监测的基础设施以最低成本交付给最需要的人群。
2.4 家庭照护的系统性压力
中国家庭结构在过去四十年间经历了深刻变迁。独生子女政策下成长起来的"80后"“90后"一代,普遍面临"4-2-1"家庭结构的照护压力——一对夫妻需要同时赡养四位老人、抚养一个孩子。国家卫健委数据显示,中国现有独生子女家庭约1.8亿户,其中相当比例的独生子女已进入需要承担父母赡养责任的中年阶段。与此同时,人口流动使得"异地养老"成为常态:第七次全国人口普查数据显示,中国流动人口规模达3.76亿,大量年轻人离开家乡前往一二线城市工作,父母留守原籍,形成了数量庞大的"空巢家庭”。民政部估算,中国空巢老人占老年人口比例已超过50%,部分省份甚至超过60%。
异地照护带来的不只是地理距离,更是信息黑箱。子女无法亲眼观察父母的日常状态,电话询问得到的信息又高度失真——父母不愿让子女担心,往往会隐瞒身体不适。当突发状况发生时,子女往往是在事后才得知消息,错失了最佳干预时机。
照护压力对承担者的身心健康同样产生着深远影响。多项流行病学研究揭示了照护者倦怠综合征(caregiver burnout)的生物学代价:长期高强度的照护工作与端粒缩短相关,一项发表于《美国国家科学院院刊》(PNAS)的研究发现,高压力照护者的端粒长度比对照组平均缩短约12%,相当于细胞加速老化了4-8年。端粒是染色体末端的保护性结构,其长度被视为细胞衰老的生物学标志,端粒缩短意味着免疫系统功能下降、慢性炎症水平上升、 age-related disease(年龄相关疾病)的发病风险增加。照护压力还显著增加心血管疾病风险,一项追踪10年的队列研究显示,高强度照护者罹患心血管疾病的风险是非照护者的2.3倍,高血压、冠心病和心律失常的发生率均显著升高。此外,照护者中抑郁和焦虑的检出率是非照护者的2-3倍,睡眠障碍发生率高达60%以上。照护不是无偿的——它以照护者自身的健康为代价在支付。
在这一困境中,女性承受着不成比例的负担。国家统计局时间利用调查数据显示,中国女性平均每天用于无偿照料活动(包括照料家庭成员、家务劳动等)的时间为2小时56分钟,男性为1小时15分钟,女性承担的无偿照料工作占比高达76.2%。在健康照护场景中,无论是陪老人就诊、日常服药管理还是术后护理,女性往往是第一责任人。CareBridge 的家庭健康协同模块正是针对这一结构性压力而设计:通过 ESP32 硬件终端自动采集父母健康数据并同步至家庭空间,让照护从"电话询问+假期探望"升级为"实时感知+异常预警",减轻子女特别是女性照护者的信息焦虑与行动负担。
2.5 信息过载与理解困境
在信息爆炸的时代,健康知识的获取不是太少,而是太多——多到真假难辨、多到无从选择。中国科学院一项针对健康信息传播的研究发现,中文互联网上与健康相关的信息中,约30%存在不同程度的科学错误或误导性表述。社交媒体上流传的"养生偏方"与"伪医学知识"往往比专业医学信息传播得更快、更广,普通用户缺乏辨别能力,容易在错误信息的引导下做出有害健康的决策。
即便是来自正规渠道的健康信息,普通用户也面临理解障碍。体检报告是典型场景:一份标准的年度体检报告通常包含数十项指标,每项指标附有参考值范围和临床注释,但对大多数非医学背景的用户而言,这些数字和术语如同天书。中国健康促进基金会的一项调查显示,超过80%的体检者无法完全理解自己的体检报告,不知道哪些指标异常需要关注、哪些在可接受范围内波动。许多人拿到报告后只是看一眼"有没有箭头",对异常指标的严重程度、潜在风险和应对措施缺乏基本认知。
CareBridge 的智能体检报告解读模块正是基于这一能力构建。用户拍照上传体检报告后,系统通过 OCR 识别提取各项指标,再由 AI 逐条解读:不仅标注异常指标,还用通俗语言解释每项指标的含义、异常的可能原因、建议的应对措施,并与历史数据对比展示趋势变化。AI 健康助手则作为24小时在线的健康知识翻译官,将用户用日常语言提出的健康问题,转化为基于权威医学文献的专业回答。在信息过载与理解困境并存的当下,CareBridge 做的不仅是提供信息,更是过滤噪音、翻译专业、降低普通人获取可靠健康知识的认知门槛。
值得注意的是,AI 在健康信息翻译中的价值不仅体现在准确性上,更体现在可及性上。传统模式下,普通人想要理解一项体检指标异常的含义,要么挂号排队等待医生解释,要么自行上网搜索——前者时间成本高昂,后者信息质量不可控。AI 健康助手的介入将这一过程压缩至秒级响应,用户在拿到报告的当下就能获得初步解读,知道哪些异常需要立即就医、哪些可以在生活方式调整后复查。这种"即时翻译"能力对于居住在医疗资源匮乏地区的人群尤为重要——当最近的医院在50公里外时,一次准确的 AI 解读可能就是及时就医与延误治疗之间的分界线。
三、复赛升级:从 Web 应用到"软件+硬件"融合方案
3.1 为什么要加硬件
初赛阶段,CareBridge 以纯 Web 应用的形态完成了核心功能验证。我们对这个版本最有信心的一点是长辈模式——字体放大到24px,操作压缩到3步以内,对比度达到WCAG AA标准。我们觉得已经把适老化做到位了。
复赛准备期间,我们决定先在自己家人身上验证一下。我们没有走进社区或养老院做正式调研——说实话也没有那个资源和时间——而是直接把 CareBridge 装到了家人父母的手机上,请他们试用。
结果比我们预想的要差很多。
团队成员的母亲(63岁)试用长辈模式时,反复在输入血压数字时误触返回键,每次输入到一半就被弹回上一页,试了三四次后她把手机放下了,说"太麻烦了,我拿本子记就行"。另一位成员的父亲(67岁)则卡在了菜单导航上——他不知道"健康记录"和"今日速记"有什么区别,在几个页面之间来回切换了几次后,放弃了。还有一位成员的婆婆(58岁)倒是成功完成了记录,但第二天就忘了怎么进去——她把App图标和微信混在了一起,找不到入口。
这些反馈让我们意识到一个根本性问题:纯软件方案在银发群体中存在天花板。我们做了24px大字体,做了3步操作路径,做了高对比度配色——但这些优化都是在"软件框架内"做的,底层逻辑依然是"打开手机→找到App→点击按钮→输入数据"。这个流程对年轻人来说是无感的,但对老年人来说,每一步都是一道坎。触屏操作的精细动作要求、文字输入的认知负担、多层级菜单的导航复杂度,不是"再优化一下界面就能解决"的——它们是智能手机交互范式本身对老年人设置的结构性壁垒。
更深层的问题在于,每一次使用挫败都会强化老年人对数字产品的排斥心理。团队成员的母亲在第一次试用失败后,后来我们请她再试一次,她的第一反应是"我肯定又弄不好"。这种"尝试-失败-放弃"的循环,不是靠把字体再放大两号能打破的。
促使我们下定决心做硬件的,还有一个更早的记忆。2020到2021年新冠期间,我们身边有不少人感染后出现胸闷、喘不上气的情况。大多数人第一反应是"可能太累了,歇歇就好",或者以为是焦虑发作,几乎没有人往血氧方向想——直到血氧仪在社交媒体上被广泛讨论后,才发现有些人的血氧饱和度已经降到危险水平,自己却浑然不觉。这件事给我们留下了一个很深的印象:人体对缺氧的感知是迟钝的,当你觉得"只是有点喘"的时候,血氧可能已经跌破90%。如果当时手边就有一个能随手一测的设备,很多人可能会更早意识到问题的严重性。
这个记忆和家人试用的挫败感汇到了一起,指向同一个结论:有些健康信号,靠用户自己"想起来去记录"是来不及的。血压、血糖这些指标,老年人好歹知道要量;但血氧、心率这些,人很难靠主观感觉判断异常——你觉得喘,不一定知道是血氧低;你觉得心慌,不一定知道心率已经飙到130。必须有一个设备,在人不经意的时候就把数据采下来。
我们由此做出了复赛阶段最关键的产品决策:尝试开发专用硬件终端,把银发群体的健康数据采集从"手动输入"往"按一下就能测"的方向推。硬件终端的唯一交互是一个物理按钮——按下即测量,测量即上传,无需任何其他操作。这不是为硬件而硬件,而是我们自己家人的真实反馈和新冠期间的记忆共同逼出来的方向。我们不敢说这个方案已经成熟,但它至少是一个值得验证的思路。
3.2 ESP32 硬件终端设计
硬件选型
ESP32 硬件终端的选型以"低成本、易获取、尽量可靠"为核心原则。所有元器件均为市场上成熟、易购的标准模块,无需定制 PCB,降低了复现门槛:
| 元器件 | 型号 | 功能 | 参考成本 |
|---|---|---|---|
| 主控芯片 | ESP32 DevKit | 微控制器 + BLE + WiFi | ~15元 |
| 心率血氧传感器 | MAX30102 | 心率与血氧饱和度采集 | ~12元 |
| 温度传感器 | DS18B20 | 精准体温测量(±0.5°C) | ~19元 |
| 合计 | | | ~46元 |
硬件架构
终端采用双总线架构连接各传感器模块。MAX30102 心率血氧传感器与 SSD1306 OLED 显示屏共用 I2C 总线,分别占用地址 0x57 和 0x3C,通过 ESP32 的 GPIO21(SDA)和 GPIO22(SCL)引脚连接。DS18B20 温度传感器采用 1-Wire 总线协议,连接至 GPIO4 引脚,并配备 4.7kΩ 上拉电阻以保障信号稳定性。蜂鸣器连接至 GPIO25 引脚,支持 PWM 驱动产生不同频率的提示音。
接线方案在设计时便考虑了组装的简洁性:所有模块均通过杜邦线连接至 ESP32 开发板的排针引脚,无需焊接,一名没有硬件经验的开发者也能在30分钟内完成组装。这一设计选择刻意牺牲了成品的体积紧凑性,换取了极低的组装门槛,使得 CareBridge 硬件方案可以被任何地区的团队低成本复现。
数据传输方案
ESP32 终端通过 BLE(低功耗蓝牙)与用户设备通信。技术方案上,团队选择了一个对终端用户近乎"零配置"的路径——Web Bluetooth API。用户无需下载任何 App,只需在手机或电脑浏览器中打开 CareBridge Web 应用,点击"连接硬件"按钮,浏览器即会弹出系统原生的蓝牙设备选择对话框,选中 ESP32 终端后建立连接。测量数据通过 BLE GATT 特征值(Characteristic)从 ESP32 传输至浏览器,由 Web 应用解析后存入本地 localStorage,不经过云端服务器。
Web Bluetooth API 的优势在于将蓝牙通信能力直接嵌入浏览器,绕过了"安装 App"这一对老年人最不友好的环节。代价是浏览器兼容性存在限制:Chrome、Edge 和 Opera 在桌面端和 Android 端完整支持 Web Bluetooth API,但 iOS Safari 尚不支持。目前 iOS 用户暂时无法使用硬件连接功能,这是我们后续需要解决的问题——可能的方案包括开发一个轻量的 WebView 壳应用,或等待 Safari 对 Web Bluetooth API 的支持。
3.3 硬件与软件的协同设计
数据流路径
ESP32 硬件终端采集的数据遵循一条完整的流路径:传感器采集原始信号 → ESP32 微控制器执行滤波与计算 → BLE 传输至浏览器 → Web 应用解析并存入 localStorage → 前端实时展示与异常告警判定 → 用户可选择通过飞书表格同步备份数据。整条链路不依赖云端服务器,数据始终留在用户设备本地。
心率数据的采集与计算是这条路径中最关键的环节。MAX30102 传感器以 100Hz 采样率输出红外光与红光通道的原始光电容积脉搏波(PPG)信号,ESP32 微控制器对原始信号执行四点滑动平均滤波以抑制高频噪声,随后通过峰值检测算法计算瞬时心率,并对5秒窗口内的有效峰值取平均,输出一个稳定的心率读数。体温数据由 DS18B20 直接输出数字温度值,精度为 ±0.5°C,无需额外信号处理。
与可穿戴设备模块集成
硬件终端采集的数据并非孤立存在,而是汇入 CareBridge 的统一健康数据层。在可穿戴设备集成模块中,用户从 Apple Watch、华为手环等设备同步的活动量、睡眠时长、血氧饱和度等数据,与 ESP32 终端采集的心率和体温数据在时间轴上对齐,构建出完整的每日健康画像。AI 健康助手在生成建议时,可以同时参考"今日心率基线为72bpm(ESP32测量)“和"昨晚深睡时长仅42分钟(Apple Watch同步)”,给出"睡眠不足可能导致今日心率偏高,建议今晚提前1小时入睡"这样的跨数据源综合分析。
异常告警机制
硬件终端与 Web 应用共同构建了异常告警机制。ESP32 端内置本地告警逻辑,当检测到心率超过 120bpm 或低于 40bpm,或体温超过 37.5°C 或低于 35.0°C 时,蜂鸣器立即发出急促提示音,OLED 屏幕同步显示异常图标,提醒用户或在场人员注意。这一本地告警不依赖网络连接,即使在断网状态下也能工作。
Web 应用端则在数据存入本地后进行风险评估。当异常数据持续超过设定阈值或与用户历史基线出现显著偏离时,应用内会标注异常提醒,包含异常指标值、发生时间、建议措施。家庭成员如果同步了数据(通过飞书表格或手动查看),也能看到这些标注。目前这套告警机制还不支持实时远程推送——这是我们后续需要完善的方向,需要搭建云端服务才能实现真正的"异常时主动通知远端守护人"。
告警阈值的设定并非随意,而是参考了临床医学的通用标准。静息心率正常范围为60-100bpm,当心率超过120bpm时可能提示心动过速、甲亢、贫血或急性感染;低于40bpm则可能提示心动过缓、传导阻滞或药物副作用。体温方面,37.5°C是低热的临床界限,持续升高可能预示感染或炎症反应;35.0°C以下则属于低体温症范畴,在老年人中可能是脓毒症的早期信号。将这些临床阈值嵌入硬件终端的本地逻辑中,意味着即使老人本人不了解这些数字的含义,设备也能在危险来临时自动发出声响提醒,让在场人员及时关注。
3.4 硬件开发的 TRAE 实践
CareBridge 的 ESP32 固件开发全程在 TRAE IDE 中完成。团队选择 TRAE 的原因有三:一是 TRAE 对 Arduino 项目结构的原生支持,可以直接管理 .ino 源文件与 libraries 依赖;二是 TRAE 的 AI 辅助编程能力显著加速了底层硬件代码的编写,尤其是在传感器驱动配置和信号处理算法实现这两个对工程经验要求较高的环节;三是 TRAE 的代码审查功能帮助团队在开发早期发现了多个潜在的内存泄漏和定时器冲突问题。
固件的核心逻辑围绕两个技术要点展开。第一是四点滑动平均滤波器。MAX30102 传感器输出的 PPG 原始信号存在显著的高频噪声,直接用于峰值检测会导致心率计算出现大幅跳动。团队在 TRAE 中实现了四点滑动平均滤波算法,维护一个长度为4的循环缓冲区,每次新采样到达时更新缓冲区并计算四点均值,将滤波后的信号送入峰值检测器。这一处理显著平滑了信号波形,使心率读数的稳定性提升了约60%。
第二是非阻塞 millis() 定时器。Arduino 传统的 delay() 函数会阻塞整个主循环,在 delay 期间无法响应传感器中断和用户按键事件。团队使用 millis() 函数实现非阻塞定时调度,在主循环中通过比较当前时间戳与上次执行时间戳的差值来触发不同任务:传感器采样每10ms执行一次,OLED 刷新每100ms执行一次,心率计算每5秒输出一次结果,BLE 数据广播每1秒执行一次。非阻塞设计保证了用户在任何时刻按下测量按钮都能得到即时响应,不会因为系统正在执行其他任务而出现卡顿或无响应。这一设计模式在嵌入式开发中被称为"协作式调度",相比 FreeRTOS 等抢占式实时操作系统,它更轻量、更易调试,在 ESP32 这种资源相对充裕的平台上能够充分满足 CareBridge 终端的功能需求。
固件开发过程中,TRAE 的 AI 辅助在两个场景中发挥了关键作用。一是传感器初始化配置——MAX30102 的寄存器配置涉及采样率、脉冲宽度、量程等多个参数的协同设置,AI 根据心率监测场景自动生成了推荐的寄存器配置代码,并附带了每个参数的原理说明。二是滤波算法优化——团队描述了"需要在不引入明显延迟的前提下平滑 PPG 信号"的需求,AI 建议了四点滑动平均方案并提供了循环缓冲区的实现代码,团队在此基础上根据实际信号质量微调了窗口大小。整个固件开发周期从零到可用的稳定版本仅用了5天时间,TRAE 的 AI 辅助在其中贡献了约40%的代码生成与优化工作量。
四、产品创作历程
4.1 灵感来源:三束光照进同一个缺口
CareBridge 的诞生并非某一次会议的产物,而是三个真实生活场景在同一个时间窗口里交汇的结果。
第一束光来自一位团队成员的母亲。2026年初春,她的母亲在年度体检中查出甲状腺结节 TI-RADS 4a 级,医生建议穿刺活检。然而这位成员当时正在另一个城市工作,面对体检报告上一连串陌生的医学术语,她既无法判断严重程度,也无法在母亲就诊时陪伴在侧。那种隔着屏幕看到母亲发来的报告照片、却什么也做不了的无力感,成为 CareBridge 最初的种子。
第二束光来自异地照护的日常焦虑。团队中另一位成员的父亲患有二型糖尿病,需要每天监测血糖、记录用药、定期复查。因为相隔千里,她只能靠电话询问"今天血糖多少"“药吃了吗”,但父亲常常记不清具体数值,或者报出一个模糊的"还好"。她曾多次尝试用手机上的健康管理 App 帮父亲记录数据,但这些 App 要么操作复杂、要么需要注册登录、要么把年轻人的健身逻辑强加给老年人,父亲用了一周便放弃了。
第三束光来自一组令人震惊的数据。全球有38亿女性,但当我们打开应用商店搜索"女性健康"时,排名靠前的产品几乎清一色聚焦于年轻女性的经期追踪和生育管理。从青春期到围绝经期,从孕产期到老年慢性病管理,女性在不同生命阶段面临的健康挑战截然不同,却几乎没有一款产品能够覆盖全生命周期。更不用说那些需要家庭共同照护的银发群体——他们的健康数据散落在各家医院的体检报告中,子女想帮忙整理却无从下手。
更深层的问题在于,现有产品几乎都假设用户是"主动的健康管理者"——愿意每天打开 App、手动录入数据、阅读健康科普。但现实中的老年人和忙碌的中年人恰恰不是这样的用户。他们需要的是被动采集、自动分析、主动提醒。这也解释了为什么市面上那么多健康管理 App 都逃不过"下载后用三天就遗忘"的命运——它们把数据录入的负担完全压在了用户身上。
这三束光照亮的其实是同一个缺口:市场上缺少一款真正面向女性、家庭与银发群体,能够覆盖全生命周期、支持多成员协同照护、并且足够"适老"的健康管理工具。这款工具不应该只是一块屏幕上的 App,它还应该包括一个让老年人"放下手指就能测"的硬件终端——让数据采集从"主动录入"变成"被动采集",让健康管理从"一个人的事"变成"一家人的事"。
我们给这款产品取名 CareBridge——Care 代表照护,Bridge 代表桥梁。它要做的是连接人与健康数据、连接家庭成员之间的照护关系、连接不同生命阶段的健康需求。三个连接,恰好对应产品三个核心维度:软件+硬件的产品形态、多成员家庭的数据模型、七种生命周期模式的动态切换。
4.2 从想法到初赛 Demo:七天的极限冲刺
2026年7月,报名参加了 TRAE AI 创造力大赛。初赛的要求是在有限时间内提交一个可运行的 Demo,展示产品的核心价值和基本功能。
面对从零到一的挑战,我们做出了第一个关键决策:用 TRAE Work 的 Auto 模式完成产品定义和架构设计,用 TRAE IDE 完成核心功能开发。这个决策源于一个朴素的认识——我们需要的不是从第一行代码开始手写,而是先用 AI 把产品蓝图想清楚,再在蓝图的指导下高效编码。
在 TRAE Work 的 Auto 模式下,我们用自然语言描述了 CareBridge 的核心愿景:"一款面向女性、家庭与银发群体的全生命周期 AI 健康共护应用,支持多成员家庭健康管理、ESP32 硬件终端采集生理数据、AI 风险评估引擎、飞书表格同步。"Auto 模式随即帮我们梳理出了产品的架构脉络:前端采用 React + TypeScript + Vite 的技术栈,状态管理使用 Zustand,硬件端使用 ESP32 + MAX30102 传感器,数据同步对接飞书多维表格。
基于这张架构蓝图,我们在 TRAE IDE 中开始了核心功能的开发。初赛阶段,我们聚焦于七个核心功能模块:
- 用户档案管理 — 支持创建个人健康档案,记录基本信息、既往病史、过敏史
- 症状日志记录 — 提供17类常见症状的结构化录入界面
- 生理周期追踪 — 面向女性用户的经期、排卵期追踪
- 健康数据可视化 — 用 Recharts 绘制体重、血压、心率等趋势图
- AI 风险评估 — 基于规则引擎的健康风险提示
- 家庭成员管理 — 添加和管理家庭成员的健康档案
- 飞书表格同步 — 将健康数据同步到飞书多维表格
七天时间,从产品定义到架构设计到代码实现,TRAE 的全流程辅助让我们做到了原本可能需要一个月才能完成的工作量。初赛 Demo 虽然功能还不够丰富,界面还不够精致,但它验证了一个核心假设:用 AI 驱动的开发工具,一个小团队也能做出覆盖软件+硬件的完整健康产品。
4.3 从 Demo 到完整作品:四个阶段的进化之路
初赛通过后,我们获得了进入复赛的机会。但 Demo 和完整作品之间的差距是巨大的——Demo 只需要证明"能做",而完整作品需要证明"好用"。我们给自己定了一个目标:把 CareBridge 从一个概念验证,打造成一款真正可以交付使用的产品。
这个过程分为四个阶段,每个阶段都伴随着架构决策和技术攻坚。
第一阶段:架构重构——从"能跑"到"能扩展"
初赛 Demo 最大的问题是架构的脆弱性。七个功能模块的状态管理散落在各个组件中,组件之间通过 props 层层传递数据,每新增一个功能就需要在多个组件间增加数据通路。这种架构在七个模块时还能勉强维持,但当我们计划扩展到60+模块时,它注定会崩溃。
我们做的第一个架构决策是引入 Zustand 单一 Store 模式。这不是一个轻率的决定——在初赛阶段我们就用过 Redux,但 Redux 的样板代码太多,每增加一个状态都需要写 action creator、reducer、constant 三套代码,开发效率极低。Zustand 的优势在于它可以用极少的代码定义状态和操作,同时支持中间件、持久化、DevTools 等高级特性。
最终我们设计了一个包含190个顶层字段的单一 Store,其中38个是状态字段(state),152个是操作函数(action)。这些字段涵盖了用户档案、症状日志、生理周期、家庭管理、硬件数据、风险评估、应用配置等全部业务领域。所有状态通过 Zustand 的 persist 中间件持久化到 localStorage,键名为 night-sugar-storage,版本号为3。
版本号的设计不是多余的——它在数据结构演进时发挥关键作用。当 Store 结构发生 breaking change(比如新增字段、重命名字段、改变嵌套结构)时,我们递增版本号并在 migrate 函数中编写迁移逻辑。用户升级到新版 CareBridge 后,persist 中间件会检测到版本不匹配,自动调用 migrate 函数将旧版本数据转换为新版本格式。这样用户不会因为产品升级而丢失历史健康数据,而开发者也不需要维护多套数据结构。
单一 Store 的好处是全局状态的一致性——任何一个组件都可以直接订阅所需的状态切片,不需要通过 props 链传递。但190个字段也带来了一个挑战:如何管理多成员家庭的健康数据?
答案是 HouseholdMemberState。这是我们在 Store 中设计的多成员家庭状态管理机制。每个家庭成员都有自己独立的 HouseholdMemberState 实例,包含该成员的用户档案、症状日志、生理数据、硬件采集数据等。通过 currentMemberId 字段切换当前活跃成员,所有界面组件自动渲染对应成员的数据。这种设计让一个 App 可以同时管理爷爷的血糖、妈妈的血压、女儿的经期,且数据之间完全隔离。
前端构建层面,我们引入了 Vite 的 manualChunks 分包策略。将 vendor 依赖、React 运行时、图表库、动画库分别打包为独立的 chunk,配合路由级别的懒加载,首屏加载资源从初赛时的2.3MB 降低到380KB。70+个页面全部通过 lazyWithRetry 函数包装,不仅实现了按需加载,还在 chunk 加载失败时自动重试——这在弱网环境(如老年人家庭 WiFi 信号不佳的场景)下尤为重要。
分包策略的细节也经过调优。最初我们把所有 vendor 依赖放在一个 chunk 中,结果这个 chunk 体积超过800KB,反而拖慢了首屏。后来我们按照依赖的使用频率和体积重新划分:React 运行时单独成 chunk(因为每个页面都用),Recharts 单独成 chunk(只有数据可视化页面用),Tesseract.js 单独成 chunk(只有 OCR 页面用,且体积超过2MB)。这样首屏只需要加载 React 运行时 chunk,其余按需加载。
第二阶段:功能扩展——从七个模块到六十余个
架构重构完成后,我们开始了大规模的功能扩展。七个核心模块逐步扩展为60+个功能模块,覆盖了健康档案、症状追踪、生理周期、用药管理、体检报告、风险评估、家庭协同、硬件数据、适老化交互等九大领域。具体而言,每个领域都经历了从"基础可用"到"场景丰富"的迭代:
- 健康档案从简单的信息录入扩展为80+字段、21个临床子档案的结构化体系,支持 OCR 识别体检报告自动提取指标
- 症状追踪从单一的文本输入扩展为17类症状的结构化录入,每类症状有专属的字段模板和严重度量表
- 生理周期从经期记录扩展为覆盖青春期到围绝经期的全周期管理,包含基础体温曲线、排卵预测、激素水平追踪
- 用药管理新增了药物相互作用检查、用药提醒推送、处方药续方提醒
- 体检报告支持拍照 OCR 识别、指标趋势对比、异常值自动标红
- 风险评估从简单的阈值判断升级为规则引擎+AI 分析的双轨架构
- 家庭协同新增了监护人权限管理、数据可见性控制、飞书表格共享
- 硬件数据完成了 ESP32 固件开发、BLE 通信、数据可视化全链路
- 适老化交互新增了长辈模式、大字体渲染、简化导航路径
扩展过程中遇到的核心挑战是数据模型的灵活性。不同生命阶段的用户需要记录的健康数据差异巨大——青春期女孩需要记录初潮年龄和经期规律,孕产期女性需要记录孕周和产检数据,围绝经期女性需要记录激素水平和骨密度,老年人需要记录慢性病指标和用药清单。如果为每种场景设计独立的数据结构,代码会变得极其臃肿;如果用一个大而全的结构覆盖所有场景,又会造成大量空字段。
我们的解决方案是"统一核心字段+扩展字段"的混合模式。UserProfile 类型包含80+个核心字段,这些字段对所有用户通用(如姓名、性别、出生日期、血型等)。同时,我们定义了21个嵌套的临床子档案(如 menstrualHistory、pregnancyRecord、medicationList、chronicDisease 等),每个子档案都是可选的,只在用户进入对应生命阶段时激活。
这种设计的精髓在于 appMode 字段。appMode 是一个枚举类型,定义了7种生命周期模式:teen、reproductive、pregnancy、postpartum、perimenopause、elderly、general。当 appMode 切换时,界面会自动展示对应生命阶段的功能模块和数据字段。例如,切换到 pregnancy 模式后,首页会显示孕周计算器、产检提醒、胎动记录等模块;切换到 elderly 模式后,首页会显示慢病指标监测、用药提醒、跌倒风险评估等模块。
这种"一套数据模型,七种呈现模式"的设计,让我们用一套代码覆盖了从青春期到银发期的全生命周期需求。
第三阶段:ESP32硬件开发——从纯软件到软硬件协同
这是整个复赛升级中最具挑战性的阶段。我们的团队成员全部是 Web 前端和后端开发背景,没有任何嵌入式开发经验。但 CareBridge 的愿景中,硬件终端是不可或缺的一环——老年人不会主动打开 App 录入数据,但他们会愿意把手指放在一个小设备上测一下心率和体温。
硬件选型的第一步是主控芯片。我们在 ESP32、Arduino Nano 33 BLE Sense 和树莓派 Pico W 之间做了详细对比(具体对比见4.4节)。最终选择 ESP32 的原因很简单:它有成熟的 BLE 支持、丰富的社区资源、极低的成本(单片不到20元),且 Arduino Core 框架对新手极其友好。
传感器选型方面,我们对比了 MAX30102、MAX30105 和 Pulse Sensor 三款心率传感器。MAX30105 虽然集成了粒子传感器功能,但心率测量的精度与 MAX30102 相当,且价格高出近一倍;Pulse Sensor 是模拟传感器,需要 ADC 采集,且没有内置的 FIFO 缓冲区,实时性较差。MAX30102 集成红光和红外光 LED、光电探测器、ADC 和 FIFO,通过 I2C 接口输出数字信号,是心率/血氧测量的工业标准选择。
温度传感器的选型相对简单。我们选择了 DS18B20 防水型温度传感器,原因是它输出数字信号(不需要 ADC),防水外壳可以直接接触皮肤测量体表温度,精度为±0.5°C 满足健康监测需求,且 OneWire 协议只占用一个 GPIO 引脚。我们也考虑过 MLX90614 红外非接触式温度传感器,但它价格是 DS18B20 的5倍以上,且非接触式测量受环境温度和测量距离影响较大,重复性不如接触式。对于老年人"把手指放在设备上"的使用场景,接触式测量更自然也更准确。
固件开发我们选择了 Arduino 框架而非 ESP-IDF。虽然 ESP-IDF 提供更底层的控制能力,但 Arduino 框架的抽象层更高,社区示例更丰富,对于没有嵌入式经验的团队来说学习曲线更平缓。固件开发的核心工作包括五项:
- 传感器初始化 — 配置 MAX30102 的采样率(100Hz)、LED 脉冲宽度(411μs)、脉冲幅度(0x0F)、ADC 范围(4096)、FIFO 平均样本数(8)
- FIFO 读取 — MAX30102 的 FIFO 寄存器可以缓冲32个采样点,我们每50ms 读取一次 FIFO,避免数据溢出
- PPG 滤波 — 原始 PPG 信号包含大量噪声,我们实现了4点滑动平均滤波器平滑信号
- 峰值检测 — 在滤波后的信号上检测 PPG 峰值,约束最小峰值间隔300ms(对应心率200bpm)、最大峰值间隔2000ms(对应心率30bpm)
- BLE GATT 配置 — 定义心率服务(0x180D)和环境传感服务(0x181A),配置对应特性值的读写权限
Web 端集成通过 Web Bluetooth API 实现。浏览器直接与 ESP32 建立 BLE 连接,读取心率数据和温度数据,无需中间服务器。这种方式的优势是数据完全不经过互联网,最大程度保护隐私。
第四阶段:稳定性打磨与适老化设计
功能开发完成后,我们花了大量时间在稳定性和适老化上。这两个方向看似不同,但本质上是同一件事——让产品对所有人都能可靠、易用。
稳定性方面,我们建立了三层防护体系。第一层是 lazyWithRetry——所有路由级组件都通过这个高阶函数包装,在 chunk 加载失败时自动重试最多3次,每次间隔指数退避。第二层是 ErrorBoundary——我们在 App 根组件、路由容器、功能模块三个层级各包裹了一层 ErrorBoundary,任何一个组件崩溃不会导致整个应用白屏,而是显示友好的错误提示和重试按钮。第三层是 PWA Service Worker——我们配置了智能缓存策略,对 HTML 使用 NetworkFirst(优先网络、回退缓存),对 JS/CSS 使用 StaleWhileRevalidate(优先缓存、后台更新),对图片使用 CacheFirst(优先缓存),让应用在离线状态下也能正常使用。
适老化设计是 CareBridge 的核心差异化。我们在软件和硬件两个维度都做了深度适老化。
软件层面,我们设计了"长辈模式"。当用户切换到长辈模式后,全局字体大小提升至18px 以上,所有文本颜色对比度达到 WCAG AA 标准(4.5:1以上),核心操作路径压缩至3步以内(如测量心率:打开设备→点击开始→查看结果),所有可点击元素的触摸区域扩大到44x44pt(符合 Apple HIG 标准)。界面元素去除装饰性图标和动画,只保留功能性元素,降低认知负荷。
长辈模式的设计并非简单的"放大字体",而是一套系统性的适老化改造。我们在设计过程中参考了家人试用时的真实反馈:家人母亲常常分不清"可点击"和"不可点击"的元素,因此我们在长辈模式中为所有可交互元素添加了明显的边框和阴影;家人父亲容易误触返回按钮导致数据丢失,因此我们在表单页面禁用了手势返回,改为显示明确的"保存"和"取消"按钮;家人婆婆对颜色的辨识能力下降,因此我们不仅依赖颜色区分状态(如红色表示异常),还配合文字标签和图标双重提示。这些改进不是来自实验室里的可用性测试报告,而是来自我们看着自己的家人操作产品时发现的每一个卡点。
硬件层面,ESP32 终端的交互设计是我们觉得方向对的地方——老年人不需要打开手机、解锁屏幕、找到 App、点击按钮,只需要把手指放在设备上按一下。设备采集心率和体温,通过蓝牙把数据传到手机上的 CareBridge,再自动记录并评估风险。整个过程的操作门槛很低,这是我们想要的适老化思路。当然,硬件本身的稳定性还需要继续打磨,目前只能说是一个值得验证的方向。
4.4 开发过程中的关键决策
在 CareBridge 的开发过程中,我们面临了多个技术路线的选择。每一个决策背后都有具体的考量和取舍。
为什么选 ESP32(因为便宜)
Arduino Nano 33 BLE Sense 虽然 BLE 版本更高且内置了多种传感器,但价格是 ESP32 的7-8倍,对于一个面向 C 端消费者的产品来说成本过高。树莓派 Pico W 的蓝牙功能受限,且社区中 BLE 外设模式的文档较少。ESP32 在价格、BLE 支持、社区资源和开发难度之间取得了最佳平衡。
为什么选 BLE 直连(vs WiFi 上传)
我们考虑过两种数据传输方案:一是 ESP32 通过 WiFi 将数据上传到云端服务器,App 从服务器获取;二是 ESP32 通过 BLE 直接与手机 App 通信。
选择 BLE 直连的核心原因是隐私。健康数据是最敏感的个人信息之一,通过 WiFi 上传意味着数据需要经过路由器、ISP、云端服务器,任何一个环节的泄露都可能造成严重后果。BLE 直连让数据只在 ESP32 和手机之间传输,不经过互联网,从物理层面杜绝了网络层面的泄露风险。
此外,BLE 直连还有两个优势:一是无需配置 WiFi,老年人不需要输入 WiFi 密码,降低使用门槛;二是响应速度快,BLE 连接建立后数据传输延迟在几十毫秒级别,而 WiFi 上传+服务器中转的延迟通常在数百毫秒到秒级。
为什么选 Zustand(vs Redux)
在初赛阶段我们使用过 Redux,但很快就遇到了瓶颈。Redux 的设计理念是"可预测的状态容器",它通过 action→reducer→state 的单向数据流保证状态变更的可追踪性。但这种设计的代价是大量的样板代码——每增加一个状态需要定义 action type、action creator、reducer 三套代码,且 reducer 中不能有副作用,异步操作需要引入 redux-thunk 或 redux-saga。
Zustand 用更少的代码实现了同样的功能。定义一个 store 只需要一个 create 函数,状态和操作写在同一个对象中,异步操作可以直接在 action 中处理。190个字段如果用 Redux 实现,至少需要写500+行样板代码,而 Zustand 只需要约300行。更重要的是,Zustand 的 API 设计与 React Hooks 完美契合,组件中通过 useStore(selector) 订阅状态切片,天然避免了不必要的重渲染。
为什么选飞书表格同步
飞书表格同步是 CareBridge 的一个差异化功能。用户可以把健康数据一键同步到飞书多维表格,方便与家庭成员共享、与医生沟通、或者做进一步的数据分析。
选择飞书而非其他平台(如 Notion、Google Sheets)的原因有三点:一是飞书在国内的网络访问稳定性远优于 Notion 和 Google Sheets;二是飞书多维表格支持公式、自动化流程、多种视图(表格、看板、甘特图、仪表盘),用户可以对同步过来的健康数据做丰富的二次处理;三是飞书的 OAuth 认证流程成熟,API 文档完善,集成成本低。
还有一个考虑是飞书在家庭场景中的渗透率。很多家庭的子女已经在工作中使用飞书,他们对飞书表格的交互方式非常熟悉。当 CareBridge 把父母的健康数据同步到飞书表格后,子女不需要学习新的工具就能查看和分析数据——这种"零学习成本"的数据共享体验是其他平台难以提供的。同时,飞书表格的协作特性让多位家庭成员可以同时查看和编辑同一份数据,避免了"数据发给大女儿但小女儿没看到"的信息不对称问题。
为什么选"规则引擎+AI"双轨风险评估
风险评估是 CareBridge 的核心功能。我们最初考虑过纯 AI 方案——把所有健康数据扔给大模型让它评估风险。但很快发现了问题:大模型的输出不稳定,同一个输入可能给出不同的评估结果;大模型存在幻觉风险,可能生成看似合理但实际错误的医学建议;大模型的推理延迟较高,不适合实时评估。
纯规则引擎方案则走向了另一个极端——规则是确定性的,但缺乏灵活性和泛化能力,无法处理规则覆盖范围之外的复杂情况。
最终我们选择了双轨架构:规则引擎负责确定性评估,AI 负责补充分析和自然语言解释。规则引擎包含红旗征候识别(7条)、Delta Check(连续监测值异常变化检测)、Westgard 多规则质控(1-2s 警告、1-3s 拒绝、2-2s 拒绝等)、生命周期特异性规则(如孕期空腹血糖>5.1mmol/L 提示 GDM 风险)。规则引擎的输出是结构化的风险等级和具体的触发规则。AI 在此基础上生成自然语言的健康建议和风险评估说明,让用户不仅知道"有风险",还能理解"为什么有风险"和"应该怎么做"。
这种双轨架构既保证了评估的确定性和可靠性,又提供了人性化的解释和建议。
五、TRAE 实践过程
5.1 开发工具与模式
在整个 CareBridge 的开发过程中,我们深度使用了 TRAE 生态的三款工具:TRAE Work 的 Auto 模式和 Code 模式,以及 TRAE IDE。三款工具各有所长,覆盖了从创意构思到代码实现再到硬件调试的全链路。
TRAE Work — Auto 模式
Auto 模式是我们在项目启动阶段使用最多的工具。它的核心能力是根据自然语言描述,自动完成产品定义、功能拆解和架构设计。在 CareBridge 项目中,我们在 Auto 模式下完成了以下工作:
- 产品愿景定义和核心功能拆解
- 前端技术栈选型和架构蓝图设计
- 数据模型设计和状态管理方案规划
- ESP32 硬件选型和固件架构规划
- API 接口设计和数据同步方案
Auto 模式的优势在于它能够从模糊的产品描述中提取出结构化的技术方案。我们输入的是"面向女性、家庭与银发群体的全生命周期 AI 健康共护应用",Auto 模式输出的是包含技术栈、架构图、功能模块清单、数据模型、开发计划的完整方案文档。这种从自然语言到技术方案的转化能力,让团队在项目初期就建立了清晰的技术路线图。
TRAE Code 模式
Code 模式用于具体的代码编写。在 CareBridge 项目中,Code 模式主要承担了两类工作:前端界面开发和 ESP32 固件开发。
前端界面开发方面,Code 模式能够根据界面描述生成完整的 React 组件代码,包括 TSX 结构、Tailwind 样式、状态管理和事件处理。我们通常的协作方式是:先用自然语言描述界面布局和交互逻辑,Code 模式生成初版代码,然后我们通过追加对话微调细节。
ESP32 固件开发方面,Code 模式帮助我们从零学习了 Arduino 框架的开发方式。当我们描述"用 ESP32 读取 MAX30102 传感器的心率数据并通过 BLE 发送"时,Code 模式不仅生成了完整的 .ino 文件,还附带了传感器寄存器配置的详细注释和 I2C 通信协议的说明。
TRAE IDE
TRAE IDE 用于前端逻辑开发、AI 模型集成和硬件固件调试。相比 Code 模式的对话式交互,TRAE IDE 提供了更完整的开发环境,包括文件树管理、多文件编辑、终端集成和实时预览。在飞书代理服务(一个轻量的 Express 脚本,用于解决 CORS 和密钥隔离)的开发中,我们使用 TRAE IDE 管理了路由文件和中间件,并通过内置终端直接运行和测试。
具体来说,TRAE IDE 在以下场景中发挥了不可替代的作用。第一,跨文件重构:当我们把 Zustand Store 从初赛的分散式重构为单一 Store 时,涉及数十个文件的 import 路径和 API 调用更新,TRAE IDE 的全局搜索和批量替换功能让这个过程在几分钟内完成。第二,固件调试:ESP32 固件的串口输出可以通过 TRAE IDE 的终端直接查看,遇到编译错误时,TRAE IDE 能在对话中分析错误信息并给出修复建议。第三,AI 模型集成:风险评估引擎的 AI 分析模块需要调用大模型 API,我们在 TRAE IDE 中编写了 prompt 模板和响应解析逻辑,并通过内置终端快速验证不同 prompt 的输出质量。
5.2 关键开发步骤
步骤一:产品定义与架构设计
Session ID: US.75880**78266763***:b492dc194069e2d4b6ef6c1aaa7fe69a_69dd0dba57314d9af15c04d4.69dd0dbc3ef076e788e8e29b.69dd0dbb57314d9af15c04d5:TRAE Work.1.0.0.2036.1e53b848-eacc-4728-9ae1-f8cddc909a8b.no_ppe.T
这是 CareBridge 项目的第一个 TRAE 会话。我们在 TRAE Work 的 Auto 模式下输入了以下需求描述:
“我要开发一款名为 CareBridge 的健康管理应用,面向女性、家庭和银发群体。核心功能包括:1)全生命周期健康档案管理,覆盖青春期到老年期;2)多成员家庭协同照护;3)ESP32 硬件终端采集心率和体温;4)AI 风险评估引擎;5)飞书表格同步。请帮我设计完整的技术架构和功能模块规划。”
Auto 模式的回复超出了我们的预期。它不仅给出了技术栈推荐(React 18 + TypeScript + Vite + Zustand + TailwindCSS + Recharts),还自动拆解出了功能模块的层级结构,并生成了一份包含前端架构、状态管理方案、硬件选型建议、数据同步策略的完整方案文档。
在后续的对话中,我们进一步追问了几个关键问题:
- 问:“多成员家庭的数据如何隔离?” — Auto 模式建议使用 HouseholdMemberState 设计模式,每个成员维护独立的状态实例,通过 currentMemberId 切换活跃成员,组件通过 selector 订阅当前成员数据。
- 问:“7种生命周期模式如何切换?” — Auto 模式提出了 appMode 字段的设计,配合条件渲染实现模式切换,并为每种模式定义了激活的子档案列表。
- 问:“ESP32 的数据如何传到 Web 端?” — Auto 模式推荐使用 Web Bluetooth API,直接在浏览器中建立 BLE 连接,并解释了相比 WiFi 方案的隐私优势。
Auto 模式还生成了一份架构层次图,将应用分为表示层(React 组件)、状态层(Zustand Store)、数据层(持久化+飞书同步)、硬件层(ESP32+BLE)四个层级,并标注了各层之间的数据流向。这次会话奠定了整个项目的技术基调,后续所有的开发工作都是在这个架构蓝图的指导下完成的。
值得一提的是,Auto 模式在架构设计阶段就预见了几个我们当时没有考虑到的问题。例如,它主动提出"多成员家庭的数据持久化需要考虑成员隔离,不能把所有成员的数据混在一个 localStorage key 下"——这直接促使我们在 persist 配置中设计了 partialize 函数,按成员维度组织持久化数据。又如,它提醒"Web Bluetooth API 需要 HTTPS 环境,开发阶段需要配置自签名证书或使用 localhost"——让我们在项目早期就解决了部署环境问题,而不是在最终部署时才发现。
步骤二:核心界面开发
Session ID 1: US.75880**78266763***:9df11e7b466d5fcb5aeca54eee88670d_69de0fccb870d754b1449a16.69e5ebcda64f97732a61445d.69e5ebcdf80aecf6e886117b:TRAE Work.1.0.0.2036.004da16c-f76d-445b-9226-841ec76c7126.no_ppe.T
Session ID 2: US.75880**78266763***:d621b88ffc3e4907e5e38c753654a65e_69de0fccb870d754b1449a16.69e5ea3ca64f97732a614426.69e5ea3c24a8d044b3864ba2:TRAE Work.1.0.0.2036.004da16c-f76d-445b-9226-841ec76c7126.no_ppe.T
核心界面开发分为两个会话。第一个会话聚焦于主界面 Dashboard 和健康档案管理界面的开发。我们向 TRAE 描述了界面需求:
“设计一个健康管理 App 的主界面,顶部显示当前家庭成员的头像和切换按钮,中间区域显示健康概览卡片(心率、体温、血压、体重),底部是功能模块导航。整体风格要简洁温暖,配色用暖色系。”
TRAE 生成了一个完整的 Dashboard 组件,包含响应式布局、Tailwind 样式、Zustand 状态订阅和成员切换逻辑。代码片段如下:
const Dashboard: React.FC = () => {
const { currentMember, householdMembers, setCurrentMember } = useHealthStore();
const [vitals, setVitals] = useState<VitalSigns | null>(null);
useEffect(() => {
if (currentMember?.hardwareData) {
setVitals(currentMember.hardwareData.latestVitals);
}
}, [currentMember]);
return (
<div className="min-h-screen bg-gradient-to-br from-rose-50 to-amber-50">
<MemberSwitcher
members={householdMembers}
current={currentMember}
onSelect={setCurrentMember}
/>
<VitalCardGrid vitals={vitals} />
<ModuleNavigator modules={getModulesForMode(currentMember?.appMode)} />
</div>
);
};
TRAE 还自动处理了一个细节:当 currentMember 为 null 时(用户首次打开应用尚未添加成员),Dashboard 会渲染一个引导用户创建首个成员的空状态组件。这种边界情况的处理让代码更加健壮。
第二个会话聚焦于症状日志录入界面和 AI 风险评估结果展示界面的开发。在症状日志界面中,我们要求 TRAE 实现17类症状的结构化录入表单,每类症状有专属的录入字段。TRAE 不仅生成了表单组件,还自动设计了一套基于症状类型的动态表单渲染机制:
const SymptomForm: React.FC<{ category: SymptomCategory }> = ({ category }) => {
const addSymptomLog = useHealthStore(s => s.addSymptomLog);
const fields = SYMPTOM_FIELD_MAP[category];
return (
<DynamicForm
fields={fields}
onSubmit={(data) => addSymptomLog({ category, ...data, timestamp: Date.now() })}
/>
);
};
// 症状字段映射表
const SYMPTOM_FIELD_MAP: Record<SymptomCategory, FormField[]> = {
cardiovascular: [
{ name: 'chestPain', type: 'severity', label: '胸痛程度' },
{ name: 'palpitation', type: 'boolean', label: '是否心悸' },
{ name: 'radiation', type: 'select', label: '疼痛放射部位', options: ['左臂', '下颌', '背部', '无'] },
],
neurological: [
{ name: 'headacheLocation', type: 'select', label: '头痛部位', options: ['前额', '颞侧', '枕部', '全头'] },
{ name: 'dizziness', type: 'boolean', label: '是否头晕' },
{ name: 'consciousness', type: 'select', label: '意识状态', options: ['清醒', '嗜睡', '模糊', '昏迷'] },
],
// ... 其余15类症状
};
在调试过程中,我们遇到了一个状态更新的问题:当用户在症状录入过程中切换家庭成员时,未保存的表单数据会丢失。TRAE 建议我们在组件卸载时将表单草稿保存到 Zustand 的临时状态中,切换回来时自动恢复:
useEffect(() => {
return () => {
// 组件卸载时保存草稿
if (formValues) {
useHealthStore.getState().saveFormDraft(formValues);
}
};
}, [formValues]);
useEffect(() => {
// 组件挂载时恢复草稿
const draft = useHealthStore.getState().getFormDraft();
if (draft) setFormValues(draft);
}, []);
这个细节处理让用户体验更加流畅,也展示了 TRAE 对实际使用场景的深入理解。
步骤三:ESP32 硬件固件开发
Session ID: SG.7624369052882256914:a01b014d7c53e2bd97ab4fb45af5a098_69de0fccb870d754b1449a16.6a55d0737ec7d9f938bf93ef.6a55d06cc9af2733805d8957:TRAE Work.1.0.0.2097.f37b62b4-40b1-4327-ad32-9d850b176b27.no_ppe.T
这是整个项目中难度最高的一个会话。我们团队没有嵌入式开发经验,对 I2C 通信、传感器寄存器配置、BLE GATT 协议都一无所知。我们向 TRAE 描述了需求:
“我需要用 ESP32 开发板和 MAX30102 心率传感器开发一个固件,功能是:1)初始化 MAX30102 传感器;2)持续读取心率数据;3)通过 BLE 将心率数据发送给手机。我之前没有嵌入式开发经验,请详细解释每一步的原理。”
TRAE 的回复像一本嵌入式开发教程。它首先解释了 MAX30102 的工作原理——通过红光和红外光照射皮肤,光电探测器接收反射光,通过 ADC 转换为数字信号存储在 FIFO 中。然后详细说明了 I2C 通信协议的基本概念——SDA(数据线)和 SCL(时钟线)的工作方式,以及 MAX30102 的 I2C 地址(0x57)。
生成的固件代码包含了完整的传感器初始化流程:
#include <Wire.h>
#include "MAX30105.h"
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
MAX30105 particleSensor;
BLECharacteristic *heartRateCharacteristic;
#define HEART_RATE_SERVICE_UUID "0000180D-0000-1000-8000-00805F9B34FB"
#define HEART_RATE_MEASUREMENT_UUID "00002A37-0000-1000-8000-00805F9B34FB"
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // SDA=GPIO21, SCL=GPIO22
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {
Serial.println("MAX30102 not found. Check wiring.");
while (1);
}
// 传感器配置
particleSensor.setup(
0x0F, // LED 亮度: 0x00-0xFF
4, // 采样平均: 1, 2, 4, 8, 16, 32
2, // 模式: 多LED模式 (红光+红外)
100, // 采样率: 50, 100, 200, 400, 800, 1000, 1600, 3200
411, // LED 脉冲宽度: 69, 118, 215, 411 μs
4096 // ADC 范围: 2048, 4096, 8192, 16384
);
particleSensor.enableDIETEMPRK(); // 启用芯片温度
// BLE 初始化
BLEDevice::init("CareBridge-001");
BLEServer *server = BLEDevice::createServer();
BLEService *service = server->createService(HEART_RATE_SERVICE_UUID);
heartRateCharacteristic = service->createCharacteristic(
HEART_RATE_MEASUREMENT_UUID,
BLECharacteristic::PROPERTY_NOTIFY
);
heartRateCharacteristic->addDescriptor(new BLE2902());
service->start();
BLEAdvertising *advertising = BLEDevice::getAdvertising();
advertising->addServiceUUID(HEART_RATE_SERVICE_UUID);
advertising->setScanResponse(true);
advertising->setMinPreferred(0x06);
advertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
Serial.println("CareBridge-001 is advertising.");
}
在调试过程中,我们遇到了两个关键问题。
问题一:心率读数不稳定,波动很大。
原始 PPG 信号包含环境光干扰和运动伪影,直接计算心率会导致数值剧烈跳动。TRAE 建议我们增加4点滑动平均滤波器和峰值检测算法:
#define FILTER_SIZE 4
float filterBuffer[FILTER_SIZE];
int filterIndex = 0;
float movingAverage(float value) {
filterBuffer[filterIndex] = value;
filterIndex = (filterIndex + 1) % FILTER_SIZE;
float sum = 0;
for (int i = 0; i < FILTER_SIZE; i++) sum += filterBuffer[i];
return sum / FILTER_SIZE;
}
// PPG 峰值检测
unsigned long lastPeak = 0;
float peakThreshold = 0;
bool aboveThreshold = false;
#define MIN_PEAK_INTERVAL 300 // 最小300ms, 对应200bpm
#define MAX_PEAK_INTERVAL 2000 // 最大2000ms, 对应30bpm
int detectPeak(float filteredValue) {
unsigned long now = millis();
unsigned long interval = now - lastPeak;
// 信号上升超过阈值
if (filteredValue > peakThreshold && !aboveThreshold) {
aboveThreshold = true;
peakThreshold = filteredValue;
}
// 信号下降至阈值80%以下, 确认峰值
if (aboveThreshold && filteredValue < peakThreshold * 0.8) {
aboveThreshold = false;
if (interval >= MIN_PEAK_INTERVAL && interval <= MAX_PEAK_INTERVAL) {
int bpm = 60000 / interval;
lastPeak = now;
peakThreshold = filteredValue;
return bpm;
}
peakThreshold = filteredValue;
}
return -1; // 无有效峰值
}
TRAE 解释了峰值间隔约束的生理依据:健康成人心率范围在30-200bpm 之间,低于30bpm 或高于200bpm 几乎不可能是真实心率,更可能是信号噪声或运动伪影。这个约束有效过滤了误检。
我们还追问了一个问题:"如果用户在测量过程中手指微微移动,导致信号短暂中断怎么办?“TRAE 建议在峰值检测逻辑中增加一个信号质量判断——当连续5个采样点的方差低于阈值时,判定为信号丢失,暂停心率计算并在串口输出"finger detected: false”。当信号恢复后,重新初始化滤波器缓冲区,避免中断期间的噪声数据污染滤波结果。这个处理让测量过程更加鲁棒,用户手指轻微移动不会导致错误的心率读数。
问题二:BLE 连接不稳定,手机偶尔扫描不到设备。
TRAE 指出问题出在 advertising 配置上。默认的 advertising 数据没有包含服务 UUID,部分手机过滤时会跳过不含已知服务 UUID 的设备。添加 addServiceUUID 后,设备可以被所有支持 BLE 的手机稳定发现。
步骤四:Web Bluetooth API 集成
Session ID: SG.7624369052882256914:6df226dfba0dc2106633b4756bbd99ff_69de0fccb870d754b1449a16.6a55c108ff77ca98494f2970.6a55c10722de6473cb4941e0:TRAE Work.1.0.0.2097.f37b62b4-40b1-4327-ad32-9d850b176b27.no_ppe.T
ESP32 固件开发完成后,下一步是在 Web 端集成 Web Bluetooth API。我们向 TRAE 描述了需求:
“我需要在 React 应用中通过 Web Bluetooth API 连接 ESP32 设备,读取心率和温度数据。需要处理设备扫描、连接、数据接收、断线重连等场景。”
TRAE 生成了一套完整的 BLE 管理工具类。核心代码如下:
class CareBridgeBLE {
private device: BluetoothDevice | null = null;
private server: BluetoothRemoteGATTServer | null = null;
private heartRateChar: BluetoothRemoteGATTCharacteristic | null = null;
private tempChar: BluetoothRemoteGATTCharacteristic | null = null;
private reconnectAttempts = 0;
async connect(): Promise<boolean> {
try {
this.device = await navigator.bluetooth.requestDevice({
filters: [{ services: ['heart_rate'] }],
optionalServices: ['environmental_sensing']
});
this.device.addEventListener('gattserverdisconnected', () => {
this.handleDisconnection();
});
this.server = await this.device.gatt!.connect();
// 订阅心率服务
const hrService = await this.server.getPrimaryService('heart_rate');
this.heartRateChar = await hrService.getCharacteristic('heart_rate_measurement');
await this.heartRateChar.startNotifications();
this.heartRateChar.addEventListener(
'characteristicvaluechanged',
this.handleHeartRateData
);
// 订阅环境传感服务 (温度)
const envService = await this.server.getPrimaryService('environmental_sensing');
this.tempChar = await envService.getCharacteristic('temperature');
await this.tempChar.startNotifications();
this.tempChar.addEventListener(
'characteristicvaluechanged',
this.handleTempData
);
this.reconnectAttempts = 0;
return true;
} catch (error) {
console.error('BLE connection failed:', error);
return false;
}
}
private handleHeartRateData = (event: Event) => {
const target = event.target as BluetoothRemoteGATTCharacteristic;
const value = target.value!;
// 心率测量值格式: flags(1 byte) + heart rate(1-2 bytes)
const flags = value.getUint8(0);
const is16Bit = flags & 0x01;
const heartRate = is16Bit ? value.getUint16(1, true) : value.getUint8(1);
useHealthStore.getState().updateHardwareData({
heartRate,
timestamp: Date.now()
});
};
private handleTempData = (event: Event) => {
const target = event.target as BluetoothRemoteGATTCharacteristic;
const value = target.value!;
// 温度值: 16-bit signed integer, 分辨率0.01°C
const tempRaw = value.getInt16(0, true);
const temperature = tempRaw / 100;
// 过滤传感器异常值
if (temperature === -127) {
console.warn('DS18B20 disconnected');
return;
}
if (temperature === 85) {
console.warn('Power-on default value, ignoring');
return;
}
useHealthStore.getState().updateHardwareData({
temperature,
timestamp: Date.now()
});
};
private async handleDisconnection() {
console.log('Device disconnected, attempting reconnect...');
if (this.reconnectAttempts < 5) {
this.reconnectAttempts++;
const delay = Math.pow(2, this.reconnectAttempts) * 1000;
setTimeout(() => this.connect(), delay);
}
}
disconnect() {
if (this.device?.gatt?.connected) {
this.device.gatt.disconnect();
}
}
}
调试过程中,我们遇到了一个 Web Bluetooth API 的兼容性问题——Chrome 浏览器要求 Web Bluetooth 必须在 HTTPS 环境下使用,且设备选择器必须由用户手势触发(不能自动弹出)。TRAE 帮我们设计了用户引导流程:用户点击"连接设备"按钮后弹出设备选择器,连接成功后显示设备状态指示灯,断线时自动重连并显示重连状态。这个流程既满足了浏览器的安全要求,又给用户清晰的操作反馈。
另一个调试中的发现是 BLE 数据解析的字节序问题。心率测量特性(0x2A37)的数据格式由第一个字节的 flags 决定:bit0 为0时心率是1字节 UINT8,bit0 为1时心率是2字节 UINT16。我们最初没有正确解析 flags,导致心率始终读为0。TRAE 帮我们定位了问题——需要先读取 flags 字节,判断心率值的数据类型,再从正确的偏移量读取。温度特性(0x2A6E)的数据是 INT16 小端序,需要用 getInt16(0, true) 读取,true 参数表示小端字节序。这些 BLE GATT 特性值的数据格式定义在 Bluetooth SIG 规范中,TRAE 直接引用了规范文档帮我们正确解析。
步骤五:飞书表格同步集成
飞书表格同步是 CareBridge 与飞书生态的深度集成。我们向 TRAE 描述了需求:
“用户希望把健康数据同步到飞书多维表格,方便与家人共享和与医生沟通。需要实现 OAuth 认证、数据双向同步、代理服务。”
TRAE 帮我们设计了完整的集成方案。首先是 OAuth 认证流程——用户在 CareBridge 中点击"同步到飞书"后,跳转到飞书授权页面,用户授权后回调到 CareBridge,获取 access_token 和 refresh_token。由于浏览器直接调用飞书 API 会面临 CORS 问题,TRAE 建议我们开发一个代理服务:
// proxy.js — 飞书API代理服务, 运行在端口3001
require('dotenv').config();
const express = require('express');
const axios = require('axios');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
// 密钥仅存在于服务器环境变量中
const FEISHU_APP_ID = process.env.FEISHU_APP_ID;
const FEISHU_APP_SECRET = process.env.FEISHU_APP_SECRET;
// OAuth Token 交换
app.post('/api/feishu/token', async (req, res) => {
try {
const response = await axios.post(
'https://open.feishu.cn/open-apis/authen/v1/oidc/access_token',
{
grant_type: 'authorization_code',
code: req.body.code,
app_id: FEISHU_APP_ID,
app_secret: FEISHU_APP_SECRET,
},
{ headers: { 'Content-Type': 'application/json' } }
);
res.json(response.data);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 多维表格批量写入
app.post('/api/feishu/sync', async (req, res) => {
try {
const { token, appToken, tableId, records } = req.body;
const response = await axios.post(
`https://open.feishu.cn/open-apis/bitable/v1/apps/${appToken}/tables/${tableId}/records/batch_create`,
{ records },
{ headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
}}
);
res.json(response.data);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(3001, () => console.log('Proxy server running on port 3001'));
密钥隔离是这套方案的关键。FEISHU_APP_ID 和 FEISHU_APP_SECRET 存储在代理服务器的环境变量中,前端永远无法接触到这些密钥。前端只负责发送授权码和数据,代理服务器负责与飞书 API 通信。这种架构既解决了 CORS 问题,又保证了密钥安全。
在开发同步功能时,我们遇到了一个数据冲突的问题:如果用户在飞书表格中直接修改了某条记录,同时在 CareBridge 中也修改了同一条记录,同步时应该以哪边为准?TRAE 建议我们实现基于时间戳的"最后写入胜出"(Last Write Wins)策略:每条记录都携带 updatedAt 字段,同步时比较两端的修改时间,保留较新的版本。同时,被覆盖的旧版本不会直接删除,而是写入一个"历史版本"表,用户可以在飞书表格的变更记录中回溯。这种设计在简单性和数据安全性之间取得了平衡——对于家庭健康管理场景,LWW 足够实用,而历史版本提供了数据恢复的兜底。
步骤六:性能优化与稳定性保障
Session ID: SG.7624369052882256914:ff080407ad7e92c04cc36f891d5e8366_69de0fccb870d754b1449a16.6a51e92bd51103b48c3efb7a.6a51e92a6e8120cf0a327e74:TRAE Work.1.0.0.2097.f37b62b4-40b1-4327-ad32-9d850b176b27.no_ppe.T
在功能开发基本完成后,我们用这个会话集中处理了性能和稳定性问题。我们向 TRAE 描述了当前的问题:
“应用有70+个页面和190个 Store 字段,首屏加载慢,偶尔出现白屏,弱网环境下 chunk 加载失败。请帮我优化。”
TRAE 从三个层面给出了优化方案。
第一层:路由懒加载与加载失败重试。
TRAE 实现了 lazyWithRetry 高阶函数:
import { lazy, ComponentType } from 'react';
function lazyWithRetry<T extends ComponentType<any>>(
factory: () => Promise<{ default: T }>
) {
return lazy(() => {
const retry = (retries: number): Promise<{ default: T }> => {
return factory().catch((error) => {
if (retries > 0) {
const delay = Math.pow(2, 3 - retries) * 1000;
return new Promise(resolve =>
setTimeout(() => resolve(retry(retries - 1)), delay)
);
}
throw error;
});
};
return retry(3);
});
}
// 使用方式
const Dashboard = lazyWithRetry(() => import('@/pages/Dashboard'));
const SymptomLog = lazyWithRetry(() => import('@/pages/SymptomLog'));
const CycleTracker = lazyWithRetry(() => import('@/pages/CycleTracker'));
// ... 70+ 个页面
指数退避策略(1s → 2s → 4s)避免了在弱网下疯狂重试加剧网络拥塞,3次重试上限防止无限等待。
第二层:ErrorBoundary 三层包裹。
TRAE 生成了 ErrorBoundary 组件,并在 App 根组件、路由容器、功能模块三个层级各包裹了一层:
// App根组件层
<ErrorBoundary fallback={<AppCrashFallback />}>
<BrowserRouter>
{/* 路由容器层 */}
<ErrorBoundary fallback={<RouteCrashFallback />}>
<Suspense fallback={<PageLoader />}>
<Routes>
{routes.map(route => (
<Route
key={route.path}
path={route.path}
element={
<ErrorBoundary fallback={<ModuleCrashFallback />}>
<route.element />
</ErrorBoundary>
}
/>
))}
</Routes>
</Suspense>
</ErrorBoundary>
</BrowserRouter>
</ErrorBoundary>
三层包裹实现了故障隔离:最内层 ErrorBoundary 捕获单个功能模块的崩溃,不影响同页面其他模块;中间层捕获整页渲染异常,显示页面级错误提示;最外层作为最后防线,捕获全局性崩溃。
第三层:PWA Service Worker 智能缓存。
// sw.ts
import { registerRoute } from 'workbox-routing';
import { NetworkFirst, StaleWhileRevalidate, CacheFirst } from 'workbox-strategies';
// HTML: 网络优先, 超时回退缓存
registerRoute(
({ request }) => request.mode === 'navigate',
new NetworkFirst({ cacheName: 'pages', networkTimeoutSeconds: 3 })
);
// JS/CSS: 缓存优先, 后台静默更新
registerRoute(
({ request }) => ['script', 'style'].includes(request.destination),
new StaleWhileRevalidate({ cacheName: 'assets' })
);
// 图片: 缓存优先, 60个上限
registerRoute(
({ request }) => request.destination === 'image',
new CacheFirst({ cacheName: 'images', maxEntries: 60 })
);
NetworkFirst 对 HTML 使用3秒超时:3秒内拿到最新 HTML 就用最新的,超时则回退到缓存。StaleWhileRevalidate 让 JS/CSS 先用缓存立即渲染,同时在后台拉取新版本,下次访问时自动更新。CacheFirst 对图片永久缓存(最多60个),因为图片不常变化且体积大。
经过这套优化,首屏加载时间从3.2秒降低到0.8秒,Lighthouse 性能评分从52分提升到91分。更直观的变化是:在3G 网络模拟环境下,应用从打开到可交互的时间从8秒降低到2.5秒,这对于网络条件不佳的老年用户来说意味着从"等不下去直接关闭"到"可以接受"的体验跨越。
5.3 交互设计与快捷键
在交互设计方面,我们遵循三条核心原则:操作路径最短化、信息层级清晰化、反馈即时化。TRAE 在这一过程中帮助我们快速实现了原型设计到代码的转化。每当我们描述一个交互场景,TRAE 不仅能生成对应的组件代码,还会主动提示边界情况的处理方式,比如空数据状态、加载中状态、错误状态。
快捷键设计是提升效率用户使用体验的重要一环。我们设计了一套覆盖全局导航、数据录入、视图切换的快捷键体系。
const useKeyboardShortcuts = () => {
const navigate = useNavigate();
const { connectDevice, saveSymptomDraft } = useHealthStore();
useEffect(() => {
const handler = (e: KeyboardEvent) => {
const isMod = e.ctrlKey || e.metaKey;
if (!isMod) return;
// Ctrl/Cmd + 1-7: 快速切换功能模块
if (e.key >= '1' && e.key <= '7') {
e.preventDefault();
const modules = [
'dashboard', 'symptoms', 'cycle',
'devices', 'reports', 'family', 'settings'
];
navigate(`/${modules[parseInt(e.key) - 1]}`);
}
// Ctrl/Cmd + D: 快速连接设备
if (e.key === 'd') {
e.preventDefault();
connectDevice();
}
// Ctrl/Cmd + S: 快速保存症状日志草稿
if (e.key === 's') {
e.preventDefault();
saveSymptomDraft();
}
// Ctrl/Cmd + E: 切换长辈模式
if (e.key === 'e') {
e.preventDefault();
useHealthStore.getState().toggleElderMode();
}
};
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler);
}, [navigate, connectDevice, saveSymptomDraft]);
};
快捷键的设计考虑了与浏览器原生快捷键的冲突规避——Ctrl+S 通常触发浏览器保存,我们通过 preventDefault() 拦截并替换为保存症状日志草稿的功能。长辈模式的快捷键 Ctrl+E 则让照护者可以在普通模式和长辈模式之间快速切换,方便在同一台设备上为不同年龄段的家庭成员服务。
六、技术方案分享
6.1 技术栈全景
CareBridge 的技术栈覆盖了前端应用、硬件终端和轻量代理服务三个维度。以下是完整的技术选型清单:
| 层级 | 技术 | 版本 | 用途 |
|---|---|---|---|
| 前端框架 | React | 18.3 | UI 组件框架 |
| 构建工具 | Vite | 5.4 | 开发服务器与打包 |
| 状态管理 | Zustand | 4.5 | 全局状态管理 |
| 样式方案 | TailwindCSS | 3.4 | 原子化 CSS |
| 路由管理 | React Router | 6.26 | SPA 路由 |
| 图表库 | Recharts | 2.12 | 健康数据可视化 |
| 动画库 | Framer Motion | 11.3 | 界面过渡动画 |
| 离线存储 | localStorage | — | Zustand persist 持久化 |
| 数据同步 | 飞书 OpenAPI | v1 | 多维表格双向同步 |
| OCR 识别 | Tesseract.js | 5.1 | 体检报告文字识别 |
| 加密库 | crypto-js | 4.2 | AES-GCM 数据加密 |
| 部署平台 | Vercel | — | 前端 PWA 部署 |
| 硬件主控 | ESP32 | ESP-WROOM-32 | BLE 外设主控 |
| 心率传感器 | MAX30102 | — | PPG 心率/血氧测量 |
| 温度传感器 | DS18B20 | — | 接触式体温测量 |
| 硬件通信 | Web Bluetooth API | — | 浏览器 BLE 通信 |
| 固件框架 | Arduino Core | 3.0 | ESP32 固件开发 |
| 代理服务 | Express | 4.19 | 飞书 API 本地代理(CORS + 密钥隔离) |
6.2 ESP32 硬件技术细节
传感器接线方案
ESP32 与两颗传感器的接线方案如下:
ESP32 MAX30102 DS18B20
------ -------- -------
GPIO21 (SDA) ---> SDA
GPIO22 (SCL) ---> SCL
3.3V ---> VDD VDD
GND ---> GND GND
GPIO4 --> DATA
4.7kΩ 电阻 3.3V ↔ DATA (上拉)
MAX30102 通过 I2C 接口与 ESP32 通信,器件地址为0x57。DS18B20 通过 OneWire 协议通信,数据线需要4.7kΩ 上拉电阻维持信号稳定。
心率信号处理
MAX30102 输出的原始 PPG 信号包含环境光噪声、运动伪影和基线漂移。我们实现了两级信号处理管线。
第一级是4点滑动平均滤波器,用于平滑高频噪声:
#define FILTER_SIZE 4
float filterBuffer[FILTER_SIZE];
int filterIndex = 0;
float movingAverage(float rawValue) {
filterBuffer[filterIndex] = rawValue;
filterIndex = (filterIndex + 1) % FILTER_SIZE;
float sum = 0;
for (int i = 0; i < FILTER_SIZE; i++) {
sum += filterBuffer[i];
}
return sum / FILTER_SIZE;
}
4点窗口在降噪和延迟之间取得了平衡——窗口太小(如2点)滤波效果不明显,窗口太大(如8点)会引入明显延迟,导致心率计算滞后。
第二级是 PPG 峰值检测算法。在滤波后的信号上检测脉搏波峰值,通过约束峰值间隔排除误检:
#define MIN_PEAK_INTERVAL 300 // 最小300ms, 对应心率200bpm
#define MAX_PEAK_INTERVAL 2000 // 最大2000ms, 对应心率30bpm
float peakThreshold = 0;
bool aboveThreshold = false;
unsigned long lastPeakTime = 0;
int detectHeartRate(float filteredValue) {
unsigned long now = millis();
unsigned long interval = now - lastPeakTime;
// 信号上升越过阈值
if (filteredValue > peakThreshold && !aboveThreshold) {
aboveThreshold = true;
peakThreshold = filteredValue;
}
// 信号下降至阈值80%以下, 确认一次脉搏
if (aboveThreshold && filteredValue < peakThreshold * 0.8) {
aboveThreshold = false;
if (interval >= MIN_PEAK_INTERVAL && interval <= MAX_PEAK_INTERVAL) {
int bpm = 60000 / interval;
lastPeakTime = now;
peakThreshold = filteredValue;
return bpm;
}
peakThreshold = filteredValue;
}
return -1; // 无有效峰值
}
最小300ms 的峰值间隔约束对应200bpm 的心率上限,排除运动伪影导致的误检;最大2000ms 的峰值间隔约束对应30bpm 的心率下限,排除信号丢失导致的假阳性。阈值动态跟踪信号峰值,自适应不同用户的 PPG 幅度差异。
温度异常处理
DS18B20 传感器在两种异常情况下会返回固定值,固件和 Web 端都需要过滤:
- 返回-127°C:传感器数据线断开(Open Circuit),I2C 总线读到全0转换后的值
- 返回85°C:传感器上电默认值(Power-On Reset Value),DS18B20 复位后寄存器的初始值
float readTemperature() {
sensors.requestTemperatures();
float temp = sensors.getTempCByIndex(0);
if (temp == -127.0) {
Serial.println("Warning: DS18B20 disconnected (open circuit)");
return NAN; // 返回NaN, 上游丢弃该值
}
if (temp == 85.0) {
Serial.println("Warning: Power-on default (85C), retrying...");
delay(750); // 等待转换完成
sensors.requestTemperatures();
temp = sensors.getTempCByIndex(0);
if (temp == 85.0) return NAN;
}
return temp;
}
Web 端在 handleTempData 回调中同样过滤这两个异常值,避免把-127°C 或85°C 写入健康档案。
BLE 服务配置
ESP32 作为 BLE 外设,向手机暴露两个 GATT 服务:
心率服务(UUID: 0x180D)
| 特性 | UUID | 属性 | 说明 |
|---|---|---|---|
| 心率测量 | 0x2A37 | NOTIFY | 每次检测到新心率时主动推送 |
| 传感器位置 | 0x2A38 | READ | 固定返回0x03(手指) |
环境传感服务(UUID: 0x181A)
| 特性 | UUID | 属性 | 说明 |
|---|---|---|---|
| 温度 | 0x2A6E | NOTIFY | 每次温度更新时推送,16-bit signed, 0.01°C 分辨率 |
| 温度类型 | 0x2A6F | READ | 固定返回0x02(体表温度) |
使用标准的 BLE 服务 UUID(0x180D 心率服务、0x181A 环境传感服务)的好处是兼容性——iOS 和 Android 的系统级健康平台都能识别这些标准服务,未来可以无缝接入 Apple Health 和 Google Fit。
Web Bluetooth API 集成
Web 端通过 Web Bluetooth API 直接与 ESP32 通信,无需中间服务器:
class CareBridgeDevice {
constructor() {
this.device = null;
this.server = null;
this.heartRateChar = null;
this.temperatureChar = null;
this.reconnectAttempts = 0;
this.listeners = new Map();
}
async connect() {
try {
this.device = await navigator.bluetooth.requestDevice({
filters: [{ services: ['heart_rate'] }],
optionalServices: ['environmental_sensing']
});
this.device.addEventListener('gattserverdisconnected',
() => this.handleDisconnect());
this.server = await this.device.gatt.connect();
// 心率服务
const hrService = await this.server.getPrimaryService('heart_rate');
this.heartRateChar = await hrService
.getCharacteristic('heart_rate_measurement');
await this.heartRateChar.startNotifications();
this.heartRateChar.addEventListener(
'characteristicvaluechanged',
this.onHeartRateChange
);
// 温度服务
const envService = await this.server
.getPrimaryService('environmental_sensing');
this.temperatureChar = await envService
.getCharacteristic('temperature');
await this.temperatureChar.startNotifications();
this.temperatureChar.addEventListener(
'characteristicvaluechanged',
this.onTemperatureChange
);
this.reconnectAttempts = 0;
this.emit('connected');
return true;
} catch (error) {
console.error('BLE connect failed:', error);
this.emit('error', error);
return false;
}
}
onHeartRateChange = (event) => {
const value = event.target.value;
const flags = value.getUint8(0);
const hr = flags & 0x01
? value.getUint16(1, true)
: value.getUint8(1);
useHealthStore.getState().updateHardwareData({
heartRate: hr,
timestamp: Date.now()
});
};
onTemperatureChange = (event) => {
const value = event.target.value;
const raw = value.getInt16(0, true);
const temperature = raw / 100;
// 过滤异常值
if (temperature === -127 || temperature === 85) return;
useHealthStore.getState().updateHardwareData({
temperature,
timestamp: Date.now()
});
};
async handleDisconnect() {
this.emit('disconnected');
if (this.reconnectAttempts < 5) {
this.reconnectAttempts++;
const delay = Math.pow(2, this.reconnectAttempts) * 1000;
this.emit('reconnecting', { attempt: this.reconnectAttempts, delay });
setTimeout(() => this.connect(), delay);
}
}
disconnect() {
if (this.device?.gatt?.connected) {
this.device.gatt.disconnect();
}
}
on(event, callback) {
if (!this.listeners.has(event)) this.listeners.set(event, []);
this.listeners.get(event).push(callback);
}
emit(event, data) {
this.listeners.get(event)?.forEach(cb => cb(data));
}
}
export const careBridgeDevice = new CareBridgeDevice();
断线重连采用指数退避策略(2s → 4s → 8s → 16s → 32s),最多重试5次。每次重连都会通过事件通知 UI 层更新连接状态指示器,让用户知道设备正在重连而非失联。
6.3 前端架构设计
Zustand 单一 Store
CareBridge 的前端状态管理采用 Zustand 单一 Store 模式。整个应用的状态集中在一个 store 中,包含190个顶层字段:38个状态字段和152个操作函数。
interface HealthStore {
// ===== 状态字段 (38个) =====
// 用户与家庭
currentUser: UserProfile | null;
householdMembers: HouseholdMemberState[];
currentMemberId: string | null;
appMode: AppMode;
// 健康数据
symptomLogs: SymptomLog[];
vitalSigns: VitalSigns | null;
hardwareData: HardwareData | null;
// 评估与报告
riskAssessments: RiskAssessment[];
examReports: ExamReport[];
// 应用配置
platform: 'web' | 'mobile' | 'tablet';
elderMode: boolean;
isDeviceConnected: boolean;
// ... 其余状态字段
// ===== 操作函数 (152个) =====
// 用户操作
setCurrentUser: (user: UserProfile) => void;
addHouseholdMember: (member: HouseholdMemberState) => void;
removeHouseholdMember: (id: string) => void;
switchMember: (id: string) => void;
// 健康数据操作
addSymptomLog: (log: SymptomLog) => void;
updateVitalSigns: (vitals: VitalSigns) => void;
updateHardwareData: (data: Partial<HardwareData>) => void;
// 评估操作
evaluateRisk: () => RiskAssessment;
addExamReport: (report: ExamReport) => void;
// 配置操作
setAppMode: (mode: AppMode) => void;
toggleElderMode: () => void;
// ... 其余操作函数
}
Store 通过 persist 中间件持久化到 localStorage:
const useHealthStore = create<HealthStore>()(
persist(
(set, get) => ({
// 状态和操作的实现
}),
{
name: 'night-sugar-storage',
version: 3,
migrate: (persistedState: any, version: number) => {
if (version < 2) {
// v1→v2: 添加 appMode 字段
persistedState.appMode = 'general';
}
if (version < 3) {
// v2→v3: 重构 householdMembers 结构
persistedState.householdMembers = persistedState.members?.map(
m => ({ ...m, guardianAccess: [] })
) ?? [];
}
return persistedState;
},
partialize: (state) => ({
// 只持久化必要字段, 排除临时状态
currentUser: state.currentUser,
householdMembers: state.householdMembers,
symptomLogs: state.symptomLogs,
riskAssessments: state.riskAssessments,
examReports: state.examReports,
appMode: state.appMode,
elderMode: state.elderMode,
// isDeviceConnected, platform 等运行时状态不持久化
}),
}
)
);
migrate 函数处理了版本1到版本3的数据结构迁移。每次 Store 结构发生 breaking change 时递增版本号,migrate 函数负责将旧版本数据转换为新版本格式,用户不会因为升级而丢失历史数据。
HouseholdMemberState 多成员机制
interface HouseholdMemberState {
id: string;
role: 'self' | 'spouse' | 'parent' | 'child' | 'grandparent' | 'other';
profile: UserProfile;
appMode: AppMode;
symptomLogs: SymptomLog[];
vitalSigns: VitalSigns[];
hardwareData: HardwareData[];
riskAssessments: RiskAssessment[];
examReports: ExamReport[];
guardianAccess: GuardianModeState[];
createdAt: string;
updatedAt: string;
}
组件通过 selector 订阅当前活跃成员的数据,避免无关成员数据变更触发重渲染:
const useCurrentMember = () => {
return useHealthStore((state) => {
const member = state.householdMembers.find(
m => m.id === state.currentMemberId
);
return member ?? state.householdMembers[0] ?? null;
});
};
// 使用
const currentMember = useCurrentMember();
const heartRate = currentMember?.hardwareData.slice(-1)[0]?.heartRate;
平台适配
通过 VITE_PLATFORM 环境变量区分三平台,构建时注入对应配置:
const platform = import.meta.env.VITE_PLATFORM as 'web' | 'mobile' | 'tablet';
const platformConfig = {
web: { layout: 'responsive', baseFontSize: 16, maxContentWidth: 1280 },
mobile: { layout: 'mobile', baseFontSize: 14, maxContentWidth: '100%' },
tablet: { layout: 'tablet', baseFontSize: 16, maxContentWidth: 1024 },
};
const config = platformConfig[platform];
路由懒加载
70+个页面全部通过 lazyWithRetry 包装,配合 Vite manualChunks 分包:
// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
'vendor-react': ['react', 'react-dom', 'react-router-dom'],
'vendor-charts': ['recharts'],
'vendor-animation': ['framer-motion'],
'vendor-crypto': ['crypto-js'],
'vendor-ocr': ['tesseract.js'],
},
},
},
},
});
6.4 数据模型设计
UserProfile 核心类型
UserProfile 是 CareBridge 最核心的数据类型,包含80+个字段和21个嵌套临床子档案:
interface UserProfile {
// 基础信息 (15字段)
id: string;
name: string;
gender: 'male' | 'female' | 'other';
birthDate: string;
bloodType: BloodType;
height: number;
weight: number;
ethnicity: string;
occupation: string;
phone: string;
emergencyContact: string;
emergencyPhone: string;
avatar: string;
createdAt: string;
updatedAt: string;
// 既往病史 (6字段)
allergies: Allergy[];
chronicDiseases: ChronicDisease[];
surgeries: SurgeryRecord[];
familyHistory: FamilyHistory[];
vaccinations: Vaccination[];
currentMedications: MedicationRecord[];
// 21个嵌套临床子档案 (按需激活)
menstrualHistory?: MenstrualHistory;
pregnancyRecord?: PregnancyRecord;
postpartumRecord?: PostpartumRecord;
contraceptiveUse?: ContraceptiveUse;
fertilityTracking?: FertilityTracking;
menopauseStatus?: MenopauseStatus;
boneDensity?: BoneDensityRecord;
thyroidFunction?: ThyroidRecord;
glucoseMetabolism?: GlucoseRecord;
lipidProfile?: LipidRecord;
bloodPressure?: BPRecord;
cardiovascularRisk?: CardiovascularRecord;
mentalHealth?: MentalHealthRecord;
sleepPattern?: SleepRecord;
nutritionStatus?: NutritionRecord;
physicalActivity?: ActivityRecord;
cancerScreening?: CancerScreeningRecord;
medicationList?: MedicationListRecord;
labResults?: LabResult[];
imagingReports?: ImagingReport[];
geneticMarkers?: GeneticMarker[];
// 元数据
appMode: AppMode;
dataVersion: number;
consentFlags: ConsentFlags;
}
appMode 生命周期模式
type AppMode =
| 'teen' // 青春期: 经期追踪、生长发育
| 'reproductive' // 育龄期: 生育力、避孕管理
| 'pregnancy' // 孕期: 孕周、产检、胎动
| 'postpartum' // 产后: 产后恢复、哺乳
| 'perimenopause' // 围绝经期: 激素水平、骨密度
| 'elderly' // 老年期: 慢病管理、跌倒风险
| 'general'; // 通用: 基础健康监测
每种模式激活不同的子档案和功能模块。例如 pregnancy 模式激活 pregnancyRecord 子档案,首页展示孕周计算器、产检提醒、胎动记录;elderly 模式激活 glucoseMetabolism、bloodPressure、boneDensity 子档案,首页展示慢病监测、用药提醒、跌倒风险评估。
SymptomLog 症状日志
interface SymptomLog {
id: string;
memberId: string;
category: SymptomCategory;
severity: 1 | 2 | 3 | 4 | 5;
onset: 'sudden' | 'gradual' | 'intermittent';
duration: string;
timestamp: string;
notes: string;
triggers: string[];
reliefMeasures: string[];
// 17类子结构 (联合类型, 按类别选择)
details:
| CardiovascularSymptom // 心血管: 胸痛、心悸、放射痛
| RespiratorySymptom // 呼吸: 咳嗽、气促、咳痰
| GastrointestinalSymptom // 消化: 腹痛、恶心、排便异常
| NeurologicalSymptom // 神经: 头痛、头晕、意识障碍
| MusculoskeletalSymptom // 骨骼肌肉: 关节痛、肌力下降
| DermatologicalSymptom // 皮肤: 皮疹、瘙痒
| EndocrineSymptom // 内分泌: 多饮多尿、怕热怕冷
| UrinarySymptom // 泌尿: 尿频尿急、血尿
| GynecologicalSymptom // 妇科: 异常出血、分泌物异常
| PsychiatricSymptom // 精神: 焦虑、抑郁、失眠
| ENTSymptom // 耳鼻喉: 耳鸣、鼻塞、咽痛
| OphthalmicSymptom // 眼科: 视力变化、眼痛
| DentalSymptom // 口腔: 牙痛、牙龈出血
| SleepSymptom // 睡眠: 入睡困难、早醒
| FatigueSymptom // 疲乏: 持续疲乏、活动耐力下降
| PainSymptom // 疼痛: 部位、性质、VAS评分
| GeneralSymptom; // 全身: 发热、体重变化
}
GuardianModeState 家庭数据模型与访问控制
interface GuardianModeState {
guardianId: string;
guardianName: string;
relationship: 'spouse' | 'child' | 'parent' | 'sibling' | 'caregiver' | 'doctor';
accessLevel: 'view' | 'edit' | 'admin';
accessibleModules: string[];
dataVisibility: DataVisibility;
expiresAt?: string;
createdAt: string;
}
interface DataVisibility {
showIdentifiers: boolean; // 姓名、电话等身份信息
showMentalHealth: boolean; // 心理健康记录
showReproductive: boolean; // 生殖健康记录
showGeneticData: boolean; // 基因检测数据
showFinancialInfo: boolean; // 医疗费用信息
showFullHistory: boolean; // 完整病史 (vs 仅近期)
}
监护人可以是被授权的家庭成员或医生。dataVisibility 的6项开关让被照护者精细控制哪些数据对监护人可见——例如,一位老年用户可能愿意让子女看到自己的血压和血糖数据,但不愿意让子女看到心理健康记录。
这种设计在伦理上尊重了被照护者的隐私自主权。传统家庭健康管理中,照护者往往"全权访问"被照护者的所有健康信息,但并非所有信息都适合让家人知道——心理健康问题可能带来家庭关系紧张,生殖健康问题可能涉及个人隐私。CareBridge 的可见性控制让被照护者保持对自身数据的掌控感,这在老年用户群体中尤为重要:他们需要被照护,但同时也需要被尊重。
6.5 AI 风险评估引擎
双轨评估架构
CareBridge 的风险评估引擎采用"规则引擎+AI 分析"双轨架构:
interface RiskAssessment {
id: string;
memberId: string;
timestamp: string;
// 规则引擎输出 (确定性)
ruleEngineResult: {
overallRisk: 'low' | 'moderate' | 'high' | 'critical';
triggeredRules: TriggeredRule[];
redFlags: RedFlag[];
deltaChecks: DeltaCheckResult[];
westgardViolations: WestgardViolation[];
};
// AI 分析输出 (解释性)
aiAnalysis: {
summary: string;
recommendations: string[];
followUpActions: string[];
confidence: number;
};
// 输入数据快照 (可追溯)
inputs: {
vitals: VitalSigns;
symptoms: SymptomLog[];
hardwareData: HardwareData;
labResults?: LabResult[];
};
}
规则引擎的输出是确定性的——同样的输入永远得到同样的结果,不依赖网络和模型可用性。AI 分析模块在规则引擎输出基础上生成自然语言解释,即使 AI 模块不可用,规则引擎仍能独立给出风险等级和触发规则。
规则引擎核心
规则引擎包含四类规则。
1. 红旗征候识别(7条)
const RED_FLAG_RULES: RedFlagRule[] = [
{ id: 'RF001',
check: (v: VitalsSnapshot) => v.heartRate < 40 || v.heartRate > 150,
level: 'critical', message: '心率异常危急值, 建议立即就医' },
{ id: 'RF002',
check: (v: VitalsSnapshot) => v.temperature > 39.5 || v.temperature < 35.0,
level: 'critical', message: '体温异常危急值' },
{ id: 'RF003',
check: (v: VitalsSnapshot) => v.systolicBP > 180 || v.diastolicBP > 120,
level: 'critical', message: '高血压危象, 需紧急处理' },
{ id: 'RF004',
check: (v: VitalsSnapshot) => v.spo2 < 90,
level: 'critical', message: '低氧血症 (SpO2 < 90%)' },
{ id: 'RF005',
check: (_v, s?: SymptomLog[]) => s?.some(x => x.severity >= 4 && x.category === 'cardiovascular') ?? false,
level: 'high', message: '心血管重度症状' },
{ id: 'RF006',
check: (_v, s?: SymptomLog[]) => s?.some(x => x.category === 'neurological' && x.severity >= 4) ?? false,
level: 'high', message: '神经系统红旗症状' },
{ id: 'RF007',
check: (v: VitalsSnapshot) => v.glucose < 3.0 || v.glucose > 22.0,
level: 'critical', message: '血糖危急值' },
];
2. Delta Check(连续监测值异常变化检测)
function deltaCheck(history: VitalsSnapshot[]): DeltaCheckResult[] {
const results: DeltaCheckResult[] = [];
if (history.length < 2) return results;
const current = history[history.length - 1];
const previous = history[history.length - 2];
const checks = [
{ metric: 'heartRate', delta: Math.abs(current.heartRate - previous.heartRate), threshold: 30 },
{ metric: 'temperature', delta: Math.abs(current.temperature - previous.temperature), threshold: 1.5 },
{ metric: 'systolicBP', delta: Math.abs(current.systolicBP - previous.systolicBP), threshold: 30 },
{ metric: 'glucose', delta: Math.abs(current.glucose - previous.glucose), threshold: 5.0 },
];
for (const check of checks) {
if (check.delta > check.threshold) {
results.push({
metric: check.metric,
delta: check.delta,
threshold: check.threshold,
status: 'violation',
message: `${check.metric} 变化幅度 ${check.delta} 超过阈值 ${check.threshold}`,
});
}
}
return results;
}
3. Westgard 多规则质控
function westgardRules(
values: number[], mean: number, sd: number
): WestgardViolation[] {
const violations: WestgardViolation[] = [];
if (values.length < 1) return violations;
const last = values[values.length - 1];
const z = (last - mean) / sd;
// 1-2s 警告
if (Math.abs(z) > 2) {
violations.push({ rule: '1-2s', level: 'warning' });
}
// 1-3s 拒绝
if (Math.abs(z) > 3) {
violations.push({ rule: '1-3s', level: 'reject' });
}
if (values.length >= 2) {
const prev = values[values.length - 2];
const prevZ = (prev - mean) / sd;
// 2-2s 拒绝: 连续2次同侧超出±2SD
if (prevZ > 2 && z > 2) violations.push({ rule: '2-2s', level: 'reject' });
if (prevZ < -2 && z < -2) violations.push({ rule: '2-2s', level: 'reject' });
// R-4s 拒绝: 连续2次Z-score差值超过4
if (Math.abs(z - prevZ) > 4) violations.push({ rule: 'R-4s', level: 'reject' });
}
return violations;
}
Westgard 多规则原本用于临床实验室质控,我们将其引入个人健康数据的连续监测——把用户一段时间的生理指标视为"质控样本",用统计学方法识别异常波动。例如,如果用户的血压连续两天高于均值+2SD,2-2s 规则触发,提示血压控制可能出了问题。
4. 生命周期特异性规则
const LIFECYCLE_RULES: Record<AppMode, LifecycleRule[]> = {
pregnancy: [
{ id: 'P001',
check: (v) => v.glucose > 5.1 && v.glucoseContext === 'fasting',
level: 'moderate', message: '孕期空腹血糖 > 5.1mmol/L, 提示GDM风险' },
{ id: 'P002',
check: (v) => v.systolicBP > 140 || v.diastolicBP > 90,
level: 'high', message: '孕期血压升高, 警惕子痫前期' },
],
elderly: [
{ id: 'E001',
check: (v) => (v.systolicBP - v.diastolicBP) > 60,
level: 'moderate', message: '脉压差 > 60mmHg, 心血管风险升高' },
{ id: 'E002',
check: (v) => v.heartRate < 50,
level: 'moderate', message: '心动过缓, 建议心电检查' },
],
perimenopause: [
{ id: 'M001',
check: (v) => v.boneDensityTScore < -1.0,
level: 'moderate', message: '骨量减少 (T-score < -1.0), 建议补充钙和维D' },
],
// ... 其他模式
};
evaluateRisk 函数
evaluateRisk() 是风险评估引擎的入口函数,约750行代码。执行流程如下:
- 收集当前成员的所有健康数据(生理指标、症状日志、硬件数据、化验结果)
- 依次执行红旗征候识别、Delta Check、Westgard 多规则质控、生命周期特异性规则
- 汇总规则引擎结果,计算综合风险等级
- 将规则引擎输出和原始数据传入 AI 分析模块
- AI 生成自然语言摘要和建议
- 返回完整的 RiskAssessment 对象
ESP32 硬件采集的心率、体温、血氧数据是风险评估的重要输入源。当硬件检测到心率危急值(<40或>150bpm)时,规则引擎立即触发 RF001 红旗规则,AI 分析模块生成"建议立即就医"的紧急建议。目前这些评估结果在应用本地展示和记录;如果用户开启了飞书表格同步,评估结果也会同步到飞书表格中,家庭成员查看表格时可以看到。不过,目前还不支持异常时主动推送通知给远端守护人——这需要搭建云端服务才能实现,是我们后续计划完善的方向。
AI 分析模块的 prompt 设计经过了多轮调优。最初版本的 prompt 是"请根据以下健康数据给出风险评估建议",但 AI 的回复过于笼统,缺乏针对性。后来我们把规则引擎的触发结果也传入 prompt,让 AI 在已知规则触发情况的基础上生成解释——“用户触发了 RF003 高血压危象规则,收缩压185mmHg,请用通俗语言解释这个风险并给出具体建议”。这样 AI 的回复就有了明确的锚点,不再是泛泛而谈。同时,我们在 prompt 中加入了生命周期模式的上下文——同样是空腹血糖6.0mmol/L,对普通成人可能只是偏高,但对孕期女性已经超过5.1mmol/L 的 GDM 阈值,AI 需要结合 appMode 给出不同的解读。
6.6 飞书生态集成
OAuth 认证流程
用户点击"同步到飞书"
↓
跳转飞书授权页面 (open.feishu.cn)
↓ (用户授权)
飞书回调 CareBridge, 携带 authorization_code
↓
前端将 code 发送到代理服务 (localhost:3001/api/feishu/token)
↓
代理服务用 code + app_secret 换取 access_token
↓
代理服务返回 access_token 给前端 (app_secret 不暴露)
↓
前端用 access_token 通过代理服务调用飞书 API
表格双向同步
class FeishuSync {
private accessToken: string | null = null;
private appToken: string;
private tableId: string;
async syncToFeishu(memberId: string): Promise<void> {
const member = useHealthStore.getState().householdMembers
.find(m => m.id === memberId);
if (!member) return;
const records = this.transformToFeishuRecords(member);
await fetch('/api/feishu/sync', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
token: this.accessToken,
appToken: this.appToken,
tableId: this.tableId,
records,
}),
});
}
async syncFromFeishu(memberId: string): Promise<void> {
const response = await fetch(
`/api/feishu/records?tableId=${this.tableId}&filter=memberId="${memberId}"`
);
const records = await response.json();
const localData = this.transformFromFeishuRecords(records);
useHealthStore.getState().mergeFromFeishu(localData);
}
private transformToFeishuRecords(member: HouseholdMemberState) {
return member.symptomLogs.map(log => ({
fields: {
'姓名': member.profile.name,
'症状类别': log.category,
'严重程度': log.severity,
'记录时间': log.timestamp,
'备注': log.notes,
},
}));
}
}
代理服务与密钥隔离
代理服务 proxy.js 运行在端口3001,承担两个职责:解决浏览器跨域限制(飞书 API 不支持 CORS),以及隔离密钥(FEISHU_APP_SECRET 只存在于服务器环境变量中,前端永远无法接触)。
require('dotenv').config();
const express = require('express');
const axios = require('axios');
const cors = require('cors');
const app = express();
app.use(cors({ origin: process.env.ALLOWED_ORIGIN }));
app.use(express.json());
const FEISHU_APP_ID = process.env.FEISHU_APP_ID;
const FEISHU_APP_SECRET = process.env.FEISHU_APP_SECRET;
// Token 交换: 密钥在此使用, 永不暴露给前端
app.post('/api/feishu/token', async (req, res) => {
try {
const response = await axios.post(
'https://open.feishu.cn/open-apis/authen/v1/oidc/access_token',
{
grant_type: 'authorization_code',
code: req.body.code,
app_id: FEISHU_APP_ID,
app_secret: FEISHU_APP_SECRET,
}
);
res.json(response.data);
} catch (error) {
res.status(500).json({ error: 'Token exchange failed' });
}
});
// 通用飞书API代理: 前端传 token, 代理转发请求
app.post('/api/feishu/:path(*)', async (req, res) => {
try {
const response = await axios({
method: 'POST',
url: `https://open.feishu.cn/open-apis/${req.params.path}`,
headers: {
Authorization: req.headers.authorization,
'Content-Type': 'application/json',
},
data: req.body,
});
res.json(response.data);
} catch (error) {
res.status(error.response?.status || 500).json(error.response?.data || { error: 'Unknown' });
}
});
app.listen(3001, () => console.log('Feishu proxy on :3001'));
ALLOWED_ORIGIN 环境变量限制只有 CareBridge 前端域名可以访问代理服务,防止代理被滥用。
6.7 安全与隐私
传输加密
CareBridge 的数据传输有三层加密保护:
- TLS 1.3:前端与代理服务之间、代理服务与飞书 API 之间均使用 TLS 1.3 加密传输
- BLE 加密层:ESP32 与手机之间的 BLE 连接使用 LE Secure Connections 配对,数据传输经过 AES-CCM 加密
- 本地蓝牙传输:ESP32 数据通过蓝牙直传手机,不经过互联网,从物理层面隔离网络风险
存储加密
本地存储的健康数据使用 AES-GCM 256位加密,密钥通过 PBKDF2 从用户密码派生:
import CryptoJS from 'crypto-js';
const SALT_KEY = 'carebridge_salt'; // 盐值存储在 localStorage
function getSalt(): string {
let salt = localStorage.getItem(SALT_KEY);
if (!salt) {
salt = CryptoJS.lib.WordArray.random(16).toString();
localStorage.setItem(SALT_KEY, salt);
}
return salt;
}
function deriveKey(password: string): string {
return CryptoJS.PBKDF2(password, getSalt(), {
keySize: 256 / 32,
iterations: 100000,
}).toString();
}
function encryptData(data: object, password: string): string {
const key = deriveKey(password);
const json = JSON.stringify(data);
const iv = CryptoJS.lib.WordArray.random(12);
const encrypted = CryptoJS.AES.encrypt(json, key, {
iv,
mode: CryptoJS.mode.GCM,
padding: CryptoJS.pad.NoPadding,
});
return iv.toString(CryptoJS.enc.Hex) + ':' + encrypted.toString();
}
function decryptData(ciphertext: string, password: string): object {
const key = deriveKey(password);
const [ivHex, encrypted] = ciphertext.split(':');
const iv = CryptoJS.enc.Hex.parse(ivHex);
const decrypted = CryptoJS.AES.decrypt(encrypted, key, {
iv,
mode: CryptoJS.mode.GCM,
padding: CryptoJS.pad.NoPadding,
});
return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8));
}
PBKDF2 的100,000次迭代使暴力破解在计算上不可行。AES-GCM 模式同时提供加密和完整性校验,任何对密文的篡改都会在解密时被检测到。
隐私保护
CareBridge 的隐私保护体系包含6项可见性控制和三级数据脱敏策略。
6项可见性控制(通过 GuardianModeState.dataVisibility 配置):
showIdentifiers— 是否显示姓名、电话等身份信息showMentalHealth— 是否显示心理健康记录showReproductive— 是否显示生殖健康记录showGeneticData— 是否显示基因检测数据showFinancialInfo— 是否显示医疗费用信息showFullHistory— 是否显示完整病史(vs 仅近期30天)
三级数据脱敏策略:
| 级别 | 适用场景 | 脱敏方式 | 示例 |
|---|---|---|---|
| L1 | 家庭成员间共享 | 隐藏敏感字段, 保留概要 | 心理健康记录仅显示"有记录" |
| L2 | 飞书表格同步 | 部分字段脱敏 | 张某某 / 138****1234 |
| L3 | AI 分析输入 | 完全匿名化 | 移除所有身份标识符 |
ESP32 硬件数据通过蓝牙本地传输,不经过互联网,从物理层面保证了生理数据的隐私安全。这一点在老年用户场景中尤为重要——老年人对"数据上传到云端"普遍存在顾虑,而 BLE 本地传输让他们知道"数据只在我的手机上",消除了隐私焦虑。
除了技术层面的加密和脱敏,CareBridge 在产品设计层面也贯彻了"最小必要"原则:只采集与健康管理直接相关的数据,不采集位置信息、通讯录、社交媒体账号等无关数据;只在使用对应功能时请求对应权限,不一次性索取全部权限;用户可以随时导出全部数据为本地文件,也可以一键删除所有本地存储的数据,不留痕迹。这些设计让用户对"我的数据我做主"有切实的感知,而非仅仅依赖隐私政策的承诺。
6.8 部署与运维
Vercel 部署
CareBridge 前端部署在 Vercel 上:
{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"framework": "vite",
"rewrites": [
{ "source": "/api/:path*", "destination": "http://localhost:3001/:path*" }
],
"headers": [
{
"source": "/sw.js",
"headers": [
{ "key": "Cache-Control", "value": "no-cache" }
]
}
]
}
Service Worker 文件(sw.js)设置 no-cache 头,避免浏览器缓存旧版 SW 导致更新无法生效。API 请求通过 rewrite 规则转发到本地3001端口的代理服务。
PWA 离线支持
通过 vite-plugin-pwa 配置 Service Worker,应用在离线状态下仍可访问已加载的页面和数据。缓存策略已在第五部分步骤六中详述——HTML 使用 NetworkFirst、JS/CSS 使用 StaleWhileRevalidate、图片使用 CacheFirst,三者配合实现了离线可用与数据新鲜度的平衡。
ESP32 硬件组装指南
材料清单:
| 元件 | 型号 | 数量 | 参考价格 |
|---|---|---|---|
| 主控板 | ESP32 (ESP-WROOM-32) | 1 | ~15元 |
| 心率传感器 | MAX30102 模块 | 1 | ~12元 |
| 温度传感器 | DS18B20 防水型 | 1 | ~19元 |
| 上拉电阻 | 4.7kΩ | 1 | ~0.1元 |
| 杜邦线 | 母对母 | 8根 | ~1元 |
| 3D打印外壳 | — | 1 | 可选 |
组装步骤:
- MAX30102 接线:SDA→GPIO21,SCL→GPIO22,VDD→3.3V,GND→GND
- DS18B20 接线:DATA→GPIO4,VDD→3.3V,GND→GND
- 在 DS18B20 的 DATA 和 VDD 之间焊接4.7kΩ 上拉电阻
- 将全部元件装入3D打印外壳,露出 MAX30102 传感器窗口和 DS18B20 探头
固件烧录:
- 安装 Arduino IDE 和 ESP32 板级支持包(Board Manager 搜索 “esp32”)
- 安装依赖库:MAX30105(兼容 MAX30102)、OneWire、DallasTemperature、ESP32 BLE Arduino
- 打开
CareBridge_Firmware.ino,选择开发板 “ESP32 Dev Module” 和正确端口 - 点击上传,等待编译和烧录完成
- 烧录完成后,ESP32 自动开始 BLE 广播,设备名称为 “CareBridge-001”
在手机浏览器(Chrome 或 Edge)中打开 CareBridge PWA,点击"连接设备",在弹出的蓝牙设备选择器中选择 “CareBridge-001”,即可开始使用。将手指轻放在 MAX30102 传感器窗口上,心率和体温数据会实时显示在界面上,同时自动写入健康档案并触发风险评估引擎。
整个硬件方案的总成本不超过30元,组装时间约15分钟,固件烧录约5分钟。这个成本和时间门槛让普通家庭也能 DIY 一台 CareBridge 健康终端,而不需要购买昂贵的商业健康设备。我们正在设计一款3D打印外壳的 STL 文件,完成后将开源到项目仓库,让用户可以直接打印外壳、组装电路、烧录固件,获得一个完整的硬件产品。
从产品闭环的角度看,CareBridge 的部署方案体现了"软件即服务、硬件即工具"的理念:软件通过 Vercel 全球 CDN 分发,用户打开浏览器即用,无需安装;硬件通过开源设计和低成本元件,让用户以极低的门槛获得数据采集能力。两者通过 Web Bluetooth API 在浏览器中无缝连接,不需要额外的 App、驱动或配对流程。
七、社会价值分析
CareBridge 想要回答的问题很朴素:当一个人最需要被看见的时候,技术能不能真正看见她。市面上的健康产品大多服务于那些已经会主动管理健康的人——年轻、懂技术、住在大城市、有医保。而我们把目光投向四个长期被主流健康叙事边缘化的群体:女性、老人、照护者,以及生活在医疗资源边缘的人。每一组数字背后,都是真实而具体的困境,也是技术本该抵达却迟迟没有抵达的地方。
7.1 社会问题:被折叠的健康角落
38亿女性的健康沉默
很长一段时间,医学研究的样本里几乎没有女性。1977年,美国FDA发布指导原则,要求将"育龄女性"排除在早期临床试验之外,本意是保护可能怀孕的女性与胎儿,结果却让整整一代药物缺乏针对女性的安全与剂量数据。一种药物只要在男性身上验证有效,就被默认对所有人有效——而女性的体重、激素水平、代谢酶活性都与男性不同,这种"默认"悄然造成了大量未被记录的伤害。直到1993年NIH振兴法案出台,才在政策层面要求将女性纳入临床研究。中间这十六年的空白,至今仍在影响女性的用药安全。
安必恩(Ambien)就是最刺眼的例证。这款广泛使用的安眠药上市二十多年后,FDA才发现女性代谢该药的速度远慢于男性,相同剂量下,女性第二天血液中药物残留浓度几乎是男性的两倍,极易引发清晨驾车事故。直到2013年,FDA才被迫专门下调女性推荐剂量——而在此之前,无数女性一直按"男性标准"服药,却没有人告诉她们这并不安全。类似的故事不止一例:女性心梗发作时常表现为背痛、恶心、极度疲惫,而非教科书上那种典型的胸痛,于是被误诊、被延误的案例屡见不鲜。一种药、一种症状的标准,长期是以男性身体为模板写就的。
数字健康领域同样存在性别鸿沟。femtech长期被视作小众赛道,融资占比长期低于3%,女性专属的健康数据集严重匮乏。月经周期、孕期变化、更年期波动这些伴随女性大半生的生理过程,在主流健康应用里往往只是几个简陋的选项,缺乏连续追踪与智能解读。女性的身体长期被当作"男性的缩小版"来对待,那些独属于女性的生理节律,得不到与之相称的研究投入与工具支持。38亿女性,占全球人口近一半,她们的健康需求长期处于沉默之中——并非没有需求,而是没有人认真倾听,没有人系统记录,也没有人把她们当作健康服务的核心对象。
这种沉默的代价,最终由每一个普通女性独自承担。她不知道自己正在吃的药有没有针对女性做过充分试验,不知道自己那些"不典型"的症状会不会被医生当成"太紧张"打发掉,更不知道自己的月经周期、孕期反应、更年期波动里藏着多少本可以被早期识别的健康信号。被排除在研究之外,意味着被排除在"被了解"之外——而一个不被了解的身体,只能靠运气和忍耐去应对每一次异常。
银发群体的数字孤独
截至2024年末,我国60岁以上人口已达3.1亿。这个庞大数字的另一面,是约1.6亿空巢老人和1.3亿独居老人。他们中的许多人,子女远在他乡,一日三餐无人过问,一次摔倒可能要在地上躺一整夜才被发现。比身体衰老更难熬的,是那种"被世界抛下"的孤独感——智能电视不会用,挂号软件弄不明白,视频通话要等孩子周末远程指导,连买一次菜都可能因为不会用手机支付而寸步难行。
更残酷的是数字鸿沟的城乡落差。农村地区智能设备持有率不足15%,许多老人连一部能上网的智能手机都没有。当城里的同龄人已经开始用健康手环记录步数、用App预约体检时,偏远乡村的老人连测一次血压都要走上几公里去乡镇卫生院,而那个卫生院可能一周只有半天有医生值班。健康监测这件事,对他们来说早已不是"方不方便"的问题,而是"有没有"的问题。慢病管理更是奢谈——高血压、糖尿病这些需要长期监测的疾病,在没有数据记录的情况下,只能靠老人模糊的记忆和"感觉还行"的判断,往往等到中风、昏迷才被送进医院。
数字背后是触目惊心的现实:跌倒已成为我国65岁以上老人因伤死亡的首因,而一次髋部骨折,往往就是一位老人从独立生活走向长期卧床的转折点。如果摔倒的那一刻能有一台设备自动报警,如果血压连续偏高时能有人被告知,很多悲剧本可以止步于"虚惊一场"。可现实是,这些老人手里什么都没有,他们只能独自面对身体的每一个不确定。
家庭照护者的系统性压力
照护者是被低估的"第二患者"。全球每年产生约164亿小时的无偿照料劳动,其中76.2%由女性承担。这意味着无数女儿、妻子、母亲,在工作和育儿之外,还要扛起照护老人的重担,成为被三重角色撕扯的"三明治一代"。长期的身心透支会留下实实在在的生理痕迹:研究发现,长期高负荷照护者的端粒比同龄人缩短约12%——这意味着他们在细胞层面老得更快;心血管疾病风险是普通人的2.3倍。她们照顾别人,却没有人照顾她们。
照护的焦虑往往不是某一件大事,而是无数个不确定瞬间累积的重压:老人今天吃药了吗,血压是不是又高了,上次头晕是什么时候,夜里会不会起来摔跤。这些疑问本可以靠数据回答,却因为缺乏顺手的工具,变成了日复一日压在心头的隐忧。电话里一句"我没事",往往是为了不让孩子担心而说的谎;而电话那头的子女,明知可能是谎,也只能无奈地信。照护的成本不止是金钱,更是这种永无止境的悬心——它消耗的不是某一个下午,而是年复一年的心力。
更隐蔽的代价是机会成本。为了照护老人,无数女性不得不减少工作时长、放弃晋升、甚至退出职场,这种牺牲不会出现在任何一张医疗账单上,却实实在在地折损着她们的经济独立与人生可能性。照护本该是一种爱的表达,却在缺乏工具和制度支撑的情况下,变成了一场漫长的自我消耗。
低资源地区的健康不平等
在世界更大的尺度上,健康不平等更加触目惊心。全球仍有8.31亿人生活在极端贫困之中,46亿人无法获得基本医疗服务。低收入国家的人均卫生支出仅17美元——这个数字甚至不够一次普通的门诊挂号,却要覆盖一个人整整一年的健康需求。在那些地方,一次可预防的感染、一次未被及时发现的高血压、一次无人陪伴的难产,都可能演变成无法挽回的悲剧。孕产妇死亡率在低收入国家是高收入国家的数十倍,而这些死亡大多本可以靠最基本的监测和及时转诊避免。
健康资源的稀缺,本质上是"看见"的稀缺:没有监测设备,就没有早期数据;没有早期数据,就没有及时干预;没有及时干预,小病就拖成大病。当城市里的人已经习惯用智能设备管理睡眠和心率时,偏远地区的人连最基础的生理指标都无从知晓。资源的鸿沟,最终折叠成生命的鸿沟——而填补它的第一步,未必是建一座医院,有时只是让一个家庭拥有一台能测心率和血压的便宜设备。
更深的不平等在于,贫困往往和地理偏远、信息闭塞叠加在一起。偏远地区的家庭不只缺医生、缺设备,还缺一个能持续提醒他们"该关注什么"的声音。城市居民稍有不适就能上网查、挂号、问诊,而山乡里的人常常连"这个症状要不要紧"都无从判断。CareBridge想做的,是把那个提醒的声音、那份判断的能力,前置到每一台50元的终端里——哪怕最近的诊所在三十公里外,健康关照也不必再等三十公里。
7.2 CareBridge 的解决方案
面对这些困境,CareBridge 没有去做一个又一个孤立的功能,而是围绕"让每个人都被健康系统看见"这个核心,搭起一套低门槛、全周期、可协同的体系。
低门槛接入。 我们用一颗50元的ESP32芯片做硬件终端,老人不需要学任何操作——按下按钮、把手指放上去,数据就采好了。对不会用智能手机的群体,尽量少的交互就是尽量多的善意。他们不必理解什么是蓝牙、什么是云端,只需要知道:按一下,有人就能看到你的数据。
全生命周期覆盖。 CareBridge 设计了七种健康模式,覆盖经期、孕期、产后、更年期、日常慢病管理、银发看护、家庭协同。从青春期第一次月经,到孕期每一次产检,到更年期的潮热与情绪波动,到暮年慢病的日常管理,一个人的健康需求在同一个体系里延续,而不必在不同应用之间反复迁徙、反复填写、反复丢失历史。
家庭协同守护。 我们构建了多级守护体系:个人自查、家人远程关注、异常自动预警逐级上报。远在异乡的子女,能随时看到父母的健康曲线;一句"今天血压正常",胜过十通电话里的反复追问。当数据异常时,系统会按风险等级通知对应的家人,让该知道的人第一时间知道,而不必等到事后才追悔。
AI双轨评估。 CareBridge 的风险引擎同时读取两条数据流:用户在Web端的问卷与日志,以及ESP32实时回传的生理指标(心率、体温、血氧)。两条线索交叉印证,让预警更早、更准,也更有依据。单凭主观感受容易漏判,单凭一次测量又容易误判,双轨交叉才能把"好像不太对"变成"确实需要关注"。
数据主权回归。 所有健康数据端到端加密,密钥掌握在用户自己手里。健康记录是私密的,不该成为平台牟利的原料。谁能看到你的数据,由你说了算。
低成本硬件。 50元的ESP32终端,把"有设备能测"这件看似寻常的事,变成偏远地区家庭也负担得起的现实。它不追求炫技,只追求一件事:让人买得起、用得上。
这六条不是各自为政的功能清单,而是一条环环相扣的链:低门槛让人进得来,全周期让人留得下,家庭协同让人不孤单,AI双轨让人被读懂,数据主权让人敢托付,低成本让最远的人也够得着。少任何一环,"被看见"都会断在半路上。CareBridge想做的,是让这条链从城市一直铺到山乡,从年轻女性一直延续到暮年老人。
7.3 社会影响力评估:当100万人被看见
如果 CareBridge 覆盖100万用户,我们预期会带来这些改变:50万女性第一次建立起连续的健康记录习惯,月经、孕期、更年期不再是被遗忘的空白,她们开始拥有属于自己的、可追溯的健康档案;30万家庭获得远程协同能力,异乡的牵挂变成可视的数据,父母的状态不再只靠一通电话去猜;20万银发群体拿到低门槛的数字健康工具,其中相当一部分通过ESP32终端第一次拥有了自己的生理指标监测能力,从"被数字时代遗忘"变成"被健康系统接住";约5万例潜在健康风险被提前识别,在演变成危机之前拉响警报——一次未被忽视的血压飙升、一段异常的心率波动,可能就避免了一次中风;10万照护者获得趁手的工具支持,从日复一日的焦虑中喘一口气,把悬着的心放回肚子里。
这些数字背后,是一个个具体的人:是终于不用每次都靠回忆向医生描述病情的女儿,是半夜看到父母心率正常后能安心入睡的远嫁姑娘,是第一次在屏幕上看到自己心跳曲线而惊讶得合不拢嘴的独居老人,是终于不用在工作和照护之间疲于奔命的中年母亲。100万用户不是终点,而是一种证明:当技术愿意俯下身,它真的能托住很多人。
这还只是直接受益者的画像。每一个被看见的人,背后都连着一个被松绑的家庭:一位不再需要每周驱车两小时回家查看父母的子女,一对终于能互相提醒按时吃药的老夫妻,一个把母亲更年期数据带去诊室、让医生第一次有据可依的女儿。少一次急诊,就少一笔可能压垮普通家庭的医药费;早一次预警,就多一个还能陪伴家人很多年的明天。我们算的不只是覆盖人数,而是一张张被重新接住的、本可能坠落的生活。
更长远地看,这100万用户沉淀下的,不只是数字,而是一片以往从未被认真收集过的健康图景——尤其是女性的、老人的、偏远地区的。当这些长期沉默的数据第一次被系统记录,它们就有机会反过来滋养医学研究、反哺公共卫生决策,让未来的健康标准不再只依据一半的人口来制定。一个产品的社会价值,不止于它直接服务了多少人,还在于它点亮了多少曾经看不见的角落。
7.4 社会服务与造种新体验的融合
CareBridge 想造的不只是一个产品,而是四种被重新定义的体验。
造健康新体验: 从被动就医,到自动感知,到智能预警,再到及时干预。健康不再是你病了才去医院的那一瞬间,而是被持续温柔注视的每一天。身体的变化在被你察觉之前,就已经有人替你记下了。
造家庭新体验: 从电话里说不清的焦虑,到一目了然的数据可视,到风险可控的安心,再到协同可及的默契。牵挂不再依赖一句"我没事",而是落在一条平稳的心率曲线上。爱不再只是嘴上说说,而是变成了可以看见、可以托付的日常。
造低资源新体验: 从医疗资源匮乏,到AI能力前置,到50元硬件尝试,到逐步可及。基础健康监测不应该只是城市的特权,山乡里的家庭也值得拥有一台属于自己的测量设备——哪怕它还很粗糙。
造代际新体验: 从对技术的恐惧,到简单交互硬件的接纳,到按一下就能测的信任,再到代际协同的温暖。让最不懂技术的人,也能被技术照顾到,让两代人因为同一份健康数据而靠得更近。
四种体验叠加在一起,指向同一个方向:让健康从一种"出事了才想起"的稀缺资源,变成一种"始终在场"的日常底色。当感知变得自动、数据变得可视、协同变得顺手、门槛低到人人可及,健康就不再是少数人的特权,而是一张兜住每个家庭的网。
7.5 ESP32 硬件的社会意义
这颗50元的芯片,是我们在这个项目里做得最"笨"的一件事——也是我们觉得最值得继续做下去的方向。
它背后的想法很简单:偏远地区一个普通家庭,花一顿饭的钱,就能拥有基础生理指标的监测能力——心率、体温、血氧。这些在城市医院里习以为常的检查,对很多家庭来说并不容易获得。我们不敢说这颗芯片已经改变了什么,但它至少让我们看到了一种可能性。
零交互的设计思路——老人不需要学任何操作,按下按钮就好——是我们觉得方向对的地方。技术主动走向人,而不是要求人去适应技术,这个顺序调过来,意义确实不同。当然,目前这套硬件还只是原型,能不能真正走进山乡、走进普通家庭,取决于后续能不能把稳定性打磨到位。
基于标准的 BLE 协议,这颗终端理论上可以兼容更多健康设备:血糖仪、血压计、体脂秤。它不是一次性的孤岛,而是一个可以生长的入口——当然,"理论上可以"和"实际做到"之间还有很长的路。50元的成本换来的是一个值得继续探索的方向,而不是一个已经验证的结论。
放在更大的图景里看,这颗芯片回答的是一个被讨论了很多年的问题:普惠健康到底卡在哪里。答案往往不是技术不够先进,而是先进的技术太贵、太难用,够不到那些最需要它的人。ESP32 用50元和简单的交互,在这个方向上迈了一小步。它也证明了一件事——几个普通人借助 AI,现在就能动手做出一个雏形,哪怕它还很粗糙。
八、产品迭代规划
CareBridge 不会停在这一版。我们把后续的路分成三段:先把眼前的体验做扎实,再把能力扩散到更多家庭,最后向更大的社会基础设施靠近。每一步都不是为了堆功能,而是为了让"被看见"这件事走得更远、更深。规划不是空想,每一阶段我们都设定了可验证的目标和对应的资源投入:短期靠打磨体验留住第一批真实用户,中期靠套件化和生态集成把覆盖面铺开,长期则要把CareBridge沉淀的数据和能力开放出去,成为更大健康网络里的一环。下面分别细说。
8.1 短期规划:复赛结束后1-3个月
移动端落地。 当前版本跑在Web上,但老人的子女、出门在外的家人,最自然的入口是手机。我们会用1-3个月时间交付iOS与Android原生应用,把核心的健康看板、家庭协同、风险预警搬上移动端,让"随时看一眼父母的状态"变成地铁上、午休里随手就能完成的动作。推送通知会优先打通,异常心率、漏服药、长时间无数据这些情况,能在第一时间震动子女口袋里的手机。我们也会针对老年用户做大字号、高对比度、语音播报等无障碍优化,并支持离线缓存最近一次健康快照,让网络不稳的偏远地区也能查看家人的基本状态。
ESP32硬件优化。 现在的终端能测心率和体温,但这远远不够。我们计划增加MAX30102的SpO2血氧监测能力,对老年人尤其关键——夜间血氧骤降往往是睡眠呼吸暂停的信号,而这是心脑血管事件的隐形前兆。同时加入MPU6050六轴传感器做计步与跌倒检测,老人最怕的"摔了没人知道"将获得第一时间的自动告警:一次异常的加速度变化触发判断,确认跌倒后立即向家人推送求助。外壳方面,我们会用3D打印定制贴合手腕的佩戴形态,兼顾舒适与耐用,让这颗50元的终端既便宜又体面,老人愿意天天戴着它。功耗上我们会优化休眠唤醒策略,让一次充电撑过整周,并设计磁吸充电底座,让"充电"也变成无需理解的零交互动作。
AI健康助手。 我们会接入大语言模型,让CareBridge拥有一个能对话的健康助手。用户可以用自然语言提问——“我这个月的经期比上个月推迟了五天,正常吗”“爸爸今天血压偏高,要不要紧”——得到结合其个人健康数据的、有依据的解答,而不是冷冰冰的搜索结果。助手会读取该用户的历史曲线给出个性化判断,并在必要时建议就医,把"我该不该担心"这种最常见却最难回答的疑问,变成一个有人陪你一起想清楚的瞬间。所有对话都基于用户自己的加密数据,不会拿来训练模型,隐私边界和Web端一样严格;它还会在检测到连续异常趋势时主动开口提醒,像一个既懂行又守口如瓶的家庭健康顾问。
远程医疗对接。 当AI评估发现需要专业介入时,CareBridge会提供一键连接在线医生的通道,把"发现问题"和"解决问题"之间的断层补上。医生一侧能直接调阅用户授权的连续健康数据,让一次线上问诊不再是"从零开始描述病情",而是建立在真实数据之上的高效沟通。这样从"自动感知—智能预警—AI初判—医生介入"就形成了一条完整的闭环,每一个环节都有数据支撑,每一次转诊都不必从零开始。
这四件事指向同一个目标:让CareBridge从"能用"变成"好用、离不开"。移动端让人随时随地在线,硬件升级让监测更全面、更安全,AI助手让健康知识不再高高在上,远程医疗让发现问题之后立刻有人接得住。我们希望复赛结束后的第一个季度,用户就能明显感到——这不是一个做完就丢的参赛作品,而是一个会持续生长、持续回应他们需求的产品。
8.2 中期规划:3-6个月
ESP32硬件套件化。 我们会把硬件做成标准化套件,配套图文与视频DIY教程,让有动手能力的社区、学校、志愿者都能自己组装、部署一台CareBridge终端。元器件清单、接线图、烧录步骤全部开源,把复制的门槛降到最低。当硬件可以像积木一样被复制,“看见"的能力就能以更低的成本扩散到更远的地方,一个志愿者小组就能为整个村子搭起健康监测网。我们还会配套一套低成本的"乡村部署手册”,把采购渠道、常见故障排查、志愿者培训流程都写清楚,让哪怕只有初中文化的热心人,也能照着把一台健康站搭起来。
多设备组网。 一个家庭往往不止一位老人。我们支持一个家庭部署多台终端,各自独立采集、统一汇聚到家庭健康看板。爷爷的心率、奶奶的体温、妈妈的经期,在同一张图上和谐共存,每个家庭成员的健康状态一目了然,异常也能定向通知到对应的照护者,而不必所有人同时被惊动。不同终端之间还能互为参照:当奶奶的体温和爷爷的心率同时出现异常,系统会结合环境因素综合判断,避免单一指标的误报打扰全家。
飞书生态深度集成。 CareBridge的健康数据将打通飞书文档、日历与即时通讯:用药提醒写进飞书日历,到点自动提醒;异常预警通过飞书消息推送给家庭成员,附带数据快照与建议;健康报告沉淀进飞书文档形成长期档案,复诊时一键分享给医生。对已经习惯飞书协同的团队和家庭,这是迁移成本最低的健康接入方式,不用再学一套新的工具。对于照料分散在多地的家庭,飞书群里的健康播报还能自动生成每周摘要,让每个牵挂的人都能在群聊里一眼掌握老人这一周过得怎么样。
多语言版本。 健康不分国界,女性与老人的困境也不分国界。我们会陆续推出英语、日语、西班牙语版本,让CareBridge照顾到更多语言背景下的家庭。女性健康数据的全球性空白,需要全球范围的工具一起去补。不同语言版本不只是翻译界面,还会适配当地的健康习惯、常见疾病谱和就医流程,让CareBridge在每个文化语境里都说"本地话"。
中期阶段的重心,是把"一个家庭一台设备"拓展成"一个社区一张网"。套件化让硬件可以低成本自我复制,多设备组网让一个家庭的所有成员都被纳入照护视野,飞书集成让健康协同嵌入已有的工作习惯,多语言则让这套能力跨越国界。我们相信,真正普惠的健康工具,应当像水电一样,平常到让人忘了它的存在,却又随时在那里。
8.3 长期愿景:成为健康基础设施的一部分
开放平台。 我们会开放API接口,让第三方应用、研究机构、公益组织都能接入CareBridge的健康数据能力(在用户授权前提下)。一个产品的力量有限,一个生态的力量无穷。我们希望CareBridge长成一片土壤,而不是一座孤岛,尤其欢迎公益组织接入,把这份能力带到它们已经在服务的弱势群体身边,让技术真正流向最需要它的地方。
医疗数据互联。 长期来看,CareBridge会与医院HIS系统对接,让用户在家积累的连续健康数据,能成为医生诊断的有效参考,从"自家用"走向"医患共用"。当医生看到的不只是诊室里那一次测量,而是过去三个月的完整曲线,诊断的精度和速度都会上一个台阶。反过来,医生的诊断结论也能回流到CareBridge,让用户的健康档案越来越完整,形成一个越用越懂你的个人健康知识库。
全球女性健康数据网络。 在严格保护隐私的前提下,CareBridge希望汇聚脱敏的女性健康数据,补上那块缺失了三十多年的数据空白,为女性专属的医学研究提供底层燃料。让未来的药物、未来的诊疗标准,不再以"男性身体"为唯一模板。我们也会与研究机构合作,把脱敏数据用于女性高发疾病的早期识别模型训练,让数据不只是躺着的记录,而是能反过来拯救更多人的活资产。
ESP32社区健康站。 我们设想在偏远乡村、社区活动中心部署标准化的ESP32健康站,由志愿者运营,让没有智能手机、没有家庭的孤寡老人也能定期获得基础生理指标监测。技术走到最远的角落,才配得上"普惠"二字——我们不想只服务那些已经被服务得很好的人。每个健康站还会成为当地一个小型的健康科普据点,志愿者在为老人测量之余,也能普及慢病管理常识,让一次测量延伸出长期的健康意识。
这些愿景看起来遥远,但每一步都扎根于眼前的这一版。从一颗50元的芯片开始,到一张覆盖家庭的健康网,再到一个连通医院、连通研究、连通偏远角落的基础设施——CareBridge想走的,是一条把"被看见"从特权变成默认的路。技术最大的善意,是让最没有话语权的人,也能被同样认真地对待。
九、关于这段开发旅程——一些真实的感受
写到这儿,我想暂时放下产品文档的腔调,和大家聊聊这段开发旅程里一些真实的感受。因为说到底,CareBridge能走到今天,离不开一个让我们整个团队都没想到的帮手——TRAE的Work。trae的work是真的好用,这句话不是我替它打广告,而是一路踩过来、用过来之后,发自内心的体会。我至今记得第一次打开它的那个下午,半信半疑地丢进去一段需求,看着它一步步把想法变成代码,那种感觉像是在一间黑屋子里突然被人开了灯。下面这些,就是那盏灯亮起来之后,我们一路走来的真实记录。
9.1 最初的疑虑
决定参赛的时候,我们团队里其实是有分歧的。有人担心:用AI生成代码,质量靠不靠谱,万一埋了坑,复赛现场翻车怎么办。也有人担心更深层的问题:长期依赖AI写代码,我们自己的技术能力会不会退化,是不是以后离了AI就什么都写不出来了。这些顾虑很真实,我也一度犹豫过——毕竟往代码库里塞一堆自己看不懂的东西,心里是不踏实的。
真正用TRAE Work跑起来之后,这些疑虑一点点消散了。它陪你一起思考,每一步都摊开在你面前,让你审、让你改、让你真正掌握。你看得见它生成的每一行代码,也能随时追问"这里为什么这么写",它会把思路讲给你听。用着用着你会发现,担心的不再是"能力会不会退化",而是"原来我还能做到这些"——它没有替你成长,反而把你推到了一个你以前够不着的高度。另一个让我放下心的细节是:它生成的代码是可读、可改、可追责的,不是一团黑箱,你看得到每一行在做什么,出了问题能定位、能修复、能学到东西。你依然在思考、在判断、在成长,只是有了一个不知疲倦的搭档替你分担了那些最枯燥的部分。
我还记得有一次,团队里最反对用AI的小伙伴,盯着TRAE生成的一段他原本要写一整天的逻辑,沉默了半天,然后说了一句"好像……还真挺靠谱的"。从那天起,争论就慢慢变成了默契。
9.2 ESP32:从零基础到可运行原型
CareBridge里最让我意外的一段经历,是ESP32硬件开发。
我们团队没有一个人有嵌入式开发经验。按传统路子,光是入门就要先啃ESP32的数据手册,再学Arduino的API,再翻各种传感器的datasheet,还要搞懂BLE协议规范怎么配服务、怎么写特征值、怎么处理连接中断。保守估计,这一套下来一到两周起步,而且大概率会卡在某个通信时序的细节上反复调试,半天调不通一个数据包。对我们这种比赛周期紧、人手又少的小团队来说,光是这道入门关,就足以让硬件这块直接流产。
但在TRAE IDE里,这件事变成了另一副模样。我把需求描述清楚——“用ESP32读取MAX30102的心率数据,通过BLE推送到前端网页”——它就能给我一份结构清晰、能直接烧录的代码框架:初始化I2C、配置传感器寄存器、读取PPG原始值、计算心率、建立BLE服务与特征值、向前端推送。我不用先去啃几天文档才能写出第一行能跑的东西,第一天就能看到传感器亮起、串口吐出数据。从"零基础"到"可运行原型",中间那堵高高的入门墙,被大大削平了。
我清楚地记得第一次把代码烧进ESP32的场景:接好线、按下上传、心跳一下子提到了嗓子眼。串口监视器里开始滚动出一串串数字的那一刻,我差点从椅子上跳起来——那是心率,是真实的、随心跳起伏的数字。一个完全不懂嵌入式的人,在第一天就拿到了一个能跑的原型,这件事放在半年前我连想都不敢想。
这种感觉很难用语言准确传达给没试过的人:你描述一个心里想要的健康设备,几个回合之后,它就真的在你桌上跳动了。以前这种事只存在于想象里,现在它就发生在你的工作台上,离你只有一根数据线的距离。
我还记得那天晚上回家路上,一直在想一件事:如果没有TRAE,这颗芯片大概会一直躺在我的零件盒里吃灰,CareBridge的硬件梦也会在"先学两周文档"面前悄悄搁浅。是它把"要不要试试"变成了"已经做出来了"——而这中间的距离,恰恰是很多人放弃的地方。
9.3 AI生成代码的局限:那些必须自己趟过的坑
我不想把TRAE说得无所不能,因为真实的过程里,确实有一些坑是AI给的初始代码填不上的,得靠自己一点点趟。而恰恰是这些坑,让我对"人机协作"这件事有了更实在的理解。
第一个是MAX30102的PPG信号滤波。AI给的初始代码能读出原始光信号,但直接算出来的心率波动很大,一会儿60一会儿90,根本没法用作健康判断。问题出在滤波参数:原始PPG信号里混着环境光、运动伪影和基线漂移,不滤干净,峰值检测就会乱跳。我反复测试,把滑动平均窗口从默认值一点点调大,再调峰值检测的阈值和最小峰间距,剔除那些明显不合理的心跳间隔,最后才得到一条相对平稳的心率曲线。这个调参的过程,AI能给你方向,但每一步的"再试一次",得你自己耐着性子磨——盯着一串串数字,看它到底稳了没有。
第二个是DS18B20温度传感器的-127°C异常。调试时串口里时不时蹦出一个-127°C,明显是错的。查下来是传感器接触不良时,读取会返回这个固定的错误码。AI给的初始代码没有处理这个边界,直接把-127°C当真实温度推上去了,前端就会显示一个荒唐的极低温。我补了一段校验:读到-127°C就丢弃这次采样、重试,并在连续异常时提示检查接线。这种边界情况,往往要等真机跑起来才会暴露,而修它的过程,恰恰是你真正理解这块硬件脾气的过程。
还有一次,BLE连接在电脑上好好的,到手机上却怎么都连不上。我和TRAE IDE一起排查了好几个小时,把能想到的可能性一个个排除,最后发现是手机浏览器对某个BLE特征的权限处理和桌面端不同。AI不会一开始就猜中这种环境差异,但它会陪你把可能性一个一个试过去,直到锁定真凶。这种"陪你看不见的bug"的能力,比直接给你一段正确代码更珍贵。
说这些恰恰不是抱怨——正因为TRAE把大部分重复性、模板性的工作承担了,我们才有精力去死磕这些真正需要人去理解、去判断的细节。它把你从体力活里解放出来,让你专注于那些真正有价值的问题。AI不是来替代你的判断,而是来腾出你判断的余裕。
9.4 这个项目到底有多大
回头看看,CareBridge的体量远超我们最初的想象。六十多个功能模块,大约七十个Web页面,背后是复杂的家庭成员状态管理、AI风险评估引擎、飞书表格双向同步、ESP32固件开发、Web Bluetooth API集成。光家庭成员这一块,就要处理多角色权限、跨代际关系、主副照护者协同、异常逐级上报这些绕来绕去的逻辑;风险评估引擎要把问卷和实时生理指标两条数据流揉到一起,给出可解释的结论;飞书同步要在网络不稳时保证数据不丢、不重。
随便举几个模块:经期预测要根据历史周期建模并给出可解释的判断;家庭看板要支持多成员切换、权限分级和异常高亮;飞书同步要在弱网下做断点续传和冲突合并;ESP32端还要处理低功耗、重连和固件OTA。每一块单独拎出来都不简单,叠在一起更是一座小山。
如果按传统方式,这套东西需要一个完整的前后端加嵌入式团队花上几个月。而我们,是借助TRAE以一个极小的团队,在有限的比赛周期里把它从想法变成了能跑的现实。工具把"可能"的边界往外推了一大截,这跟我们个人有多厉害关系不大——是时代和工具,给了普通人去做大事的机会。
9.5 TRAE的三种能力,像三种不同的伙伴
用下来,我对TRAE的三种能力各有各的体会,它们像三个性格不同却都很靠谱的伙伴。
Auto模式像一位经验丰富的架构师。 面对一堆零散的需求,它帮我们理清思路、规划路径——先做什么、后做什么、模块之间怎么衔接。很多次我脑子里一团乱麻,连"从哪儿下手"都想不清楚,和Auto聊几个回合,脉络就清晰了,它甚至会提醒我一些我没想到的边界情况。
Code模式像一个高效的执行伙伴。 把需求描述清楚,它就能把需求变成可运行的实现。从页面到接口,从逻辑到样式,描述到位,产出就到位。它不挑活儿,复杂的引擎和琐碎的表单都一样踏实。
TRAE IDE像一个耐心的调试助手。 报错了、数据对不上了、某个传感器读数异常了,把问题喂给它,它会陪你一步步定位、一步步修复,不厌其烦。哪怕你凌晨两点卡在一个奇怪的bug上,它也不会甩脸色给你看。
回想起来,整个项目最难的从来不是某一段代码,而是把这么多模块串成一条顺畅的体验。Auto帮我搭骨架,Code帮我填血肉,IDE帮我修神经,三者接力,才把一个庞杂的系统从混沌里拎了出来。
9.6 最感人的那个瞬间
如果非要挑一个最感人的瞬间,是ESP32传感器第一次成功把心率数据推送到Web页面上的那一刻。
那天调了很久,BLE连不上、数据包是空的、前端收到的全是乱码,反反复复。等到终于把最后一个小问题修掉,刷新页面,屏幕上那个数字开始随心跳起伏——68、69、68、70——我盯着看了很久,半天没说话。那一刻,硬件、固件、BLE、前端,这一路踩过的所有坑,全都有了交代。
更让我动容的是,我忽然意识到这个跳动的数字背后,可能是一个远方独居老人的心跳,是一个远嫁女儿终于能"看见"的父母,是一个原本只能在电话里说"我没事"的人,第一次被如实记录下来的生命体征。我们做的不是一个demo,而是一根连接亲人的线。所有的辛苦,在那一刻都值了。
我甚至拍了张照片发到团队群里,配了一句"它活了"。群里瞬间炸开,几个伙伴连发了一串感叹号。那一刻我们心里都清楚:我们做的这个东西,是真的可能走进某个真实家庭的。
后来我把那段心率曲线截了下来,一直存在手机里。每当开发卡住、想要放弃的时候,我就翻出来看一眼。它提醒我,我们写的每一行代码、调的每一个参数,最终都会落在一个真实的人身上——会变成一位老人手腕上那一点点温度,会变成一个女儿深夜看到"一切正常"时的安心。这不是一份作业,这是一根救生索。
9.7 写给社区的每一位
我特别想把CareBridge的故事讲给更多人听,不只是技术牛人。
如果你是产品经理,你脑子里那些"要是有个产品能……"的念头,现在有了落地的可能,不必再苦等开发排期;如果你是设计师,你对体验的细腻感知,可以直接长成可交互的界面,让美好的想法不再停留在草稿里;如果你是医疗从业者,你懂的那些被忽视的健康需求,能变成真正服务人的工具,把诊室里的关怀延伸到患者家里;甚至如果你完全没有编程经验,只要你愿意把一个真实的问题描述清楚,AI就能陪你把它做出来——描述清楚问题,本身就是一种了不起的能力。
门槛从来没有像现在这样低过。真正稀缺的,是看见真实问题的眼睛,和愿意为它做点什么的真心。技术会写代码,但只有人会心疼另一个人。我们做CareBridge的初衷,就是看见了那些被忽视的人,而TRAE让我们有能力把这份"看见"落到实处。如果你心里也有这样一群想照顾的人,别让"我不会写代码"成为放弃的理由——这个时代,已经替你把那块石头搬走了。
我见过太多好想法,不是死在"太难",而是死在"我不会"。其实你不必会写代码,你需要的是愿意把一个问题想清楚、讲清楚——剩下的,交给工具就好。CareBridge就是这样一个"想清楚之后就被做出来"的故事,而这样的故事,理应不止我们一个。
9.8 写在最后
这段旅程教会我一件事:技术最有价值的地方,不是它本身有多酷,而是它能解决多少真实世界的问题,能帮助多少真实的人。
CareBridge还远不够完美,它有bug,有粗糙的边角,有还没来得及实现的设想。但它真真切切地,让一颗50元的芯片学会倾听心跳,让一个不会用手机的老人被健康系统看见,让一个远方的女儿放下心来。这就够了。
如果你也被某个真实的问题牵动,别犹豫,拿起工具去做吧。这个时代,已经给了我们足够的可能——剩下的,就看你愿不愿意迈出那一步了。愿每一个被忽略的心跳,都能被听见;愿每一个想为别人做点什么的人,都能找到趁手的工具。这是CareBridge想说的,也是我想对每一位读到这里的你说的。
体验地址:https://workspace-nine-blush.vercel.app/dashboard
Session ID:
SG.7624369052882256914:a01b014d7c53e2bd97ab4fb45af5a098_69de0fccb870d754b1449a16.6a55d0737ec7d9f938bf93ef.6a55d06cc9af2733805d8957:TRAE Work.1.0.0.2097.f37b62b4-40b1-4327-ad32-9d850b176b27.no_ppe.T(2026/7/14 14:00:31)[spoiler]
[/spoiler]SG.7624369052882256914:6df226dfba0dc2106633b4756bbd99ff_69de0fccb870d754b1449a16.6a55c108ff77ca98494f2970.6a55c10722de6473cb4941e0:TRAE Work.1.0.0.2097.f37b62b4-40b1-4327-ad32-9d850b176b27.no_ppe.T(2026/7/14 12:54:36)[spoiler]
[/spoiler]SG.7624369052882256914:ff080407ad7e92c04cc36f891d5e8366_69de0fccb870d754b1449a16.6a51e92bd51103b48c3efb7a.6a51e92a6e8120cf0a327e74:TRAE Work.1.0.0.2097.f37b62b4-40b1-4327-ad32-9d850b176b27.no_ppe.T(2026/7/11 15:07:07)。[spoiler]













