[一] Debug 调试总结 & 调度流程深入讲解


一、Debug 调试总结

你调试的内容 (debug_agent.py)

debug_agent.py 手动按顺序调用了 5 个 Agent:
步骤 函数 测试内容
1 test_intake() 将原始文本 → 结构化 patient_info
2 test_diagnosis() patient_info → 差异化诊断 + needs_more_info
3 test_treatment() diagnosis → 治疗方案(含药物相互作用检查)
4 test_coding() diagnosis + treatment_plan → ICD-10/DRGs 编码
5 test_audit() 全量数据 → HIPAA 合规报告

核心发现:每个 Agent 都是纯函数,输入是 ClinicalState,输出是 dict(要更新的状态字段)。


二、Pipeline 调度流程详解

2.1 核心文件关系

routes.py (API入口)
    ↓ POST /api/v1/clinical/analyze
clinical_pipeline.py (LangGraph 图定义)
    ↓
5个 Agent (intake/diagnosis/treatment/coding/audit)
    ↓
state.py (ClinicalState 数据流转)

2.2 clinical_pipeline.py — 图结构拆解

第 1 步:构建节点 (add_node)

workflow = StateGraph(ClinicalState)

workflow.add_node("intake", intake_agent)        # 节点名 = Agent函数
workflow.add_node("diagnosis", diagnosis_agent)
workflow.add_node("treatment", treatment_agent)
workflow.add_node("coding", coding_agent)
workflow.add_node("audit", audit_agent)

每个 Agent 是一个 LangGraph Node"intake" 只是节点名称,实际执行的是 intake_agent 函数。

第 2 步:定义入口和边 (edge)

workflow.set_entry_point("intake")   # 起点:intake

workflow.add_edge("intake", "diagnosis")      # intake 完成后自动去 diagnosis
workflow.add_edge("treatment", "coding")       # treatment 完成后自动去 coding
workflow.add_edge("coding", "audit")           # coding 完成后自动去 audit
workflow.add_edge("audit", END)                # audit 完成后结束
第 3 步:条件路由 (conditional_edges) — 关键

workflow.add_conditional_edges(
    "diagnosis",                          # 监听 diagnosis 节点
    _route_after_diagnosis,               # ← 路由决策函数
    {
        "intake": "intake",               # needs_more_info=True → 回到 intake
        "treatment": "treatment",         # needs_more_info=False → 去 treatment
    },
)

_route_after_diagnosis 函数 (clinical_pipeline.py:22-30):

def _route_after_diagnosis(state: ClinicalState) -> str:
    if state.needs_more_info:             # Diagnosis Agent 设置的标志
        return "intake"                   # → 循环回去补充信息
    return "treatment"                    # → 正常流程继续

这是 Diagnosis ↔ Intake 循环 的实现:当 needs_more_info=True 时,Graph 会回到 Intake 重新收集信息。

第 4 步:编译 (compile)

return workflow.compile(checkpointer=MemorySaver())
  • MemorySaver():内置内存持久化,支持通过 thread_id 恢复状态
  • 编译后生成 CompiledStateGraph 实例,调用 invoke() 执行

2.3 状态流转 (State Flow)

