[开源] 合理用药规则改了三年,临床药师还在等排期:基于内容寻址与状态机的院内前置审核落地工具
2026/8/3 3:56:27 网站建设 项目流程

本项目把"合理用药规则的编辑、版本化、签核、发布、审计"五件事从信息科手里拿回临床药师桌上。院里常见的尴尬是:药师周二例会临时拍板"肝功能不全患者禁用头孢哌酮",真正落到 HIS 前置审核里要等到下周五,因为 SQL 存储过程攥在信息科手里,改一条规则得走排期、测试、上线流程。我们想让药师在 Web 配置台里用结构化表单改规则、拖拽表达式、保存草稿、提交签核、一键发布,全部在自己的浏览器里完成;交付形态是 Web 配置台 + 离线 CLI + JSON-LD 自检包 + PDF 报告,技术栈是 Fastify + TypeScript + PostgreSQL + React 18,模拟适配器用 FHIR MedicationRequest 子集跑通端到端。

角色与触发时刻

院里这套活儿绕不开四个人:临床药师、主任药师、信息科、审计员。临床药师平时在配置台用结构化表单写规则、保存为 draft;主任药师在签核页看 AI 预审提示、人工 approve 或驳回;信息科负责适配器注册、强制下线、上线阻断;审计员在飞检月导出 JSON-LD 自检包交给飞行检查组。

典型的周二例会故事线是这样走的:上午例会决定加一条"肝功能不全患者禁用头孢哌酮"的规则,药师进入配置台、选好 category 与 severity、拖拽表达式构造器拼出patient.hepatic_function in ['B','C']、保存为 draft、提交 testing;下午主任药师打开签核页、看到 AI 预审提示"与现有肝损规则存在 severity 冲突"、调整后批准 active;周三信息科一键发布,30 秒内所有在线适配器同步拉到新规则集,HIS 前置审核立刻生效;次月飞检,审计员导出 JSON-LD 自检包交给飞检组离线校验,包里含规则全版本链、全部签核记录、全部触发拦截记录,飞检组不用连任何生产数据库就能验自洽。

核心机制拆开看

五条主线支撑上面这套流程,我们一项一项拆开。

模块

职责

技术要点

DSL 强类型

药师拖拽式构造规则,结构化、可校验、防幻觉

JSONLogic 受限子集 + 强类型 AST + 深度类型推导

内容寻址

规则体规范化后算 SHA-256,存不可变版本对象

JSON canonicalize + SHA-256 hex

Git-like 版本化

分支 / tag / diff / 3-way merge / 一键回滚

不依赖真实 git,纯 Postgres JSONB + 父指针链表

工作流状态机

draft → testing → active → retired,加签核工单

状态转换守卫 + HMAC 签名 + AI 预审 stub

审计 append-only + JSON-LD

飞检时一键导出可校验包

链式 HMAC + schema.org 锚定 + PDF 报告

表达式构造器是药师每天打交道最多的组件。它在白名单内做嵌套式拖拽:操作符只能在==/!=/>/>=/</<=/in/!in/and/or/not/+/-/cat/coalesce里挑,变量只能在 14 条 drug / dose / department / patient 路径里挑,函数只能在 10 条白名单函数(如has_allergy/creatinine_clearance/is_liver_compromised)里挑。除了literal节点的字面值输入框,没有任何让药师自由键入 op/var/function 名的控件,前端有专门的测试断言锁定这个不变量。底部 Lint 面板防抖 300ms 调后端/v1/dsl/validate,客户端先做白名单静态校验,通过后再请求后端;后端不可达时降级为本地校验并提示DSL_BACKEND_UNREACHABLE

版本化与回滚:30 秒的故事线

上线 5 分钟发现"肝功能不全 + 头孢哌酮 → block"规则误伤了孕妇科室,需要立刻回滚到 v2(仅 block 肝功能 C),配置台不可达时仍可走 CLI 兜底,整个过程分四步:

