1. 项目概述:PediaMind儿科预诊决策系统
在儿科医疗场景中,家长对患儿症状的描述往往存在模糊性和主观性,而儿科用药又对年龄、体重、症状等指标有着极高的精确性要求。PediaMind系统正是为解决这一矛盾而设计的智能辅助决策平台,它通过多智能体博弈机制和强化检索技术,为家长提供可靠的预诊建议,同时确保所有诊断结论都有据可查。
这个项目最核心的创新点在于:
- 采用"红蓝对抗"机制,通过诊断Agent和评审Agent的多轮博弈确保医疗建议的安全性
- 开发双路检索系统,结合语义理解和关键词匹配,提高医学信息检索的准确性
- 实现完整的引文锚定功能,使每个诊断建议都能追溯到具体的医学文献来源
2. 系统架构设计
2.1 核心业务需求分析
PediaMind需要满足三个关键业务需求:
结构化体征采集
- 精确收集月龄(而非简单年龄)
- 体温记录精确到0.1℃
- 体重记录精确到0.1kg
- 主诉症状的标准化描述转换
多智能体博弈机制
- 诊断Agent提出初步方案
- 评审Agent进行医学合规性检查
- 最多3轮博弈,超时触发安全熔断
- 所有决策过程完整记录可审计
可验证的RAG系统
- 混合检索策略确保结果准确性
- 引文标注精确到具体章节和页码
- 检索结果与诊断建议强关联
2.2 技术栈选型与考量
接入层:FastAPI
- 选择原因:异步性能优异,自动生成OpenAPI文档
- 关键配置:启用Swagger UI,设置合理的请求超时
- 性能优化:使用uvicorn+asyncio实现高并发
认知层:LangGraph
- 核心价值:可视化工作流编排,内置状态管理
- 关键特性:MemorySaver实现断点续跑
- 扩展考虑:支持自定义节点和条件分支
数据层:混合检索方案
- ChromaDB:处理语义相似性检索
- rank_bm25:处理精确关键词匹配
- 融合策略:RRF算法平衡两种检索结果
表现层:Streamlit
- 优势:快速原型开发,内置丰富UI组件
- 定制能力:支持自定义CSS和交互逻辑
- 数据绑定:与后端API无缝对接
3. 多智能体博弈框架实现
3.1 状态机设计与数据流
PediaMindState是整个系统的核心数据总线,采用TypedDict确保类型安全:
python复制class PediaMindState(TypedDict, total=False):
# 输入阶段
user_input: str # 原始描述如"宝宝发烧三天"
triage_features: dict # 结构化数据如{"age_months":12,"temp":38.5}
# 检索阶段
rewritten_query: str # 医学标准查询如"婴幼儿发热处理指南"
rag_citations: list # 引文列表
# 博弈阶段
diagnosis_proposal: str # 初步诊断建议
review_feedback: dict # 评审结果
retry_count: int # 博弈轮次计数
# 输出阶段
final_report: str # 最终报告
状态流转遵循严格的生命周期:
- 输入 → 2. 分诊 → 3. 检索 → 4. 诊断 ⇄ 5. 评审 → 6. 定稿
3.2 智能体基类设计
采用抽象基类规范所有智能体的行为:
python复制class BaseAgent(ABC):
name: str = "BaseAgent"
@abstractmethod
async def run(self, state: dict) -> dict:
pass
async def __call__(self, state: dict) -> dict:
logger.info(f"[{self.name}]启动")
try:
result = await self.run(state)
logger.success(f"[{self.name}]完成")
return result
except Exception as e:
logger.error(f"[{self.name}]异常: {str(e)}")
raise
3.3 核心智能体实现
TriageAgent分诊智能体
- 功能:将"宝宝咳嗽有痰"转换为结构化症状描述
- 关键技术:正则匹配+医学词典映射
- 输出示例:
DiagnosisAgent诊断智能体
- 输入:体征数据+检索结果
- 处理:生成初步治疗方案
- 示例输出:"建议口服氨溴索口服液,每次2.5ml,每日2次"
ReviewAgent评审智能体
- 核查内容:
- 年龄禁忌(如<3月禁用某些药物)
- 剂量安全(按体重计算)
- 药物相互作用
- 驳回示例:
PlanAgent方案定稿智能体
- 整合所有信息生成最终报告
- 包含:诊断建议、用药指导、引文来源
- 格式:Markdown结构化输出
FallbackAgent熔断智能体
- 触发条件:博弈超限或严重异常
- 输出:建议立即就医的警示信息
- 设计原则:宁可保守也不冒险
3.4 工作流编排实现
LangGraph的状态机编排核心逻辑:
python复制def after_review_router(state: PediaMindState) -> str:
feedback = state.get("review_feedback", {})
retry_count = state.get("retry_count", 0)
if feedback.get("is_passed"):
return "proposal"
if retry_count >= MAX_RETRY:
return "fallback"
return "diagnosis"
工作流可视化表示:
code复制[输入] → [分诊] → [检索] → [诊断] → [评审]
↑____________↓ ↓
[熔断] ← [定稿]
4. 双路强化RAG系统
4.1 混合检索架构设计
稠密检索(ChromaDB)
- 优势:捕捉语义相似性
- 配置:使用all-MiniLM-L6-v2嵌入模型
- 调优:调整相似度阈值过滤低质量结果
稀疏检索(BM25)
- 优势:精确匹配医学术语
- 实现:基于rank_bm25库
- 优化:自定义词干提取和停用词表
4.2 RRF融合算法实现
python复制def _merge_rrf(chroma_results, bm25_results, k=60):
merged = {}
# Chroma结果处理
for rank, item in enumerate(chroma_results):
score = 1/(k + rank + 1)
merged[item.doc_id] = {"score":score, "source":"chroma"}
# BM25结果处理
for rank, item in enumerate(bm25_results):
score = 1/(k + rank + 1)
if item.doc_id in merged:
merged[item.doc_id]["score"] += score
merged[item.doc_id]["source"] = "both"
else:
merged[item.doc_id] = {"score":score, "source":"bm25"}
return sorted(merged.items(), key=lambda x: -x[1]["score"])
4.3 二次精排策略
精排考虑因素:
- RRF基础分
- 关键词命中加分
- 双通道召回加分
- 来源权威性加权
- 出版时间衰减因子
精排公式示例:
code复制最终分数 = RRF分 × 1.2
+ 关键词命中数 × 0.5
+ (双通道召回 ? 1.0 : 0)
+ 权威系数(0.5-1.5)
+ 时效系数(近3年出版 ? 0.3 : 0)
4.4 知识锚定模型
python复制class CitationAnchor(BaseModel):
anchor_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
text: str
source: CitationSource
relevance: float = Field(ge=0, le=1)
def format_citation(self) -> str:
return f"[{self.source.source_name} {self.source.chapter} p.{self.source.page}]"
前端渲染效果示例:
code复制建议使用布洛芬混悬滴剂([《儿科用药指南》第5章 p.32])
5. 业务API与前端实现
5.1 FastAPI接口设计
诊断请求模型:
python复制class DiagnosisRequest(BaseModel):
description: str = Field(..., min_length=10)
age_months: int = Field(..., gt=0)
temperature: float = Field(..., ge=35.0, le=42.0)
weight: float = Field(..., gt=0)
异步处理端点:
python复制@app.post("/diagnose")
async def diagnose(request: DiagnosisRequest):
state = await _workflow.ainvoke({
"user_input": request.description,
"triage_features": {
"age_months": request.age_months,
"temp": request.temperature,
"weight": request.weight
}
})
return state["final_report"]
5.2 Streamlit前端关键实现
体征采集表单:
python复制with st.sidebar:
age = st.number_input("月龄", min_value=1, max_value=216)
temp = st.number_input("体温(℃)", min_value=35.0, max_value=42.0, step=0.1)
weight = st.number_input("体重(kg)", min_value=0.1, step=0.1)
symptoms = st.text_area("症状描述", help="请详细描述症状及持续时间")
智能体日志展示:
python复制with st.expander("诊断过程追踪"):
for log in state.get("agent_logs", []):
st.text(f"[{log['time']}] {log['agent']}: {log['message']}")
if log.get("data"):
st.json(log["data"], expanded=False)
引文高亮渲染:
css复制.citation {
background-color: #f0f7ff;
border-radius: 4px;
padding: 0 2px;
border-left: 3px solid #4a90e2;
}
6. 开发经验与优化建议
6.1 关键调试经验
LangGraph状态管理
- 问题:状态字典字段变更导致工作流中断
- 解决:使用TypedDict+total=False实现渐进式类型
- 建议:为每个状态变更添加版本标记
混合检索性能
- 发现:BM25检索成为性能瓶颈
- 优化:预建索引+结果缓存
- 效果:响应时间从1200ms降至400ms
智能体博弈死锁
- 场景:诊断与评审陷入无限循环
- 解决:引入retry_count硬性限制
- 监控:添加prometheus指标采集
6.2 典型问题排查指南
| 问题现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 检索结果不相关 | 查询重写失败 | 1. 检查rewritten_query内容 2. 验证嵌入模型质量 |
| 评审总是驳回 | 医学规则过严 | 1. 检查ReviewAgent日志 2. 验证年龄/体重单位 |
| 前端渲染错乱 | 引文格式异常 | 1. 捕获CitationAnchor异常 2. 添加schema验证 |
| 工作流卡死 | 条件路由错误 | 1. 检查after_review_router 2. 验证状态字段完整性 |
6.3 后续优化方向
-
知识库扩展
- 导入《尼尔森儿科学》等权威资料
- 增加药品说明书结构化数据
- 建立症状-诊断-治疗的关联图谱
-
智能体增强
- 接入医疗大模型API
- 增加循证医学证据检索
- 实现多专家投票机制
-
系统健壮性
- 添加输入合理性校验
- 实现工作流断点续跑
- 完善监控告警系统
在实际开发过程中,我们发现医疗AI系统最关键的不仅是技术实现,更是安全机制的层层把关。每个智能体的决策都必须有明确的医学依据,任何不确定的情况都必须触发熔断机制。这种保守策略虽然可能降低系统"智能感",但在医疗领域,安全永远是第一位的考量。