┌─────────────────────────────────────────────────────────────────────┐
│                        ClinicalState 流转                           │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  raw_input (患者主诉)                                                │
│       │                                                             │
│       ▼                                                             │
│  ┌─ IntakeAgent ──────────────────────────────────────────────────┐ │
│  │ intake_agent()                                                │ │
│  │   读取: raw_input                                              │ │
│  │   写入: patient_info, current_agent                            │ │
│  └────────────────────────────────────────────────────────────────┘ │
│       │                                                             │
│       ▼                                                             │
│  ┌─ DiagnosisAgent ──────────────────────────────────────────────┐ │
│  │ diagnosis_agent()                                             │ │
│  │   读取: patient_info                                           │ │
│  │   写入: diagnosis, needs_more_info, current_agent              │ │
│  │                                                             │ │
│  │   ┌─ needs_more_info=True? ──────────────────────────────┐   │ │
│  │   │              ↓ 是                                      │   │ │
│  │   │         回到 IntakeAgent (循环)                        │   │ │
│  │   └──────────────────────────────────────────────────────────┘   │ │
│  │              ↓ 否                                               │ │
│  └────────────────────────────────────────────────────────────────┘ │
│       │                                                             │
│       ▼                                                             │
│  ┌─ TreatmentAgent ─────────────────────────────────────────────┐ │
│  │ treatment_agent()                                            │ │
│  │   读取: patient_info, diagnosis                               │ │
│  │   写入: treatment_plan, current_agent                        │ │
│  └───────────────────────────────────────────────────────────────┘ │
│       │                                                             │
│       ▼                                                             │
│  ┌─ CodingAgent ────────────────────────────────────────────────┐ │
│  │ coding_agent()                                               │ │
│  │   读取: diagnosis, treatment_plan                            │ │
│  │   写入: coding_result, current_agent                         │ │
│  └───────────────────────────────────────────────────────────────┘ │
│       │                                                             │
│       ▼                                                             │
│  ┌─ AuditAgent ─────────────────────────────────────────────────┐ │
│  │ audit_agent()                                                │ │
│  │   读取: patient_info, diagnosis, treatment_plan, coding_result │
│  │   写入: audit_result, current_agent                           │ │
│  └────────────────────────────────────────────────────────────────┘ │
│       │                                                             │
│       ▼                                                             │
│     [END]                                                           │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

2.4 每个 Agent 的内部逻辑 (以 IntakeAgent 为例)

def intake_agent(state) -> dict:
    # 1. 读取输入
    raw = state.raw_input
    
    # 2. 调用 LLM(DashScope 阿里云)
    llm = ChatOpenAI(
        model=settings.openai_model,      # "qwen-plus"
        api_key=settings.openai_api_key,
        base_url=settings.openai_base_url,
        temperature=0.1,
    )
    
    messages = [
        SystemMessage(content=INTAKE_SYSTEM_PROMPT),  # 结构化提取指令
        HumanMessage(content=f"Patient narrative:\n\n{raw}"),
    ]
    
    response = llm.invoke(messages)       # 3. LLM 推理
    content = response.content.strip()
    
    # 4. 解析 JSON 输出
    patient_data = json.loads(content)
    
    # 5. 返回要更新的状态字段
    return {
        "patient_info": patient_data,     # ← 写入 state.patient_info
        "current_agent": "intake",         # ← 标记当前执行者
    }

2.5 API 调用链

当你调用 POST /api/v1/clinical/analyze

FastAPI routes.py
    ↓
pipeline = get_pipeline()                 # 获取编译好的图
    ↓
result = pipeline.invoke(
    {"raw_input": req.patient_description},
    config={"configurable": {"thread_id": req.thread_id}},
)
    ↓
返回: {
    patient_info: {...},
    diagnosis: {...},
    treatment_plan: {...},
    coding_result: {...},
    audit_result: {...},
    errors: []
}

三、5 个 Agent 职责速查表

Agent 输入 输出 核心能力
Intake raw_input patient_info 文本→结构化(FHIR格式)
Diagnosis patient_info diagnosisneeds_more_info 差异化诊断 + 置信度
Treatment patient_infodiagnosis treatment_plan 药物相互作用检查(DDI)
Coding diagnosistreatment_plan coding_result ICD-10 + DRGs 编码
Audit 所有字段 audit_result HIPAA 合规 + PHI脱敏

四、调试建议

设置断点的关键位置

文件:行号 目的
intake_agent.py:98 llm.invoke() — 看 LLM 输入输出
diagnosis_agent.py:97 同上
clinical_pipeline.py:22-30 _route_after_diagnosis() — 看条件路由逻辑
routes.py:75 pipeline.invoke() — 看整体入口

快速验证命令

# 启动服务
cd /home/zxb/work/medical-multi-agent-system/python && source .venv/bin/activate && uvicorn src.api.main:app --reload --port 8000

# 发送测试请求
curl -X POST http://localhost:8000/api/v1/clinical/analyze \
  -H "Content-Type: application/json" \
  -d '{"patient_description": "45-year-old male with fever for 3 days"}'
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