面试官:你说你参与了“AI症状检查”功能的开发,能系统地讲讲这个模块的整体设计吗?
面试者: 当然可以。
“AI症状检查”是我们医疗平台中一个面向用户的智能健康导诊功能。它的核心目标是: 帮助用户在未就医前,通过输入自身症状,获得初步的疾病可能性分析、就医建议和健康指导,从而减少盲目挂号、提升就医效率。
但我们也非常清楚:
AI不能替代医生,只能作为辅助工具。 所以整个设计从一开始,就围绕“智能、安全、可控、可解释”四个原则展开。
一、整体业务流程设计
整个功能的用户旅程如下:
用户输入症状 支持三种方式:
- 自由文字输入(如“我头疼三天了,还发烧”)
- 语音输入(调用讯飞语音识别转文字)
- 预设症状选择(点击“头痛”、“咳嗽”等常见症状)
系统初步分析 后端接收输入后,进行文本清洗、关键词提取,结合用户的年龄、性别、既往病史等基础信息,生成一个“初步症状画像”。
AI交互式问诊 系统不会一次性给出结论,而是像医生一样,主动追问关键问题,比如:
- “头痛是持续性的还是阵发性的?”
- “有没有恶心、呕吐或视力模糊?”
- “最近有没有受过外伤?”
通过2~3轮交互,逐步缩小可能的疾病范围。
生成最终建议 在信息相对完整后,系统输出:
- 可能的疾病方向(如“偏头痛可能性较大”、“上呼吸道感染待排查”)
- 建议就诊科室(如“神经内科”、“呼吸内科”)
- 紧急程度提示(普通 / 建议尽快就诊 / 立即就医)
- 健康指导(如“多休息、避免劳累”)
- 明确免责声明:“本建议仅供参考,不能替代专业医疗诊断”
引导下一步动作 用户可选择:
- 查看详细解释
- 直接跳转“在线挂号”
- 分享结果给家人
二、后端核心架构设计(Java视角)
作为Java开发工程师,我主要负责整个后端的流程编排、AI集成、状态管理、安全控制和系统稳定性保障。
1. 多模态输入统一处理
前端传来的无论是文字、语音转文字,还是预设症状,后端都会统一归一化为“症状关键词集合”。 例如:“头好晕” → 标准化为“头晕”;“发烧”和“发热”视为同义词。 这个过程依赖一个可配置的医疗同义词词典,由产品和医学团队维护,后端通过配置中心动态加载。
2. AI分析流程的结构化控制
我们没有让AI“自由发挥”,而是设计了一个结构化推理流程:
- 第一步:角色定制(Role Prompting) 我们给大模型设定明确身份:“你是一名三甲医院全科医生,擅长初步筛查和分诊”。 并严格规定输出格式,确保返回的是结构化数据,而不是一段自由文本。
- 第二步:检索增强(RAG) AI的“知识”不是靠记忆,而是靠实时检索。 我们接入了一个医学知识库,包含《常见病诊疗指南》《症状鉴别诊断手册》等权威资料。 当用户输入“头痛+恶心”时,系统会先从知识库中检索“偏头痛”“颅内压增高”等条目,作为AI推理的依据,避免“幻觉”。
- 第三步:函数调用(Function Calling) AI不仅能“说”,还能“做”。 例如,当AI判断需要查看用户过往的血压记录时,它可以“调用”一个内部接口,获取历史数据,再结合新症状做判断。 这种能力让AI从“聊天机器人”升级为“智能协作者”。
- 第四步:多轮交互控制(MCP) 我们设计了一个会话状态机,管理用户的问诊进度:
- 初始状态:收集主诉
- 第一轮追问:症状特征(持续时间、加重因素)
- 第二轮追问:伴随症状
- 最终状态:生成建议 每一步都可中断、可回退,确保流程可控。
- 第五步:Agent式整合 最终,我们将以上能力整合为一个“AI诊疗代理(Agent)”,它能自主决策: “先查知识 → 再问用户 → 调历史数据 → 更新判断 → 输出建议”,实现端到端的智能服务。
三、关键非功能性设计
1. 性能优化:异步 + 缓存
AI分析耗时较长,不能阻塞用户。 我们采用异步处理 + WebSocket推送: 用户提交后,系统立即返回“AI分析中…”,后台通过消息队列(RabbitMQ)异步处理,完成后主动推送结果。
同时,对高频症状组合(如“感冒”“拉肚子”)的AI结果做Redis缓存,命中率超60%,显著降低响应延迟和AI调用成本。
2. 安全与合规:四重防护
医疗场景容不得半点马虎,我们做了四层保障:
- 内容安全:输出结果过滤“推荐药物”“自行用药”等敏感词,禁止AI越界;
- 紧急拦截:一旦用户输入“胸痛”“意识模糊”“呼吸困难”,系统直接跳过AI,弹出“建议立即就医”;
- 免责声明:所有AI建议页面顶部有红色提示,明确告知“仅供参考”;
- 审计留痕:所有AI调用、用户交互、结果生成均记录日志,支持追溯与复核。
3. 高可用保障:熔断 + 降级
AI服务可能因网络、负载等原因不可用。 我们引入熔断机制(Sentinel): 当AI调用失败率超过阈值,自动切换到“规则引擎兜底”。 例如:“头痛 + 发热” → 默认建议“呼吸内科”;“腹痛 + 腹泻” → 建议“消化内科”。 虽然智能程度降低,但基本功能不中断。
四、可拓展场景与未来方向
这个模块不仅仅是一个“症状自查工具”,它还可以延伸出多个高价值场景:
1. 与医生端系统打通
当用户完成AI症状检查后,生成的“主诉摘要”可直接同步到医生端电子病历系统,减少医生重复问诊时间,提升门诊效率。
2. 个性化健康档案
长期使用AI症状检查的用户,系统可自动构建“个人健康画像”,记录常见症状模式,未来可提供慢性病管理、健康预警等服务。
3. 家庭健康共享
支持用户将AI检查结果分享给家人或家庭医生,便于远程问诊或照护决策。
4. 与可穿戴设备联动
未来可接入智能手表的实时数据(如心率、血氧),让AI分析更全面,例如:“您当前心率偏高,结合胸闷症状,建议尽快就医”。
面试官:你们的AI医生对话功能依赖网络调用大模型,如果用户网络很差,页面卡住或者请求失败,这种情况你们是怎么处理的?
面试者: 这是一个非常实际的问题。在移动端或弱网环境下,网络不稳定是常态。我们从用户体验、系统稳定性和降级策略三个层面做了系统性设计。
面试官:具体是怎么保障用户体验的?
面试者: 首先,在前端交互上,我们做了友好的加载反馈机制。
当用户发送问题后,即使网络慢,我们也立即给出响应:
- 立刻显示“AI正在思考中…”的动画;
- 如果2秒内没返回,提示“网络较慢,正在努力加载”;
- 支持用户手动“重新生成”或“切换到文字建议”。
这样避免用户觉得“卡死了”,提升等待耐心。
面试官:那后端是怎么应对网络不稳定的?
面试者: 后端我们做了三件事:
- 超时控制: 调用大模型API时,设置严格的超时时间,比如连接1秒,读取3秒。 避免线程长时间阻塞,防止服务雪崩。
- 异步处理 + 消息队列: 用户请求进来后,我们不直接同步调AI,而是放入消息队列(如RabbitMQ),后台异步处理。 即使网络波动,请求也不会丢失,处理完后通过WebSocket推送给用户。
- 本地缓存兜底: 对常见症状(如“感冒”“头痛”),我们将高频AI回答缓存在Redis中。 当检测到用户网络较差时,优先尝试返回缓存结果,保证“有内容可看”。
面试官:如果AI服务本身也响应慢或不可用呢?
面试者: 这就是我们要做的熔断与降级。
我们使用了Sentinel做流量控制和熔断管理:
- 当AI服务连续调用失败超过阈值,自动触发熔断;
- 熔断后,不再调用大模型,而是切换到“规则引擎兜底”;
- 规则引擎基于预设逻辑返回基础建议,比如:
- “头痛 + 发热” → 建议“呼吸内科”
- “腹痛 + 腹泻” → 建议“消化内科”
- 所有结果都带免责声明
虽然不如AI智能,但保证了核心功能可用,用户体验不中断。
面试官:用户已经发了消息,但中途断网了怎么办?
面试者: 我们做了对话状态持久化。
每次用户发起对话,系统都会创建一个“会话ID”,所有提问和追问都绑定这个ID。
- 如果中途断网,用户重新进入时,系统通过会话ID恢复上下文;
- 用户可以看到“之前的对话记录”;
- 可选择“继续等待”或“重新开始”。
这样避免用户重复描述症状,提升弱网下的使用体验。
面试官:有没有考虑离线方案?
面试者: 目前大模型还无法完全跑在手机端,但我们做了轻量级预加载:
- 在用户打开AI对话页时,预先加载一些常见问题的静态答案(如“发烧怎么处理”);
- 这些内容打包在前端资源中,不依赖网络;
- 当检测到离线或极慢网络时,展示这些预置内容,引导用户先看基础知识。
未来如果端侧大模型成熟,我们会探索“本地小模型+云端大模型”的混合架构。
面试官:总结一下,你是怎么看待这个问题的?
面试者: 我认为,网络差不是异常,而是常态。 特别是在医疗场景下,用户可能在地铁、山区、医院地下室使用,网络条件复杂。
所以我们不能假设“网络永远通畅”,而要设计一个弹性、可靠、有退路的系统:
- 快的时候,用AI提供智能服务;
- 慢的时候,用缓存和异步保体验;
- 断的时候,用降级和持久化保功能。
这才是一个真正可用的AI医疗产品。
面试官:你们的AI医生对话最后能直接预约医生,这个“预约”功能是怎么实现的?涉及哪些系统?
面试者: 是的,这是我们设计的关键转化路径:
用户输入症状 → AI分析 → 推荐医生 → 一键预约 → 完成挂号
“预约”不是简单的跳转链接,而是一个安全、可靠、可追溯的业务闭环。 我在后端负责整个预约流程的接口对接、状态管理、并发控制和异常处理。
面试官:那用户在AI对话里点“预约”,系统是怎么处理的?
面试者:
这里AI肯定不能做这些事情,这里就使用到了Function Calling,
整个流程分为五步,我来一步步说明:
预约前校验 用户点击“预约”时,系统立即检查:
- 医生号源是否可用(调用排班系统API)
- 用户是否已实名认证(医疗合规要求)
- 是否存在未完成的预约(防重复提交)
任一校验失败,立即提示用户,避免后续失败。
锁定号源(预占) 如果校验通过,系统会向医院的预约挂号系统发起“号源预占”请求:
- 锁定该时段的号源,防止被他人抢走;
- 设置预占有效期(如10分钟),超时自动释放。
生成预约订单 在我们平台创建一条“预约订单”,状态为“待支付”或“待确认”,包含:
- 用户信息
- 医生ID、科室、就诊时间
- 来源标记:“来自AI对话推荐”
引导完成支付/确认 跳转到支付页或医院官方确认页,用户完成支付或确认后,状态更新为“已预约”。
通知与提醒 预约成功后:
- 发送站内信、短信、微信模板消息;
- 自动加入用户“我的就诊”列表;
- 支持添加日历提醒。
面试官:如果多个用户同时抢一个号,会不会超卖?
面试者: 这是个非常关键的问题,我们通过分布式锁 + 数据库乐观锁双重机制防止超卖。
分布式锁(Redis) 每次预约请求进来,先尝试获取该“医生+时段”的Redis锁:
SETNX appointment_lock:doctor_1001:2025-04-05-14-00 true EX 5只有拿到锁的请求才能继续,其他请求排队或返回“号源紧张”。
数据库乐观锁 在更新号源表时,使用版本号控制:
UPDATE doctor_schedule SET available_count = available_count - 1, version = version + 1 WHERE id = ? AND available_count > 0 AND version = ?如果更新影响行数为0,说明已被他人占用,本次预约失败。
最终一致性 所有操作通过本地事务 + 消息队列保证最终一致:
- 预约成功 → 发消息 → 同步到HIS系统(医院管理信息系统)、发送通知;
- 失败 → 记录日志 → 支持人工对账。
面试官:如果医院系统挂了,预约失败了怎么办?
面试者: 我们设计了熔断 + 降级 + 补偿机制来应对依赖系统故障。
- 熔断机制 使用Sentinel监控医院挂号接口的失败率,超过阈值自动熔断,暂停预约功能,避免雪崩。
- 降级策略 熔断后,前端提示:“当前医院系统繁忙,建议稍后通过医院官方渠道挂号”,并提供医院官网或电话。
- 补偿任务 所有失败的预约请求进入“重试队列”,后台定时重试(最多3次),成功后通知用户。
- 人工对账 每天定时跑批,对比我们系统的预约记录和医院HIS系统的实际挂号数据,发现不一致时告警处理。
面试官:预约信息怎么和医院系统同步?会不会对不上?
面试者: 这是医疗系统的核心合规要求,我们采用双向同步 + 唯一标识 + 审计日志保障一致性。
唯一订单号 每次预约生成全局唯一ID(如Snowflake),同时作为我们系统的订单号和医院系统的外部订单号。
状态同步 医院HIS系统会通过回调接口,主动推送预约状态变更:
- 已确认
- 已取消
- 就诊完成
我们收到后更新本地状态,保证两端一致。
审计日志 所有预约操作(创建、取消、修改)都记录完整日志,包括:
- 操作人(用户或系统)
- 时间戳
- 请求/响应报文(脱敏)
- 用于后续对账和合规审查。
面试官:用户预约后想取消,怎么处理?
面试者: 我们支持用户自助取消,但要符合医院规则。
- 取消规则校验 根据医院政策,判断是否可取消:
- 一般要求提前24小时;
- 临近就诊时间不可取消;
- 特需门诊可能不支持取消。
- 释放号源 取消成功后,调用医院接口释放号源,同时更新我们系统的号源库存。
- 退款处理 如果已支付,触发退款流程:
- 原路退回
- 异步处理,通过消息队列解耦
- 退款状态可查
- 记录取消原因 引导用户选择取消原因(如“时间冲突”“症状缓解”),用于分析AI推荐的合理性。