feat(ai): Agent Tool 扩展 — QueryPatientProfile + DisplayHint 新增 3 变体

- QueryPatientProfileTool: 查询患者档案摘要(年龄/性别/慢性病/用药/家族史)
- DisplayHint 新增 TrendChart/InsightCard/PatientProfile 变体
- 沙箱: Patient + MedicalStaff 添加 query_patient_profile
This commit is contained in:
iven
2026-05-19 10:41:29 +08:00
parent 8b88cb4a50
commit 7edf1ed1d3
5 changed files with 127 additions and 0 deletions

View File

@@ -45,6 +45,7 @@ pub fn get_sandbox_config(role: &UserRole) -> SandboxConfig {
"query_patient_lab_reports".into(),
"query_patient_medications".into(),
"search_medical_knowledge".into(),
"query_patient_profile".into(),
]),
system_prompt_suffix: PATIENT_PROMPT_SUFFIX,
output_filter: OutputFilter {
@@ -61,6 +62,7 @@ pub fn get_sandbox_config(role: &UserRole) -> SandboxConfig {
"query_patient_appointments".into(),
"query_patient_medications".into(),
"search_medical_knowledge".into(),
"query_patient_profile".into(),
]),
system_prompt_suffix: MEDICAL_STAFF_PROMPT_SUFFIX,
output_filter: OutputFilter {

View File

@@ -51,5 +51,19 @@ pub enum DisplayHint {
level: String,
message: String,
},
TrendChart {
metrics: Vec<String>,
period: String,
summary: String,
},
InsightCard {
title: String,
severity: String,
items: Vec<String>,
},
PatientProfile {
chronic_conditions: Vec<String>,
medication_count: usize,
},
Text,
}

View File

@@ -3,11 +3,13 @@
pub mod query_appointments;
pub mod query_lab_reports;
pub mod query_medications;
pub mod query_patient_profile;
pub mod query_vitals;
pub mod search_medical_knowledge;
pub use query_appointments::QueryAppointmentsTool;
pub use query_lab_reports::QueryLabReportsTool;
pub use query_medications::QueryMedicationsTool;
pub use query_patient_profile::QueryPatientProfileTool;
pub use query_vitals::QueryPatientVitalsTool;
pub use search_medical_knowledge::SearchMedicalKnowledgeTool;

View File

@@ -0,0 +1,107 @@
use async_trait::async_trait;
use crate::agent::tool::{AgentTool, DisplayHint, ToolContext, ToolResult};
/// 查询患者档案摘要(年龄/性别/慢性病/用药/家族史)
pub struct QueryPatientProfileTool;
#[async_trait]
impl AgentTool for QueryPatientProfileTool {
fn name(&self) -> &str {
"query_patient_profile"
}
fn description(&self) -> &str {
"查询患者健康档案摘要,包括年龄组、性别、慢性疾病、当前用药、家族病史和最近体检日期。"
}
fn parameters_schema(&self) -> serde_json::Value {
serde_json::json!({
"type": "object",
"properties": {}
})
}
async fn execute(&self, ctx: &ToolContext, _params: serde_json::Value) -> ToolResult {
let patient_id = match ctx.patient_id {
Some(id) => id,
None => {
return ToolResult {
output: "未关联患者档案,无法查询患者信息".to_string(),
display_hint: None,
};
}
};
match ctx
.health_provider
.get_patient_summary(ctx.tenant_id, patient_id)
.await
{
Ok(summary) => {
let mut output = String::from("患者档案摘要:\n");
output.push_str(&format!("- 年龄组: {}\n", summary.age_group));
output.push_str(&format!("- 性别: {}\n", summary.sex));
if summary.chronic_conditions.is_empty() {
output.push_str("- 慢性疾病: 无\n");
} else {
output.push_str(&format!(
"- 慢性疾病: {}\n",
summary.chronic_conditions.join("")
));
}
if summary.medications.is_empty() {
output.push_str("- 当前用药: 无\n");
} else {
output.push_str(&format!("- 当前用药: {}\n", summary.medications.join("")));
}
if summary.family_history.is_empty() {
output.push_str("- 家族病史: 无\n");
} else {
output.push_str(&format!(
"- 家族病史: {}\n",
summary.family_history.join("")
));
}
output.push_str(&format!("- 最近体检: {}\n", summary.last_checkup_date));
let display_hint = DisplayHint::PatientProfile {
chronic_conditions: summary.chronic_conditions.clone(),
medication_count: summary.medications.len(),
};
ToolResult {
output,
display_hint: Some(display_hint),
}
}
Err(e) => ToolResult {
output: format!("查询患者档案失败: {}", e),
display_hint: None,
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tool_name() {
let tool = QueryPatientProfileTool;
assert_eq!(tool.name(), "query_patient_profile");
}
#[test]
fn parameters_schema_is_empty_object() {
let tool = QueryPatientProfileTool;
let schema = tool.parameters_schema();
assert_eq!(schema["type"], "object");
assert!(schema["properties"].as_object().unwrap().is_empty());
}
}

View File

@@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
use crate::agent::orchestrator::AgentRunParams;
use crate::agent::sandbox::{get_sandbox_config, resolve_role};
use crate::agent::tool::ToolContext;
use crate::agent::tools::QueryPatientProfileTool;
use crate::agent::tools::QueryPatientVitalsTool;
use crate::agent::tools::SearchMedicalKnowledgeTool;
use crate::agent::tools::{QueryAppointmentsTool, QueryLabReportsTool, QueryMedicationsTool};
@@ -123,6 +124,7 @@ where
registry.register(std::sync::Arc::new(QueryAppointmentsTool));
registry.register(std::sync::Arc::new(QueryMedicationsTool));
registry.register(std::sync::Arc::new(SearchMedicalKnowledgeTool));
registry.register(std::sync::Arc::new(QueryPatientProfileTool));
// 根据用户角色获取沙箱配置
let user_role = resolve_role(&ctx.roles);