第九章 案例研究:一个完整的 Rust 医疗 AI Harness 实现

9.1 引言:从零件到整机
前八章分别铸造了医疗 AI Harness 的各个组件:可靠的运行时底盘(第二章)、类型安全的医疗数据层(第三章)、与 Python 推理服务的互操作桥梁(第四章)、上下文-工具-记忆的编排核心(第五章)、多层护栏与安全控制器(第六章)、不可篡改的审计追踪(第七章)、以及自动化的评测体系(第八章)。这些组件如同精密加工的齿轮,单独看各自闪耀,但只有在咬合为一个整体时,才能真正输出临床可用且安全可信的 AI 辅助能力。
本章将把这些齿轮组装起来,呈现一个虽然简化但五脏俱全的医疗 AI Harness 实例——“循证临床指南问答系统”(Evidence-Based Guideline Q&A Harness)。我们将从需求定义开始,搭建项目骨架,逐步实现各个模块,最终形成一个可运行、可评测、可审计的最小化产品。这既是前述理论的工程落地,也为读者提供了一个可复制、可裁剪的起点。
本章刻意保持代码的完整性,但为了篇幅合理,某些辅助函数和完整配置会以伪代码或关键片段呈现。完整的代码库可伴随本书发布在开源仓库中。
9.2 系统概览与需求
我们的示例系统面向以下场景:临床医生在电子病历中查看某患者病历时,通过 CDS Hooks 机制触发 AI 辅助。医生提问:“根据最新指南,该患者的高血压用药方案需要调整吗?” Harness 从 FHIR 服务器获取患者当前用药和检验结果,在内部知识库中检索相关指南片段,调用大模型生成建议,经过多层护栏检查,最终以“建议卡片”形式返回给 EMR,同时记录完整的审计日志。
核心功能需求:
- 接收符合 CDS Hooks 规范的 HTTP 请求。
- 通过 FHIR API 获取患者 MedicationStatement 和 Observation 资源。
- 将患者数据脱敏并构建上下文,调用向量数据库检索相关指南。
- 编排 Agent:模型可决定是否调用药物相互作用查询工具。
- 对模型输出执行规则护栏和事实一致性护栏。
- 将最终建议包装为标准 CDS Hooks 响应,附加引用来源。
- 全链路审计记录。
- 独立安全控制器监控高风险词汇。
- 支持通过评测套件验证安全性。
非功能需求:p99 延迟 < 3 秒(不含推理时间),支持 100 并发请求,审计日志不可篡改,所有秘密加密存储。
9.3 项目结构与依赖
我们采用 Rust 的 workspace 组织多 crate 项目,便于单独测试和复用。
medical-harness/
├── Cargo.toml # workspace 配置
├── harness-core/ # 核心业务逻辑:编排、护栏、工具、状态
├── harness-server/ # axum HTTP 服务、中间件、配置
├── harness-fhir/ # FHIR 客户端与类型
├── harness-inference/ # gRPC 推理客户端
├── harness-eval/ # 评测 CLI 工具
├── harness-audit/ # 审计系统(Audited<T>、审计写入器)
├── migrations/ # 数据库迁移
├── config/ # 示例配置文件
├── tests/ # 集成测试与评测套件
└── proto/ # Protobuf 定义
关键依赖在 workspace Cargo.toml 中统一管理版本:
[workspace.dependencies]
tokio = { version = "1.39", features = ["full"] }
axum = "0.7"
tower = "0.4"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
sqlx = { version = "0.8", features = ["runtime-tokio", "postgres", "uuid", "chrono"] }
uuid = { version = "1", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }
tonic = "0.12"
tracing = "0.1"
tracing-subscriber = "0.3"
aho-corasick = "1"
regex = "1"
thiserror = "1"
async-trait = "0.1"
9.4 配置与启动
配置文件 config/default.toml 定义所有可变参数:
[server]
port = 8080
request_timeout_secs = 30
[database]
url = "postgres://user:pass@localhost:5432/harness"
max_connections = 20
[inference]
endpoint = "http://vllm:50051"
default_model = "medllama-v2"
timeout_secs = 60
max_concurrent = 10
[fhir]
base_url = "https://fhir.example.com"
auth_header = "Bearer ${FHIR_TOKEN}"
[guardrails]
input_max_length = 2000
jailbreak_patterns_file = "config/jailbreak_patterns.txt"
enable_factual_check = true
[safety]
emergency_keywords = ["chest pain+sweating", "suicide", "self-harm", "difficulty breathing+wheezing"]
[audit]
batch_size = 100
flush_interval_ms = 1000
使用 figment 加载配置,并用 secrecy 包装秘密字段。在 main.rs 中初始化所有子系统并启动服务器。
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// 加载配置
let settings = Settings::load()?;
// 初始化 tracing
init_tracing(&settings);
// 创建数据库连接池
let pool = sqlx::postgres::PgPoolOptions::new()
.max_connections(settings.database.max_connections)
.connect(settings.database.url.expose_secret())
.await?;
sqlx::migrate!().run(&pool).await?;
// 初始化 FHIR 客户端
let fhir_client = FhirClient::new(&settings.fhir)?;
// 初始化推理客户端
let inference_client = InferenceServiceClient::connect(settings.inference.endpoint.clone()).await?;
let inference_provider = GrpcInferenceProvider::new(inference_client);
// 初始化工具注册表
let mut tool_registry = ToolRegistry::new();
tool_registry.register(DrugInteractionTool::new(pool.clone()));
// 初始化护栏管道
let guardrail_pipeline = GuardrailPipeline::from_config(&settings.guardrails, inference_provider.clone())?;
// 初始化审计系统
let (audit_tx, audit_rx) = tokio::sync::mpsc::unbounded_channel();
let audit_service = AuditService::new(audit_tx.clone());
tokio::spawn(audit_writer(audit_rx, pool.
转载自 CSDN-专业IT技术社区




