feat(ai): Agent Tool 扩展 — QueryPatientProfile + DisplayHint 新增 3 变体
- QueryPatientProfileTool: 查询患者档案摘要(年龄/性别/慢性病/用药/家族史) - DisplayHint 新增 TrendChart/InsightCard/PatientProfile 变体 - 沙箱: Patient + MedicalStaff 添加 query_patient_profile
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
107
crates/erp-ai/src/agent/tools/query_patient_profile.rs
Normal file
107
crates/erp-ai/src/agent/tools/query_patient_profile.rs
Normal 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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user