# 步骤 1:查版本树,30 秒内确定目标 curl -sS http://localhost:4010/v1/versioning/list/R0001 | jq '.[] | {version_hash, state, message, author, created_at}' # → 当前 active = v3 (肝损 B + C block);目标 = v2 (肝损 C only block) # 步骤 2:diff 确认回滚内容 curl -sS -X POST http://localhost:4010/v1/versioning/diff \ -H 'Content-Type: application/json' \ -d '{"a_hash": "<v3-hash>", "b_hash": "<v2-hash>"}' | jq # → {added:[], removed:["when.0.in.0 == 'B'"], changed:["then.message_template"]} # 步骤 3:一键回滚 curl -sS -X POST http://localhost:4010/v1/versioning/rollback \ -H 'Content-Type: application/json' \ -d '{ "rule_id": "R0001", "target_hash": "<v2-hash>", "actor": "info-001", "reason": "v3 误伤孕妇科室(B 级患者包含部分正常孕检样本)" }' | jq # → {new_version_hash: "<v4-hash>", new_state: "active", # retired_hashes: ["<v3-hash>"], audit_event_id: "<audit-id>"} # 步骤 4:验证拦截解除 curl -sS -X POST http://localhost:4011/fhir/MedicationRequest \ -H 'Content-Type: application/fhir+json' \ -d @eval/fixtures/orders/hepatic-b.json # → verdict=pass(v3 时为 block,回滚后为 pass)

两个关键不变量必须守住:回滚不删任何历史(v1/v2/v3 仍存在,state 标 retired);回滚产生全新版本 v4,不修改 v3 的 content_address。审计链同时记录rule.version.rolled_back与旧 activerule.version.retired,飞检组可双向追溯。

适配器降级:上线不能"假成功"

适配器在 HIS / EMR / 医保前置审核节点是最终消费者。规则集上线前必须确认至少一个 active 适配器在线,否则就是"假上线",规则在 testing 阶段签核通过,却因为下游都收不到而形同虚设。

衍生状态由心跳新鲜度决定:online是心跳 ≤ 5 分钟、degraded是 5–30 分钟、offline是 > 30 分钟或失联、disabled是信息科主动停用。阈值定义在backend/src/modules/adapter/types.ts。当前 active 规则集中,如果没有任何 online 适配器的last_pulled_version命中,配置台顶部显示红色 banner"当前 N 条规则未下发到任何在线适配器",但不阻断发布;信息科可继续推进 release 但必须看到 banner。

真正阻断的是 testing → active 这道守卫:任何 active 适配器均处于 offline(或注册表为空)时,状态机抛出WorkflowError({ code: 'ADAPTER_OFFLINE_BLOCKS_PUBLISH', http: 409, details: { online_count, offline_count, disabled_count, unpushed_rules } }),上线按钮无法点击。恢复路径是信息科联系厂商恢复心跳 → 调用POST /v1/adapters/:id/heartbeat重新拉取版本 → 配置台unpushed_rules清零且 online_count ≥ 1 后自动解锁。

REST 端点速查:

路径

用途

GET /v1/adapters

