
做医疗健康类小程序的朋友应该都有体会用户一进来就问症状、找建议、要评估但你一个个人开发者或者小团队手里既没有医生资源也没有成熟的知识库很难凭人力撑起有质量的问答。我自己在做一个“微信小程序的AI健康问诊系统”时踩了不少坑也积累了一套从架构到落地的完整打法。这套系统本质上是一个个人健康评估工具用户在微信里打开小程序通过对话式问诊逐步提交症状、既往病史、生活习惯等信息AI在后台完成分诊判断和健康风险分析最后合成一份个人健康评估报告。它能解决的核心问题是在没有人工客服和全职医生团队的情况下用AI把“用户健康自测”这件事流程化、标准化、可追踪适合想快速上线健康咨询类MVP的个人开发者、医疗行业的产品运营以及需要给用户提供前置评估的创业团队参考。下面我把整个项目的设计思路、小程序端实现、AI问诊流程、健康评估模型、数据安全合规、上线踩坑这些环节一次讲透尽量给到可以直接抄作业的配置、代码和参数。1. 项目定位与整体设计思路1.1 这套系统到底解决什么问题健康问诊类小程序最常见的尴尬是用户想要的是一份“靠谱的回答”而你的第一版产品只能给一个“固定的表单”。让用户填一堆选择题体验很差完全开放对话AI又容易胡说。我的目标是做一个折中方案先用结构化对话收集信息再交给大模型做语义理解和推理最后用规则引擎兜底保证输出既有人情味又有可解释性。“健康评估”这个词听起来玄实际上拆开就是三步收集、分析、反馈。收集环节对应问诊对话分析环节对应疾病风险推断和生活方式评分反馈环节对应健康报告和建议列表。只要这三个环节的数据链路打通系统就已经能跑起来了。我的建议是不要把AI健康问诊当成“AI医生”而是当成“AI分诊台健康助理”它的任务是帮用户理清问题严重程度、提示就医时机、记录健康趋势而不是给出确诊结论。1.2 技术选型为什么是微信小程序加云端AI大模型选微信小程序做前端理由很实际用户不用下载安装搜一搜或扫码就能用医疗健康类场景里用户往往是在临时不舒服、急需建议的时刻打开小程序轻量化入口是硬需求。小程序本身的组件生态也覆盖了表单、单选、多选、文本输入、富文本展示这些问诊全流程需要的基础元素。后端的AI部分我选择了云端大模型API加自建业务服务层的组合而不是把所有逻辑都塞进小程序本地。原因有三点大模型推理需要GPU资源个人开发者不可能本地部署问诊会话和健康报告需要持久化存储本地存储顶多存个草稿健康数据必须集中管控加密、脱敏、审计这些操作放在服务端才可控。整体架构上小程序端只负责UI交互和本地缓存业务服务部署在云服务器上对外暴露HTTPS接口AI推理通过统一网关调用大模型接口。为了省钱初期可以直接用带公网API的服务不必要自己买GPU服务器。1.3 系统核心模块划分我把系统拆成了五个模块模块职责关键点问诊对话模块引导用户描述症状、病史、生活习惯多轮上下文管理分诊评估模块判断风险等级、给出就医建议规则引擎兜底报告生成模块汇总对话数据生成个人健康评估报告结构化内容模板用户与数据模块微信登录、健康档案、历史记录隐私隔离运维监控模块异常日志、AI调用计费、反馈收集防止失控这五个模块缺一不可。很多初版项目只做前三个结果用户换个手机登录历史报告全不见了或者AI接口超时直接把页面卡死都是因为后两个模块没有提前布局。我的经验是用户与数据模块在第一个版本就要上哪怕只有一个手机号绑定和一张历史记录表也要做。2. 微信小程序端开发要点2.1 页面结构与交互设计问诊类小程序的核心页面就那么几个首页、对话问诊页、评估报告页、个人中心页。首页不要堆功能只放一个“开始健康自测”按钮以及最近一次评估报告的入口。对话问诊页是整个产品的灵魂交互上要模仿聊天软件左侧是AI消息右侧是用户消息但不要用传统聊天输入框作为唯一入口因为用户不知道该怎么描述症状。我的做法是“按钮选择为主、文本输入为辅”。AI先问“你主要哪里不舒服”下面给出几个常见分类按钮头疼、发热、腹痛、咳嗽等用户点一下就发送AI继续追问“持续多久了”、“疼痛是什么性质的”、“有没有伴随症状”每一步都给出可选答案同时保留一个自由输入框允许用户用自己的话补充。用单选框和复选框组件做多选症状的时候记得给每个选项加一个sort字段保证选中后按预设顺序展示不要以用户点击顺序为准。顶部导航栏的适配是个容易忽略的坑。不同机型的胶囊按钮位置和状态栏高度都不一样。我是用一个工具函数通过wx.getWindowInfo()拿到状态栏高度和菜单按钮位置把自定义导航栏的高度动态算出来。如果你用默认导航栏至少要把页面标题设置清楚别让用户在问诊中途迷失方向。2.2 请求封装与AI对话流式返回处理小程序网络请求必须走HTTPS并且要在微信公众平台配置request合法域名。我封装了一个统一的request方法所有业务接口都走同一套逻辑统一处理token、超时、错误提示、加载状态。// utils/request.js const BASE_URL https://your-api-domain.com/api; function request(path, method, data, options {}) { return new Promise((resolve, reject) { wx.request({ url: ${BASE_URL}${path}, method: method || GET, data: data || {}, header: { Content-Type: application/json, Authorization: wx.getStorageSync(token) ? Bearer ${wx.getStorageSync(token)} : }, timeout: options.timeout || 15000, success(res) { if (res.statusCode 401) { wx.removeStorageSync(token); wx.navigateTo({ url: /pages/login/login }); reject(res); return; } if (res.statusCode 200 res.statusCode 300) { resolve(res.data); } else { wx.showToast({ title: res.data.message || 请求失败, icon: none }); reject(res); } }, fail(err) { wx.showToast({ title: 网络异常请检查网络, icon: none }); reject(err); } }); }); } module.exports { request };这里有个很重要的细节AI对话别等完整响应再展示用户等不了那几秒钟。新版小程序基础库的wx.request支持enableChunkedTransfer开启分块接收配合onChunkReceived可以模拟流式输出。实际开发中我发现onChunkReceived返回的数据是ArrayBuffer需要手动按\n拆包而且有时候一次chunk里有多条数据。我在服务端统一按“data: {json}\n\n”格式推送前端做缓冲解析。千万不要在每次收到chunk时就setData整个消息数组那会卡到没法用。我采用的方案是维护一个用于渲染的消息列表只在用户发言和AI完整回复结束时更新列表流式过程中的内容更新通过selectComponent拿到子组件实例只更新最后一条消息的文本节点这样渲染压力小很多。2.3 登录态与会话管理登录这块我直接用了微信的wx.login()拿到code之后发给后端由后端调用微信的接口换取openid同时签发自己的token。注意不要在响应里把openid下发到前端openid属于敏感信息泄露出去会被刷接口。// utils/auth.js function wxLogin() { return new Promise((resolve, reject) { wx.login({ success(res) { if (res.code) { // 将 code 发送到自己的后端 request(/auth/login, POST, { code: res.code }) .then(data { wx.setStorageSync(token, data.token); resolve(data); }) .catch(reject); } else { reject(new Error(wx.login failed)); } }, fail: reject }); }); }问诊会话的超时机制要单独处理。很多用户聊到一半切出去回微信消息再回来可能已经过了十几分钟。我的策略是把问诊状态存到本地storage和远端双份进入页面时如果检测到上一条AI消息停留超过30分钟且流程未结束弹窗提醒用户“继续上次问诊”还是“重新开始”。这能用上小程序的生命周期监听在onHide里记录离开时间在onShow里做恢复判断。这里要注意onHide在用户切后台、跳转其他页面、弹出授权框时都会触发记录时间戳要精确到秒不然容易误判。3. AI问诊与健康评估的核心实现3.1 结构化问诊流程设计问诊流程不能设计成纯自由的聊天否则AI很容易聊到失控。我的做法是“用户主诉引导 系统追问闭环”。流程分四步主诉收集用户选择或输入主要不适如发热、头痛、腹痛特征追问持续时间、发作频率、严重程度、加重/缓解因素伴随症状选择从预设列表多选如恶心、呕吐、腹泻、乏力风险信号筛查是否高龄、是否孕妇、是否有基础病、是否出现呼吸困难、意识模糊等危急信号。每一步AI只问一个核心问题优先问风险最高的信息。比如用户说“胸痛”不要先问“疼了多久”而要先问“有没有出冷汗、呼吸困难、濒死感”这是为了尽早筛出需要急诊的病例。规则配置里我维护了一个“风险信号词库”如果用户描述中命中这些词评估等级直接跳转最高风险不再继续常规追问。整个对话上下文会拼成一个结构化的prompt传给大模型。我保留了一份完整对话记录而非只传当前一轮因为用户可能在第五轮才提到“我以前有过胃炎”这个既往史对风险评估非常重要。在大模型拿到完整历史的同时我也把前端收集的结构化字段一并传给服务端做规则判断形成“AI生成追问规则判定风险”的双通道机制。3.2 个人健康评估模型搭建健康评估这部分我没有完全依赖大模型的自由发挥而是做了一套可解释的评分体系。分两大块疾病风险等级和生活方式得分。疾病风险等级用“红黄绿”三色标签对应紧急、关注、平稳。风险判断由两层完成第一层是规则引擎比如“发热≥39℃且持续超过3天”直接给黄色“胸痛伴大汗”直接给红色第二层是大模型根据完整对话输出一个建议风险等级和依据说明。最终等级取两者更高的一级宁可保守不能漏。生活方式得分则是从问诊中采集的睡眠时长、运动频率、饮水习惯、压力自评等数据按百分制加权计算。我给每个维度设了权重睡眠30%运动25%饮食25%心理20%。每项按用户作答内容映射为0到100分再乘权重求和。比如睡眠6小时以下算50分7到8小时算90分8小时以上但入睡困难也算70分。这个映射逻辑要在一开始就定清楚不能指望大模型稳定地输出精确分数否则报告前后标准不一致。计算过程的代码放到服务端执行我贴一个简化版伪代码你可以按需改成Python或Node.js# score_calculator.py def calc_sleep_score(hours): if hours 7 and hours 8: return 90 elif hours 6 and hours 7: return 60 elif hours 6: return 40 elif hours 9: return 70 else: return 80 def calc_health_score(profile): sleep calc_sleep_score(profile.get(sleep_hours, 7)) exercise profile.get(exercise_weekly, 2) * 10 diet profile.get(diet_score, 70) mental profile.get(stress_score, 70) return round(sleep * 0.3 exercise * 0.25 diet * 0.25 mental * 0.2, 1)这里要特别注意运动频率如果每周超过7次得分不应该线性上涨我做了封顶处理超过7次按7次算提醒用户“运动过量”也是风险。很多健康评估系统在这块拍脑袋加分用户一周练十天也给高分一看就不专业。3.3 健康报告生成与建议推送报告生成不是让AI自由写作文而是“模板加变量填充加AI润色”。我设计了三个固定区块基本信息区、风险评估区、生活建议区。基本信息区直接展示结构化数据风险评估区把风险等级翻译成通俗语言比如“目前症状倾向于轻度上呼吸道感染建议居家观察三天如出现持续高热请及时就医”生活建议区根据评分结果生成可执行的建议比如“睡眠得分偏低建议固定23点前入睡睡前1小时减少手机使用”。模板文案我维护在服务端配置里AI只负责在模板框架内微调措辞避免出现“你可多吃水果”这种放之四海而皆准的废话。为了让报告看起来可信我还加了一条核心逻辑报告顶部永远显示“本报告由AI辅助生成不构成医疗诊断如有不适请线下就医”。这句话不只是合规要求也是降低用户预期、防止纠纷的保命条款。报告生成之后推送给用户的方式有两种在小程序内打开报告页面同时通过订阅消息提醒用户“您的健康评估报告已生成”。订阅消息需要用户主动点击允许订阅所以我的触发时机是问诊完成的最后一步“点击查看报告”按钮同时拉起订阅授权而不是在对话中途插入授权弹窗。4. 数据安全与合规处理4.1 健康数据的敏感等级划分健康数据在《个人信息保护法》语境下属于敏感个人信息这是我在项目初期就反复确认过的。只要涉及症状、病史、用药记录就不能按普通用户数据来存。我在数据库设计上做了三层隔离用户基本信息表、健康档案表、AI对话日志表。三张表之间用加密后的用户ID关联不在任何一张表里同时出现openid和完整健康记录。这意味着即使数据库被人拖走了攻击者也很难把“用户A的电话号码”和“用户A的腹痛症状”串联起来。实际开发里我用了一个简单的办法把微信openid做HMAC摘要作为关联键原始openid单独存到用户表健康档案表里只出现这个摘要值。4.2 加密传输与脱敏存储传输层全部走HTTPS小程序端严格要求域名ICP备案且配置证书这是微信官方强制项不用自己纠结。存储层的敏感字段比如姓名、手机号在后端统一加字段级加密。我用的对称加密密钥存在环境变量中不写进代码仓库。密钥轮换周期我设的是90天每次轮换要做数据迁移所以接口里顺手做了一个密钥版本号字段解密时按版本找对应密钥。脱敏也是必须做的。AI对话日志如果要拿来做模型效果分析我会先把姓名、手机号、具体地址替换成占位符再导出。症状描述里偶尔会有用户不自觉输入电话和身份证号我在入库前用正则做了扫描命中号码规则就自动打码。4.3 合规红线AI辅助定位这是我这套系统最重要的一个设计立场AI不诊断、不开方、不替代医生。所有给用户的建议文案都必须经过合规词过滤。我在服务端加了一个敏感词和违规律师函级别的规则列表比如任何药品名称出现在AI回答中除非是用户自己输入否则直接拦截并要求AI改写成“请遵医嘱使用相关药物”。此外在小程序隐私保护指引中我明确填写了“收集你的症状、病史信息用于健康评估”并在用户首次进入问诊时弹出独立的健康数据授权弹窗不做默认勾选。这块的体验损失是值得的因为一旦被投诉小程序下架是分分钟的事。我见过几个同类项目因为隐私弹窗不完整被拒审大家一定不要抱侥幸心理。5. 实操过程与踩坑记录5.1 从原型到MVP的落地步骤第一个版本不要想着一步到位我的落地节奏是这样先用微信开发者工具搭建三个静态页面把问诊的UI交互完整走一遍这个阶段不接AI用写死的模拟数据接一个最简单的AI接口只做“单轮问答”验证AI返回内容的质量和速度补齐问诊流程的状态机把“进行中、已完成、已过期”三种状态跑通接入微信登录和基本用户表保证报告可以持久化用体验版发给周围人收集反馈同时开启真机调试。最后一步很重要。小程序开发工具里模拟器跑得再顺真机上也可能出现键盘顶起页面、输入框被遮挡、流式输出卡顿、安卓机大文本渲染掉帧等问题。我给体验用户发了丝滑版任务清单让他们试着在问诊中途退出再进入、切到后台几分钟再接、快速点击多个症状选项把这类边界场景的Bug都逼出来。5.2 实测中的典型问题我在实测阶段被下面两个问题折磨了很久。第一个是iOS和安卓的流式文本渲染差异。同一段AI回复iOS上rich-text组件渲染没问题安卓上偶发显示不全。调试发现是流式更新时部分内容还在缓冲里就强制刷新了UI。我的解决方式是前端增加一个“文本缓冲区”只有缓冲区里检测到完整的“\n\n”分隔符才允许刷新一次UI避免边收边画导致的内容截断。第二个是问诊上下文过长导致AI响应变慢。多轮问答之后整个对话历史可能有几千字每次请求都全量带上响应时间从1秒涨到8秒。我是这么优化的服务端维护一个“摘要压缩”机制当对话超过十轮就把前几轮的信息压缩成一段结构化摘要只保留用户主诉、关键症状和时间线再和最近三轮对话拼在一起发AI。这个优化把p95的响应时间降到了3秒以内。5.3 常见问题速查表问题可能原因解决方案真机上请求失败域名未配置合法域名、证书不完整公众平台配置request域名用HTTPS检测工具检查证书链wx.request返回10002错误网络异常或域名解析失败检查域名备案、服务器防火墙、本地网络代理设置用户登录后信息不同步token过期启动时静默调用wx.login刷新token利用refresh_token机制AI流式输出不显示onChunkReceived解析错位按数据分隔符缓冲解析避免多条数据合并小程序审核被拒医疗健康类目的资质不全避免使用“诊断、治疗”等绝对化用语增加免责声明申请相关类目或走咨询工具定位键盘遮挡输入框页面没有做键盘适配使用adjust-positiontrue并在onKeyboardHeightChange中动态调整报告分享到微信打不开页面路径带参数过长用短链或通过storage暂存报告ID再跳转另外单个很实用的建议收集反馈的时候不要只收文字让体验用户直接录屏。很多UI问题光看文字描述根本复现不出来录屏配合日志能省一半排查时间。6. 性能优化与体验细节6.1 首屏加载优化健康问诊小程序的目标是让用户“最短时间内开始问诊”所以首屏加载链路要极简。首页只请求一个接口获取用户最近一次报告摘要。这个接口必须控制在200毫秒内返回做法是报告摘要字段单独存一份JSON而不是查询原始大表。用户在报告页要看详情时再按ID拉取完整内容。小程序这边优先考虑分包。问诊页和报告页通常依赖一堆第三方组件全部塞在主包会让首包体积膨胀到几兆审核和加载都很慢。我把“AI对话页”和“报告详情页”拆到单独分包主包只保留首页、个人中心、登录相关页面。这样主包能控制在1.5MB以内加载速度明显变快。6.2 流式输出的并发控制AI流式请求有个容易出问题的点用户连续发送消息时上一条请求还没结束新请求就进来了。如果不做控制AI会同时输出两段互相矛盾的内容显存和服务账单全在燃烧。我在前端做了“正在生成中禁止发送”的锁在服务端对同一个用户ID的对话请求做了串行化。具体实现是给用户加一把分布式锁锁的过期时间设为30秒如果当前已有未完成请求新请求直接返回“请稍候”的状态码前端提示用户等待。体验细节上AI输入中的“正在输入”动画一定要有不然用户以为系统没反应就反复点发送。动画不要做那种复杂的打字机效果简单三个点的透明度循环就够了省电又流畅。6.3 列表加载更多与历史报告分页用户做过多次评估后历史报告列表会越来越长。这里用小程序原生的onReachBottom触发加载下一页配合selectComponent里的列表容器计算坑位避免用户滑到底部时出现“加载中”和“到底了”两个状态同时出现。还要注意每次从报告详情返回列表时保持滚动位置不变不要整页刷新否则用户发现自己又滚回顶部耐心直接清零。6.4 调试工具的使用经验开发过程中网络请求排查我用的是微信开发者工具自带的Network面板配合sources调试断点。遇到线上接口参数诡异的问题我习惯在后端加一个echo调试接口把请求头和请求体原样返回前端在控制台直接看结构化输出比任何外部工具都直观。对于线上偶发的接口故障我在后端接了错误日志平台把HTTP状态码、用户链路追踪ID、AI调用耗时统一上报这样用户在群里反馈“刚才白屏了”的时候我能直接按traceId查日志而不是瞎猜。结尾关于这套系统我最想说的一点回头再看这个项目我最大的感受是AI健康问诊系统的难点并不在AI而在“边界”。你要在“让AI足够聪明”和“让AI不越界”之间找到平衡点。健康领域容错率极低一句不严谨的话就可能误导用户。所以我最后再分享三个观点第一所有AI生成的健康相关内容都必须经过结构化模板和规则引擎的双重校验。我的系统里AI的话术不是最终版本规则引擎才是最终兜底。第二用户体验的优先级大于AI炫技把一个简单的问诊流程做到不迷路、不卡顿、不丢数据比接入最新的AI模型更能提升用户留存。第三上线之后持续用真实对话数据优化提示词我在第一个月整理了近千条真实用户对话把AI频繁追问同一个问题、漏问关键风险点的情况逐一修掉健康评估的“靠谱感”才会有本质提升。如果你也在做同类小程序建议从小而美的问诊场景切入先把“感冒发热初步评估”这一条链路做透再慢慢扩展其他科室。先跑通一条路也比铺一张大而全的网实际得多。