健康咨询 Agent 工作流设计
医疗健康场景下 AI 咨询 Agent 的工作流设计:为什么不能用纯 LLM 自由对话、意图分类方案选型、阶段推进条件设计、安全检测插入点。
#type / concept
#status / growing
#tech / ai
[!info] related notes
- 前置概念: Function Calling, Agent 执行闭环
- 安全系统: Red Flag 检测器, RAG Faithfulness 校验
- 知识检索: 意图感知 RAG 重排
健康咨询 Agent 工作流设计
这篇解决什么问题
用 AI 做健康咨询,最简单的方案是”用户说什么,LLM 就回什么”。但在医疗健康场景,纯自由对话有几个致命问题:
- 信息收集不可控 — 用户说”我肩膀疼”,LLM 可能直接给诊断,跳过必要的信息收集
- 阶段不可控 — 用户还没确认诊断,LLM 就生成治疗方案
- 安全检测无处插入 — 没有明确的”检测点”来判断是否有危险症状
- 质量不可审计 — 完全依赖 LLM 的”判断”,无法验证是否收集了足够信息
所以需要一个显式的工作流来控制对话的推进。
核心设计:四阶段状态机
collecting → analysis_ready → diagnosis_confirmed → treatment_generated
(收集) (可分析) (确认诊断) (生成方案)
每个阶段有明确的进入条件和允许的动作:
| 阶段 | 进入条件 | 允许的动作 |
|---|---|---|
| collecting | 新会话 | 收集症状、追问细节 |
| analysis_ready | 至少一个症状 + 一个细节 | 生成诊断、继续追问 |
| diagnosis_confirmed | 用户确认诊断 | 生成治疗方案 |
| treatment_generated | 方案已生成 | 讨论方案、复评 |
关键决策:阶段推进必须有硬性条件,不能靠 LLM “觉得信息够了”。
意图分类:方案选型
用户消息进来后,第一步是分类意图(用户想干什么)。三种方案:
方案 A:正则关键词匹配
PATTERNS = [
(r"(分析|诊断|判断|看看)", REQUEST_ANALYSIS, 0.8),
(r"(确认|同意|是的|对)", CONFIRM_DIAGNOSIS, 0.8),
(r"(方案|改善|治疗|训练)", REQUEST_TREATMENT, 0.8),
]
- 优点:极快(<1ms)、确定性、可审计
- 缺点:覆盖面有限、无法理解复杂表述
- 适用:意图类型少、表述相对固定的场景
方案 B:LLM 分类
把用户消息和意图列表发给 LLM,让它返回分类结果。
- 优点:理解复杂表述、覆盖面广
- 缺点:慢(1-3s)、有成本、结果不确定
- 适用:意图类型多、表述灵活的场景
方案 C:混合方案(推荐)
先用正则快速匹配高置信度意图,匹配不到再用 LLM:
def classify_intent(message, context):
# 快速路径:正则匹配
for pattern, intent, confidence in PATTERNS:
if re.search(pattern, message):
if confidence >= 0.7:
return intent
# 慢速路径:LLM 分类
return await llm_classify(message, context)
这样大多数常见意图走快速路径,只有模糊表述才调 LLM。
信息收集完整性判断
不要用”对话轮数”判断信息够不够,要用结构化数据判断:
def is_info_sufficient(extracted_info: list[Symptom]) -> bool:
for symptom in extracted_info:
if not symptom.body_part:
continue
# 至少有部位 + 一个维度的细节
has_detail = any([
symptom.symptom_type, # 疼痛/酸胀/麻木
symptom.duration, # 持续时间
symptom.trigger, # 触发场景
symptom.severity, # 严重程度
])
if has_detail:
return True
return False
设计要点:
- 用 Function Calling 提取结构化症状,而不是从文本里猜
- 提取是增量的——每轮对话都可能补充新信息
- 完整性检查基于结构化字段,不是”用户说了几句话”
Function Calling 提取症状
SYMPTOM_TOOL = {
"name": "extract_symptom_info",
"description": "从对话中提取结构化症状信息",
"parameters": {
"type": "object",
"properties": {
"body_part": {"type": "string", "description": "身体部位"},
"symptom_type": {"type": "string", "description": "症状类型"},
"duration": {"type": "string", "description": "持续时间"},
"trigger": {"type": "string", "description": "触发场景"},
"severity": {"type": "string", "description": "严重程度"},
},
"required": ["body_part"],
},
}
LLM 在对话过程中自动调用这个工具,提取到的结构化数据用于:
- 驱动阶段推进(is_info_sufficient)
- 注入后续 prompt(让 LLM 知道已经收集了什么)
- 渲染到 UI(人体可视化面板)
安全检测插入点
Red Flag 检测必须在 LLM 生成回复之前 执行:
用户消息
↓
Red Flag 检测 → (命中) → 立即推送安全警告 SSE 事件
↓
意图分类 → 动作决策 → RAG 检索 → LLM 生成 → 推送回复
不能依赖 LLM 自己判断”用户描述的症状很严重”——LLM 可能漏判,而且用户需要在看到 LLM 回复之前就看到安全警告。
完整的单轮处理流程
1. 收到用户消息
2. Red Flag 检测(关键词匹配,<1ms)
3. 如果有 red flag → 推送 red_flag SSE 事件
4. 意图分类(正则 + LLM 混合)
5. 动作决策(意图 + 当前阶段 → 下一步动作)
6. RAG 检索(带意图感知重排)
7. Function Calling 提取症状
8. LLM 生成回复(流式)
9. 推送 text / extracted_info / phase_changed SSE 事件
10. 更新会话状态
与纯 LLM 方案的对比
| 维度 | 纯 LLM | 显式工作流 |
|---|---|---|
| 信息收集 | 依赖 LLM “判断” | 硬性条件检查 |
| 阶段推进 | LLM 自行决定 | 状态机控制 |
| 安全检测 | LLM 自己判断 | 独立模块,先于 LLM |
| 可审计性 | 黑盒 | 每步有决策依据 |
| 灵活性 | 极高 | 受限于预定义流程 |
| 开发成本 | 低 | 中等 |
推荐:医疗健康场景用显式工作流,一般聊天场景用纯 LLM 就够。
常见错误
用对话轮数判断信息够不够
# ❌
if len(messages) >= 6:
generate_diagnosis()
# ✅
if is_info_sufficient(extracted_info):
generate_diagnosis()
让 LLM 决定是否推进阶段
# ❌ prompt 里写"你觉得信息够了就生成诊断"
# LLM 可能在第 1 轮就"觉得够了"
# ✅ 代码里检查结构化数据
if not is_info_sufficient(extracted_info):
return ask_follow_up()
Red Flag 检测放在 LLM 之后
# ❌ 先让 LLM 回复,再检查 red flag
response = await llm.chat(messages)
if has_red_flag(user_message):
response = add_warning(response)
# ✅ 先检测,再生成
if has_red_flag(user_message):
yield red_flag_event(...)
response = await llm.chat(messages) # LLM 回复正常内容