列表(含derived_status

GET /v1/adapters/:id

单条(含derived_status

GET /v1/adapters/status

聚合:total / online / degraded / offline / disabled / unpushed_rules / by_protocol

POST /v1/adapters/:id/heartbeat

mock-adapter 主动调用

POST /v1/adapters/:id/enable

信息科启用 / 禁用

GET /v1/rules/active

mock-adapter hot-reload 端点(30s TTL)

凭证管理守住一条底线:credentials_ref字段只接受路径/URI 引用(vault://his/app-secret/env:HIS_TOKEN),绝不存明文。明文走 HashiCorp Vault / 云 KMS / 院方 KSM,bin/rxpc 与 mock-adapter 启动时读process.env但不写入任何 audit_event.payload。

飞检自检包:离线可验

次月飞检时,审计员向飞行检查组或医保稽核组提交一份"规则决策全过程"的可校验包。JSON-LD 自检包是唯一权威交付,飞检组离线校验自洽即可,不依赖任何在跑服务。

# 步骤 1:导出 JSON-LD 自检包(最近 30 天全量) curl -sS -X POST http://localhost:4010/v1/audit/export-bundle \ -H 'Content-Type: application/json' \ -d '{"from_ts": "2026-06-01T00:00:00Z", "to_ts": "2026-06-30T23:59:59Z"}' \ > audit-export-202606.json # 步骤 2:离线自检(无需联网) ./bin/rxpc verify-bundle ./audit-export-202606.json # → {ok: true}(manifest hash + HMAC + 内部 prev_hash 链均一致) # 步骤 3:同步出具 PDF 报告(线下归档) curl -sS -X POST http://localhost:4010/v1/audit/export-pdf \ -H 'Content-Type: application/json' \ -d '{"rule_id": "<uuid-1>", "from_ts": "...", "to_ts": "...", "generator": "audit-001"}' \ --output audit-report-202606.pdf # PDF 含 5 章节:Chain Verification / Rule Definition / Rule Versions / # Signoff Tickets / Action Counts

不可抵赖的根基是:每条audit_eventpayload_sha256由 SHA-256 算得,signature由 HMAC-SHA256(secret) 算得,任何字段修改都会被检测到。包内含规则定义 / 版本链 / 签核工单 / 审计事件 4 类节点,"谁、在何时、基于什么依据、做了什么变更"在包里自描述,无需查询生产数据库。飞检组如怀疑本系统有缺陷,可同时运行eval/bench/baseline.sql与本系统的eval/bench/eval.ts做对照,precision/recall 写入eval/bench/report.json作为质量佐证。

快速上手

cp .env.example .env docker compose up -d npm run migrate bash eval/demo.sh # 端到端 demo < 60s 跑通 8 步 npm run bench # 召回率 / 精确率 benchmark npm run coverage # 覆盖率 + mutation npm run bench:perf # 性能 benchmark(per-rule p95 < 5ms) open http://localhost:4012/ # Web 配置台 ./bin/rxpc validate test/fixtures/dsl/valid-rule.json # 离线 CLI 校验

端口分配:postgres 5432、backend (Fastify) 4010、frontend (Vite) 4012、mock-adapter (FHIR) 4011。OpenAPI UI 在http://localhost:4010/docs,OpenAPI JSON 在http://localhost:4010/docs/json

性能 benchmark 跑完后,业务吞吐的折算很直观:per-rule p95 实测 0.001 ms(预算 5 ms,快 5000 倍);end-to-end p95 < 0.01 ms;实测吞吐 > 100,000 医嘱/秒。信科主任问"能不能扛住早高峰 1 万医嘱/小时"时,1 万/小时 ≈ 3 医嘱/秒,余裕 3 万倍。

样例数据底座在data/samples/:30 药品 / 10 科室 / 50 规则 / 200 医嘱(seed=42 确定性生成),覆盖 5 类规则(抗菌药分级、溶媒禁忌、单次剂量上限、特殊人群、医保限制)。所有patient_hash=HMAC-SHA256(seed|salt).slice(0,16),无姓名 / 住院号 / 真实批号。规则来源字段映射到美康 / 大通 / 卫宁 / 国家版知识库的接口约定,本样例不复制任何真实知识库原文,真实接入需按院方采购合同处理凭证。

边界与范围

产品不重做合理用药知识库内容,美康 / 大通 / 卫宁 / 国家版均视为外部数据源;不内置与真实 HIS / EMR / 医保前置审核的厂商 SDK,mock-adapter用于自包含端到端,真实接入需 HIS 厂商按其协议自行实现。LLM 仅 stub(LLM_PROVIDER=stub|openai|claude可拔插),AI 预审提示在 MVP 阶段是占位实现。许可 MIT。

项目地址: https://github.com/nexorin9/rx-policy-station

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询