用药安全 Agent 答对了还不够:药物知识 MCP 的日志该写什么

4 阅读6分钟

夜班门诊,医生在 EHR 里问:这两个药能不能合用?

Agent 很快返回:建议避免合用,存在相互作用风险。第二天,药师想看触发规则,信息科查 MCP 调用日志,质控部门追问知识库版本和更新时间。系统里只剩一段自然语言回答。

缺少标准药品 ID、剂量、给药途径、相互作用等级、证据来源版本,也没有记录患者肾功能、妊娠状态、过敏史是否参与判断,更看不到医生最后采纳、修改还是覆盖提醒。

图1:EHR 处方辅助界面草图。左侧是医嘱编辑区,中间显示 Agent 风险提示,右侧固定展示 source_version、source_updated_at、rule_snapshot_id、retrieved_at、clinician_action、override_reason;底部有“药师复核队列”和“知识检查失败”状态入口。

图1:EHR 处方辅助界面草图。左侧是医嘱编辑区,中间显示 Agent 风险提示,右侧固定展示 source_version、source_updated_at、rule_snapshot_id、retrieved_at、clinician_action、override_reason;底部有“药师复核队列”和“知识检查失败”状态入口。

MCP 调用要落成审计事件

贴近医院现场的流程可以这样拆:医生开立医嘱;处方系统把商品名、院内简称、历史编码映射到标准药品 ID;Agent Orchestrator 读取最小患者上下文;药物知识 MCP 接收结构化请求;DDI 规则服务返回风险等级、证据来源和规则快照;EHR 决定弹窗、非阻断提醒或静默记录;医生确认、修改或覆盖;药师复核看到同一条事件。

药品 ID 映射常比模型回答难。同一种药可能有商品名、通用名、院内码、医保码、外院带入名称。海外系统还会遇到 RxNorm、ATC,本地还要对接院内药品主数据。映射置信度低时,应要求人工选择标准名,或把医嘱送入药师复核,不能继续生成“可用/不可用”的结论。

MCP tool schema 需要收紧输入:药品标准 ID、剂量、route、年龄段、eGFR 分层、妊娠状态、过敏史、当前用药列表版本都应有明确类型。调用方声明可接受的知识库版本范围,MCP 返回实际命中的 source_versionrule_snapshot_id。重复提交依赖 request_id 幂等,避免生成两条互相矛盾的审计事件。

字段用途
drug_id / standard_name固定药品身份,减少商品名、简称、历史编码混淆
dose / route剂量和给药途径,部分规则需要参与判断
interaction_severity / evidence_level风险等级和证据强度分开保存
source_version / source_updated_at知识库版本和更新时间
rule_id / rule_snapshot_id命中规则和当时规则快照
patient_context_hash参与判断的患者上下文指纹
retrieved_at / clinician_action调用时间和医生处理状态
override_reason覆盖提醒时的原因

patient_context_hash 不应塞进完整病历。可采用字段白名单:年龄段、eGFR 分层、妊娠状态、过敏史标记、当前用药列表版本。按固定顺序规范化、脱敏、加盐哈希,盐值由院内安全域管理。审计人员能验证当时哪些上下文参与判断,不能从日志反推出病历内容。

图2:调用链草图。EHR/处方系统 → 药品主数据映射 → Agent Orchestrator → 药物知识 MCP → DDI 规则服务 → EHR 弹窗/静默审计 → 医生确认/药师复核。

图2:调用链草图。EHR/处方系统 → 药品主数据映射 → Agent Orchestrator → 药物知识 MCP → DDI 规则服务 → EHR 弹窗/静默审计 → 医生确认/药师复核。

最小实现片段

以下是模拟审计事件字段设计,不对应真实患者、真实药品或真实检索结果。

