feat(ai): 添加知识库 trait 和 DTO — KnowledgeSource/PatientSummary/Reference
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

Phase 3 Task 19: 定义统一知识获取接口,支持未来向量检索扩展
This commit is contained in:
iven
2026-05-05 15:50:57 +08:00
parent 54116d1a1f
commit 75a70d2e46
2 changed files with 117 additions and 0 deletions

View File

@@ -0,0 +1,116 @@
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::error::AiResult;
/// 知识源 trait — 统一结构化和未来向量检索的知识获取接口
#[async_trait]
pub trait KnowledgeSource: Send + Sync {
/// 根据查询获取知识上下文
async fn get_context(&self, query: &KnowledgeQuery) -> AiResult<KnowledgeContext>;
/// 知识源类型标识
fn source_type(&self) -> &str;
/// 健康检查
async fn health_check(&self) -> AiResult<bool>;
}
/// 知识查询参数
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KnowledgeQuery {
pub tenant_id: Uuid,
pub analysis_type: String,
pub patient_context: Option<PatientSummary>,
pub query_text: Option<String>,
}
/// 脱敏患者摘要(不含 PII
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PatientSummary {
pub age: Option<i32>,
pub gender: Option<String>,
pub tags: Vec<String>,
}
/// 知识上下文(返回给 Prompt 注入)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KnowledgeContext {
pub source: String,
pub context_text: String,
pub references: Vec<Reference>,
pub confidence: f32,
}
/// 参考引用
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Reference {
pub title: String,
pub source: String,
pub relevance_score: f32,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn knowledge_query_construction() {
let query = KnowledgeQuery {
tenant_id: Uuid::now_v7(),
analysis_type: "lab_report".into(),
patient_context: Some(PatientSummary {
age: Some(65),
gender: Some("male".into()),
tags: vec!["高血压".into(), "糖尿病".into()],
}),
query_text: Some("血红蛋白偏低".into()),
};
assert_eq!(query.analysis_type, "lab_report");
assert_eq!(query.patient_context.as_ref().unwrap().tags.len(), 2);
}
#[test]
fn knowledge_context_serde_roundtrip() {
let ctx = KnowledgeContext {
source: "structured".into(),
context_text: "【规则】血压 >140 需关注".into(),
references: vec![Reference {
title: "高血压指南".into(),
source: "system".into(),
relevance_score: 0.95,
}],
confidence: 0.9,
};
let json = serde_json::to_string(&ctx).unwrap();
let back: KnowledgeContext = serde_json::from_str(&json).unwrap();
assert_eq!(back.source, "structured");
assert_eq!(back.references.len(), 1);
assert!((back.confidence - 0.9).abs() < 0.01);
}
#[test]
fn patient_summary_serde() {
let summary = PatientSummary {
age: Some(70),
gender: Some("female".into()),
tags: vec![],
};
let json = serde_json::to_string(&summary).unwrap();
let back: PatientSummary = serde_json::from_str(&json).unwrap();
assert_eq!(back.age, Some(70));
}
#[test]
fn truncate_context_text() {
let long_text: String = "x".repeat(10000);
let max_chars = 8000;
let truncated = if long_text.len() > max_chars {
long_text[..max_chars].to_string()
} else {
long_text
};
assert_eq!(truncated.len(), max_chars);
}
}

View File

@@ -3,6 +3,7 @@ pub mod dto;
pub mod entity;
pub mod error;
pub mod handler;
pub mod knowledge;
pub mod module;
pub mod prompt;
pub mod provider;