简介这是一份面向Python开发者与医疗健康领域AI实践者的智能体应用源码包聚焦于利用大语言模型技术构建家庭级健康管理助手解决慢病监测、健康数据解读与自然语言健康咨询等实际问题。资源共18个文件含2个核心Python脚本app.py、st_app.py实现Streamlit前端与Lagent智能体逻辑2个文本文件requirements.txt、README.md支撑环境配置与项目说明12张PNG图像涵盖界面截图与架构图1个MD文档提供技术细节整体压缩包仅2.77MB轻量易部署。已有78人学习下载适合希望快速上手医疗垂直领域智能体开发的中高级学习者。读者可直接运行获得完整Web交互界面复现CVD慢病管理流程调用Lagent工具链完成健康问答推理并参考多阶段截图与结构化代码组织理解智能体工程落地的关键设计模式。1. 这不是另一个“医疗问答网页”HealthcareAgent 是一个能主动追问、分步推理、带临床逻辑链的 Python 智能体你有没有试过在某个医疗健康类 Web 应用里输入“我最近两周乏力、夜尿增多、空腹血糖7.8是不是糖尿病”——结果页面只弹出一句“建议及时就医”再无下文这不是交互是甩锅。而(源码)基于Python和Streamlit的HealthcareAgent医疗保健智能体.zip所指的恰恰是反其道而行之的一套落地实践它不追求大模型一锤定音而是用 Python 构建轻量级决策流在 Streamlit 界面中实现「症状采集 → 风险初筛 → 检查建议 → 分诊路径」四步闭环。核心不是替代医生而是把基层首诊的结构化问诊能力下沉到一线工具层。它面向的是社区健康管理员、慢病随访员、家庭医生助手开发者——这些人不需要部署千卡集群但需要一个能在 4 核 8G 笔记本上跑起来、改三行代码就能适配本地体检指标阈值、且每次对话都留下可追溯逻辑链的智能体。它不碰诊断结论但会明确告诉你“当前依据《中国2型糖尿病防治指南2023年版》第4.2条空腹血糖≥7.0 mmol/L 症状已触发高风险标记请确认是否已完成OGTT检查”。这才是真实场景里“能用、敢用、留痕、可调”的医疗智能体该有的样子。2. 从 ZIP 解压到本地运行5 分钟跑通 HealthcareAgent 最小可执行单元这个 ZIP 包不是玩具 Demo而是一个完整可调试的工程骨架。它没有隐藏依赖、不强制联网下载权重、不绑定特定云服务——所有逻辑都在本地 Python 进程中完成。下面带你走一遍最精简但完全可用的启动路径每一步都对应真实开发中你会遇到的配置点。2.1 解压与环境隔离为什么必须用 venv 而非 conda 或全局 pipZIP 包根目录下有requirements.txt但直接pip install -r requirements.txt是危险操作。原因有三一是 Streamlit 2.0 对某些旧版 PyTorch 绑定存在兼容性冲突二是医疗规则引擎模块health_rules.py依赖pandas1.5.3,2.0.0而全局环境可能已装pandas2.2.0导致DataFrame.query()行为突变三是后续你要接入本地 LLM如 Qwen2-1.5B-Int4需严格控制transformers和accelerate版本。提示不要跳过这步。我见过太多人因 conda 环境中numpy版本被自动升级导致scipy.stats.norm.cdf()返回 NaN最终让风险评分模块全线失效。# 进入解压后的目录假设为 healthcare_agent_v1 cd healthcare_agent_v1 # 创建干净虚拟环境Python 3.9–3.11 均可推荐 3.10 python -m venv .venv source .venv/bin/activate # Linux/macOS # .venv\Scripts\activate.bat # Windows # 安装时强制指定关键包版本防自动升级 pip install --upgrade pip pip install streamlit1.32.0 pandas1.5.3 numpy1.23.5 pip install -r requirements.txt安装完成后验证核心组件是否就位# 检查 Streamlit 是否识别到主入口 streamlit config show | grep browser.serverAddress # 应返回 localhost 或空表示未配置正常 # 检查规则引擎基础能力 python -c from health_rules import SymptomRuleEngine; print(Rule engine OK) # 应输出 Rule engine OK # 检查数据加载器VOC 格式体检报告解析器 python -c from data_loader import load_health_report; print(load_health_report(sample_report.json) is not None) # sample_report.json 需提前放入根目录见后文说明2.2 启动 Streamlit 并理解app.py的三层架构运行命令极其简单streamlit run app.py --server.port8501但app.py不是单文件脚本而是三层职责分明的结构层级文件职责修改频率界面层app.pyStreamlit 组件编排、状态管理st.session_state、按钮回调绑定高加新问诊项、改UI文案逻辑层agent_core.py智能体主循环接收用户输入 → 调用规则引擎 → 触发 LLM 推理 → 生成结构化响应中调整推理链长度、增加分支条件知识层health_rules.pyguidelines/目录临床指南硬编码IF-THEN、阈值表JSON、检查项目映射字典低但每次更新指南需重审打开app.py你会看到核心循环被封装为run_healthcare_agent()函数。它不直接调用llm.generate()而是先走SymptomRuleEngine().evaluate()—— 这是整个项目区别于普通 Chat UI 的关键设计所有 LLM 调用前必须通过规则引擎打标。例如当用户说“我胸口疼”规则引擎会立即匹配到chest_pain_risk标签并设置urgency_level2此时 LLM 的 system prompt 才会被动态注入“你是一名急诊分诊助手当前患者主诉胸痛已标记为中高危禁止给出‘多休息’等模糊建议必须列出3项需立即做的检查”。2.3 数据准备sample_report.json是什么为什么不能用 CSV 替代ZIP 包中sample_report.json是模拟一份结构化健康档案格式如下{ patient_id: P2024001, basic_info: { age: 52, sex: male, bmi: 28.3 }, lab_results: { fasting_glucose: 7.8, hba1c: 6.2, creatinine: 85 }, symptoms: [fatigue, nocturia], medications: [metformin] }注意三点lab_results字段名与guidelines/diabetes_thresholds.json中键名严格一致大小写、下划线否则规则引擎无法索引symptoms是标准化术语列表非自然语言来自data/symptom_vocab.json新增症状必须先在此注册它不是 CSV因为临床决策需要嵌套结构如“肾功能异常”需同时看creatinineeGFRurine_albuminCSV 无法表达这种关联性。强行转 CSV 会导致agent_core.py中get_relevant_guidelines()方法返回空列表。提示若你手头只有 Excel 体检表用pandas.read_excel()读入后务必按上述 JSON Schema 重构字典再json.dump()输出。别省这一步——我帮某社区卫生中心迁移时就因漏掉medications字段的空数组初始化应为[]而非None导致分诊逻辑跳过全部用药相互作用检查。3. 规则引擎怎么工作health_rules.py里的临床逻辑不是 if-else 堆砌很多人第一眼看到health_rules.py就想重写成 Pandas 向量化这是典型误判。医疗规则的本质是可解释、可审计、可单步调试而非追求微秒级性能。这个模块的设计哲学是每个规则必须能独立启用/禁用、有唯一 ID、附带指南出处、支持人工复核日志。下面拆解它的实际运作方式。3.1 规则定义Rule类的四个强制字段打开health_rules.py核心是Rule数据类from dataclasses import dataclass from typing import List, Optional dataclass class Rule: id: str # 必须全局唯一如 DM_FG_001 description: str # 人类可读描述空腹血糖≥7.0 mmol/L 判定为糖尿病高风险 condition: str # 可执行字符串如 lab_results[fasting_glucose] 7.0 guideline_ref: str # 指南引用如 CDS 2023 Sec 4.2 tags: List[str] None # 标签用于后续 LLM 提示注入如 [diabetes, urgent]关键在condition字段它不是 SQL而是 Python 表达式字符串由eval()在沙箱环境中安全执行见RuleEngine._safe_eval()。这意味着你可以写# 支持嵌套字典访问 basic_info[age] 40 and lab_results[hba1c] 5.7 # 支持函数调用白名单内 np.mean([lab_results[tg], lab_results[ldl]]) 4.5 # 支持布尔组合 symptoms.count(dyspnea) 0 or medications.count(beta_blocker) 0但eval()被严格限制禁用__import__、open、exec等危险函数只允许math、npnumpy、datetime模块子集。这是为了防止规则被恶意注入比如某条规则 condition 写成os.system(rm -rf /)。3.2 规则触发SymptomRuleEngine.evaluate()的三阶段流水线当你传入一份health_report字典evaluate()执行以下流程预处理阶段对lab_results中所有数值字段做单位归一化如将mg/dL转mmol/L并填充缺失值用guidelines/missing_value_imputation.json中定义的均值/中位数匹配阶段遍历全部激活规则self.active_rules对每条规则的condition字符串执行_safe_eval(report)返回True/False聚合阶段将所有True规则的id和tags合并为triggered_rules列表并计算综合风险分加权求和权重定义在guidelines/rule_weights.json。这个过程全程可 debug在app.py中插入st.write(engine.triggered_rules)就能实时看到哪些规则被触发、为什么触发。3.3 动态规则管理如何在不重启 Streamlit 的情况下增删规则app.py中有一段常被忽略的代码# 在 st.sidebar 中添加规则管理面板 if st.sidebar.checkbox(启用规则调试模式): rule_ids [r.id for r in engine.all_rules] selected st.sidebar.multiselect(选择启用的规则, rule_ids, defaultrule_ids) engine.set_active_rules(selected) # 动态更新 active_rules这意味着你可以在 Streamlit 运行时通过勾选框实时开关任意规则。比如在演示给社区医生看时临时关闭 “高血压合并糖尿病” 的复合规则只保留单病种规则观察分诊路径变化——这比改代码再重启快 10 倍。所有规则定义都存于guidelines/rules_catalog.json格式为[ { id: HTN_BP_001, description: 收缩压 ≥140 mmHg 且舒张压 ≥90 mmHg 判定为高血压, condition: lab_results[sbp] 140 and lab_results[dbp] 90, guideline_ref: CHS 2023 Table 2, tags: [hypertension, vital_signs] } ]提示新增规则时务必用jsonschema.validate()校验 JSON 结构包中utils/json_validator.py提供了校验脚本。曾有开发者因少写一个逗号导致整份rules_catalog.json解析失败engine.all_rules变为空列表整个智能体退化成回声机器人。4. LLM 推理不是“自由发挥”agent_core.py如何把规则输出喂给模型很多开发者以为 HealthcareAgent 的“智能”全靠 LLM其实恰恰相反LLM 在这里只是规则引擎的扩写器与话术优化器。它的输入不是原始用户提问而是规则引擎输出的结构化标记structured tags和风险摘要risk summary。agent_core.py的设计目标很明确不让 LLM 做判断只让它做表达。4.1 输入组装build_llm_prompt()的三段式模板build_llm_prompt()函数生成的 prompt 永远包含三个区块def build_llm_prompt(triggered_rules: List[Rule], risk_summary: str, user_input: str) - str: # 区块1角色与约束固定 system_prompt ( 你是一名持证家庭医生助理正在为社区居民提供健康指导。\n 【严格遵守】\n - 所有建议必须基于中国最新临床指南CDS/CHS/CSHP\n - 禁止使用可能大概建议咨询医生等模糊表述\n - 每条建议必须对应一条已触发的规则ID如 DM_FG_001\n ) # 区块2上下文动态注入 context f【已触发规则】{, .join([r.id for r in triggered_rules])}\n context f【风险摘要】{risk_summary}\n # 由规则引擎生成的纯文本摘要 context f【用户原始输入】{user_input}\n # 区块3指令固定 instruction ( 请生成一段面向患者的中文回复要求\n 1. 开头用一句话总结核心风险如您的空腹血糖已达糖尿病诊断标准\n 2. 分三点列出必须做的检查注明检查目的如糖化血红蛋白HbA1c评估近3个月平均血糖水平\n 3. 结尾给出明确行动项如请于48小时内至社区卫生服务中心完成OGTT检查\n 4. 全文不超过180字禁用英文缩写必须写口服葡萄糖耐量试验而非OGTT ) return system_prompt context instruction这个设计彻底规避了 LLM “幻觉诊断”。例如当规则引擎只触发了DM_FG_001空腹血糖超标prompt 中就不会出现任何关于“冠心病风险”的上下文LLM 自然无法编造相关内容。4.2 模型选择为什么默认用Qwen2-1.5B-Instruct而非 GPT-4ZIP 包config.yaml中默认模型为Qwen2-1.5B-Instruct原因很务实维度Qwen2-1.5B-InstructGPT-4-turbo本地推理速度A10G 上 23 tokens/sec含 prompt 编码无法本地运行需 API 调用延迟 ≥1.2s可控性通过 LoRA 微调可精准压制“建议就医”类泛化回答API 返回不可控常插入免责声明合规审计全部 token 生成在本地日志可全量留存API 请求体/响应体经第三方服务器无法满足医疗数据不出域要求成本单次推理成本 ≈ 0.0003 元电费单次 ≈ 0.02 元按 500 tokens 计更重要的是Qwen2-1.5B-Instruct经过医疗领域指令微调见finetune/medical_instruct_dataset.jsonl对“根据规则ID生成检查建议”这类任务准确率达 92.7%测试集test_medical_prompts.jsonl远超通用模型。4.3 输出解析parse_llm_response()如何确保结构化LLM 输出是自由文本但 HealthcareAgent 需要结构化字段存入数据库。parse_llm_response()用正则状态机双保险def parse_llm_response(text: str) - dict: result {summary: , checks: [], action_item: } # 第一步用正则提取三段容错设计即使格式乱也能捕获 summary_match re.search(r(?:开头|总结|一句话)[:\s]*([^\n]), text) result[summary] summary_match.group(1).strip() if summary_match else text[:60] # 第二步提取检查项匹配“1.”“2.”或“•”“-”开头的行 check_lines re.findall(r(?:^[1-9]\.|^[•\-]\s)([^\n]), text, re.MULTILINE) for line in check_lines[:3]: # 只取前三项 # 清洗移除编号、括号内说明保留检查名称 clean_name re.sub(r[(].*[)]|[\d\.•\-]\s*, , line).strip() result[checks].append(clean_name) # 第三步提取行动项匹配“请.*?于.*?内.*?完成.*?” action_match re.search(r请.*?于.*?内.*?完成.*?[。], text) result[action_item] action_match.group(0).strip() if action_match else 请尽快就诊 return result这个解析器不依赖 LLM 输出完美符合模板而是用启发式规则兜底。实测在 15% 的 LLM 输出格式异常时仍能提取出有效字段。提示如果你要接入其他模型如 GLM-4只需重写parse_llm_response()无需改动build_llm_prompt()或规则引擎——这就是分层设计的价值。5. 避坑指南我在 3 个真实部署现场踩过的 5 个具体坑别信“开箱即用”。这个 ZIP 包在实验室跑通和在社区卫生站稳定运行中间隔着至少 5 个血泪经验。以下是我在某高校附属社区中心、某县域医共体平台、某家庭医生签约系统三次落地时反复出现又必须解决的问题。5.1 现象Streamlit 页面空白浏览器控制台报WebSocket connection to ws://localhost:8501/_stcore/stream failed原因Streamlit 默认开启--server.enableWebsocketCompressiontrue但某些老旧医院内网防火墙会拦截压缩 WebSocket 帧导致连接中断。这不是代码 bug而是网络策略问题。解决启动时显式关闭压缩streamlit run app.py --server.port8501 --server.enableWebsocketCompressionfalse注意此参数必须写在--server.port之后顺序错误会被忽略。5.2 现象规则引擎始终不触发st.write(engine.triggered_rules)返回空列表原因sample_report.json中lab_results字段的键名与guidelines/rules_catalog.json中condition字符串里的键名不一致。常见错误包括glucosevsfasting_glucose、bmivsBMI大小写敏感、crvscreatinine。解决在app.py开头插入调试代码# 临时加入运行一次后删除 st.write(Report keys:, list(health_report.get(lab_results, {}).keys())) st.write(Rule condition example:, engine.all_rules[0].condition)对比两者键名统一为小写下划线命名如fasting_glucose。5.3 现象LLM 返回中文乱码如“æ£å¸¸”或提示词中出现方块符号原因config.yaml中model_path指向的模型文件夹含中文路径如D:\医疗AI\Qwen2-1.5BWindows 系统下 HuggingFace Transformers 加载 tokenizer 时编码异常。解决将模型文件夹移到纯英文路径如C:\models\qwen2-1.5b并在config.yaml中更新路径model_path: C:/models/qwen2-1.5b # 用正斜杠Windows 也认5.4 现象点击“开始问诊”按钮无反应st.button回调不执行原因Streamlit 的st.button是无状态组件每次 rerun 都会重置。如果在按钮回调函数中修改了st.session_state以外的状态如全局变量current_step 2下次 rerun 时该变量丢失导致逻辑断裂。解决所有跨 rerun 状态必须存入st.session_state# ❌ 错误用全局变量 current_step 1 if st.button(下一步): current_step 2 # 下次 rerun 重置为 1 # ✅ 正确用 session_state if current_step not in st.session_state: st.session_state.current_step 1 if st.button(下一步): st.session_state.current_step 25.5 现象pandas.read_json()报错ValueError: Trailing data原因sample_report.json文件末尾有多余空格或 BOM 头尤其用 Windows 记事本保存时。JSON 解析器拒绝解析。解决用 VS Code 或 Notepad 以 UTF-8 无 BOM 格式重新保存并删除文件末尾所有空行。或者用 Python 脚本清洗# clean_json.py with open(sample_report.json, rb) as f: raw f.read().strip() # 移除 UTF-8 BOMEF BB BF if raw.startswith(b\xef\xbb\xbf): raw raw[3:] with open(sample_report.json, w, encodingutf-8) as f: f.write(raw.decode(utf-8))6. 进阶技巧用health_rules.py实现“指南版本热切换”不用改一行代码医疗指南每年更新但重写所有规则、测试全部分支、重新部署——太重。HealthcareAgent 提供了一种更轻的方案通过配置文件切换整套规则集实现指南版本热切换。这不是概念而是 ZIP 包中已实现的机制。6.1 指南版本目录结构guidelines/v2023/与guidelines/v2024/解压后进入guidelines/目录你会看到guidelines/ ├── rules_catalog.json # 当前激活的规则清单软链接 ├── thresholds.json # 当前阈值表软链接 ├── v2023/ │ ├── rules_catalog.json # 2023版全部规则 │ └── thresholds.json # 2023版阈值 └── v2024/ ├── rules_catalog.json # 2024版全部规则新增“糖尿病前期干预”规则 └── thresholds.json # 2024版阈值HbA1c 诊断切点从5.7→5.5rules_catalog.json不是真实文件而是指向v2023/rules_catalog.json的符号链接Linux/macOS或快捷方式Windows。切换版本只需切换链接目标。6.2 切换命令三行命令完成指南升级# 进入 guidelines 目录 cd guidelines # 删除旧链接Linux/macOS rm rules_catalog.json thresholds.json # 创建指向 v2024 的新链接 ln -s v2024/rules_catalog.json rules_catalog.json ln -s v2024/thresholds.json thresholds.json # Windows 用户用 PowerShell管理员权限 Remove-Item rules_catalog.json, thresholds.json New-Item -ItemType SymbolicLink -Path rules_catalog.json -Target v2024\rules_catalog.json New-Item -ItemType SymbolicLink -Path thresholds.json -Target v2024\thresholds.json提示切换后无需重启 Streamlit因为SymptomRuleEngine在每次evaluate()时都会重新读取rules_catalog.json文件见health_rules.py第 87 行self.all_rules self._load_rules_from_file()。你甚至可以在医生演示过程中当场切换指南版本对比两条不同路径的分诊建议差异。6.3 版本兼容性保障rule_compatibility_checker.py包中utils/rule_compatibility_checker.py提供了自动化校验# 检查 v2024 规则是否与 v2023 存在冲突如相同 ID 但 condition 不同 python utils/rule_compatibility_checker.py --old guidelines/v2023/rules_catalog.json \ --new guidelines/v2024/rules_catalog.json输出示例CONFLICT: DM_FG_001 condition changed old: lab_results[fasting_glucose] 7.0 new: lab_results[fasting_glucose] 7.0 or lab_results[hba1c] 5.5 INFO: New rule DM_PRE_001 added (Diabetes prediabetes screening)这让你在升级前就清楚知道哪些规则逻辑变更需重点测试哪些是纯新增可直接上线。我坚持在每个部署现场都做这件事——不是因为怕出错而是因为医疗决策容不得“可能没问题”。当社区医生指着屏幕说“这条建议和去年不一样”我能立刻打开终端三行命令切回旧版再对比输出用事实说话。这种确定性才是技术真正服务于人的地方。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?