{
  "event_type": "medication_knowledge_check",
  "request_id": "rx-20260101-abcdef",
  "tool_schema_version": "ddi.mcp.v1",
  "drug_pair": [
    {"drug_id": "LOCAL_DRUG_001", "dose": "masked", "route": "oral"},
    {"drug_id": "LOCAL_DRUG_002", "dose": "masked", "route": "iv"}
  ],
  "patient_context_hash": "sha256:...",
  "context_fields": ["age_band", "egfr_band", "pregnancy", "allergy_flag", "med_list_version"],
  "rule_id": "DDI_RULE_0001",
  "rule_snapshot_id": "ddi-rules-2026-01-01T00:00:00Z",
  "interaction_severity": "major",
  "evidence_level": "label",
  "source_version": "kb-2026.01",
  "source_updated_at": "2026-01-03T08:00:00Z",
  "retrieved_at": "2026-01-10T19:32:11Z",
  "clinician_action": "pharmacist_review",
  "override_reason": null,
  "error_code": null
}

失败状态也要进入协议。常见错误码包括 mapping_failedknowledge_timeoutcontext_missingversion_unsupportedrule_service_unavailable。MCP 超时不能写成“未发现风险”;药品映射失败不能让模型猜标准名;患者上下文缺失时,日志应记录缺哪些字段,并进入补录或药师复核流程。

证据来源要在上线前整理。药品说明书、监管标签、临床指南、系统评价、真实世界研究、院内规则,更新频率和适用范围差异很大。做规则评审时,可以用 超能文献 做中文检索,并追踪 PubMed / OpenAlex 来源,围绕 drug-drug interaction、clinical decision support、alert fatigue、medication safety、MCP healthcare workflow 建候选材料。它适合文献整理和来源追踪,不能替代医生或药师判断。

少弹无效窗,也要记录没弹的理由

DDI 系统很容易把医生训练成“关闭弹窗的人”。同一条规则命中,处理方式应受严重程度、证据等级、患者上下文完整度、临床可操作性共同影响。

举个模拟分流例子:两种药物命中高严重度规则,证据来自监管标签,患者上下文完整,且有明确替代方案,EHR 可以进入阻断式弹窗,要求医生修改或写明覆盖原因。若严重度高、证据强,但 eGFR 或妊娠状态缺失,系统应提示补齐字段,并进入药师复核。若风险中等、证据来自较低等级研究,且临床上只能加强监测,可做非阻断提醒。若低严重度、证据弱、缺少可操作路径,可静默审计,但日志必须保存 suppressed_reason,供规则团队后续调参。

图3:提醒分流界面草图。横轴为临床可操作性,纵轴为风险等级;四个区域分别对应阻断弹窗、补齐上下文、非阻断提醒、静默审计,每个区域下方显示审计字段。

图3:提醒分流界面草图。横轴为临床可操作性,纵轴为风险等级;四个区域分别对应阻断弹窗、补齐上下文、非阻断提醒、静默审计,每个区域下方显示审计字段。

医疗安全边界也要写进界面和权限。模型、MCP 工具、文献产品只能做证据入口、文献追踪、研究审计、风险分级和来源追溯;诊断、处方、停药、换药等决定由具备资质的临床人员确认。EHR 里应把“已提示、已确认、已修改、已覆盖、需药师复核、知识检查失败”做成结构化状态,不能把一段模型回答直接塞进病历。

回到夜班那句“这两个药能不能合用”,麻烦来自回答和审计事实脱节。第二天药师、信息科、质控部门追问的是同一组记录:命中了哪个标准药品 ID,source_version 是多少,rule_snapshot_id 指向哪次规则快照,患者上下文缺了哪些字段,医生最后做了什么处理,覆盖提醒有没有原因。

下一步可以从 50 条高频 DDI 场景开始:整理本院药品主数据映射,给每条规则补齐版本、证据等级和适用范围;把 mapping_failedknowledge_timeoutcontext_missing 接入 EHR 状态机;抽样回放旧事件,检查日志能否支撑药师复核和质控追踪。先把这些跑通,再扩展 Agent 工作流。