feat(ai): Day 4 — 策略 Prompt 优化 + Tool 调用日志
- System Prompt 增加 10 个 Tool 的使用时机指引,Agent 自动选择最合适的 Tool - 优先使用 get_health_insights 作为首次对话开场工具 - AgentRunResult 新增 tool_calls: Vec<ToolCallLog>,记录每次调用名称/耗时/成功状态 - ToolCallLog 将在 Phase 2 写入 ai_tool_call_logs 表
This commit is contained in:
@@ -6,6 +6,14 @@ use crate::dto::{ChatMessage, ChatMessageRole};
|
||||
use crate::error::AiResult;
|
||||
use crate::provider::AiProvider;
|
||||
|
||||
/// 单次 Tool 调用日志
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ToolCallLog {
|
||||
pub tool_name: String,
|
||||
pub duration_ms: u64,
|
||||
pub success: bool,
|
||||
}
|
||||
|
||||
/// Agent 运行时参数
|
||||
pub struct AgentRunParams {
|
||||
pub model: String,
|
||||
@@ -40,6 +48,7 @@ pub struct AgentRunResult {
|
||||
pub total_input_tokens: u32,
|
||||
pub total_output_tokens: u32,
|
||||
pub iterations: usize,
|
||||
pub tool_calls: Vec<ToolCallLog>,
|
||||
}
|
||||
|
||||
impl AgentOrchestrator {
|
||||
@@ -66,6 +75,7 @@ impl AgentOrchestrator {
|
||||
let mut iterations = 0;
|
||||
let mut total_input_tokens = 0u32;
|
||||
let mut total_output_tokens = 0u32;
|
||||
let mut tool_call_logs: Vec<ToolCallLog> = Vec::new();
|
||||
|
||||
loop {
|
||||
iterations += 1;
|
||||
@@ -96,6 +106,7 @@ impl AgentOrchestrator {
|
||||
total_input_tokens,
|
||||
total_output_tokens,
|
||||
iterations,
|
||||
tool_calls: tool_call_logs,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -143,23 +154,30 @@ impl AgentOrchestrator {
|
||||
|
||||
// 执行每个 Tool Call(受沙箱 allowed_tools 约束)
|
||||
for tc in &tool_calls {
|
||||
let tool_result = match self.tool_registry.get(&tc.name) {
|
||||
let start = std::time::Instant::now();
|
||||
let (tool_result, success) = match self.tool_registry.get(&tc.name) {
|
||||
Some(tool) => {
|
||||
// 沙箱过滤:如果 allowed_tools 存在且不包含此 Tool,拒绝执行
|
||||
if let Some(allowed) = allowed_tools {
|
||||
if !allowed.contains(tc.name.as_str()) {
|
||||
format!("Tool '{}' 在当前角色下不可用", tc.name)
|
||||
(format!("Tool '{}' 在当前角色下不可用", tc.name), false)
|
||||
} else {
|
||||
let result = tool.execute(ctx, tc.arguments.clone()).await;
|
||||
result.output
|
||||
(result.output, true)
|
||||
}
|
||||
} else {
|
||||
let result = tool.execute(ctx, tc.arguments.clone()).await;
|
||||
result.output
|
||||
(result.output, true)
|
||||
}
|
||||
}
|
||||
None => format!("未知 Tool: {}", tc.name),
|
||||
None => (format!("未知 Tool: {}", tc.name), false),
|
||||
};
|
||||
let duration = start.elapsed();
|
||||
|
||||
tool_call_logs.push(ToolCallLog {
|
||||
tool_name: tc.name.clone(),
|
||||
duration_ms: duration.as_millis() as u64,
|
||||
success,
|
||||
});
|
||||
|
||||
messages.push(ChatMessage {
|
||||
role: ChatMessageRole::Tool,
|
||||
|
||||
@@ -574,16 +574,16 @@ fn default_system_prompt() -> String {
|
||||
- 分享积极案例,降低恐惧感
|
||||
|
||||
2. 【医疗科普】当用户询问指标含义、疾病知识时:
|
||||
- 调用 search_medical_knowledge 获取准确信息(如可用)
|
||||
- 调用 search_medical_knowledge 获取准确信息
|
||||
- 用比喻和类比让老年患者也能理解
|
||||
- 强调"具体请以医生诊断为准"
|
||||
|
||||
3. 【服务推荐】当用户表达就医需求或身体不适时:
|
||||
- 调用 query_appointments 查看已有预约(如可用)
|
||||
- 调用 query_patient_appointments 查看已有预约
|
||||
- 主动提出帮用户预约
|
||||
|
||||
4. 【风险预警】当用户描述的症状或数据异常时:
|
||||
- 调用 query_patient_vitals 查看体征数据
|
||||
- 调用 get_health_insights 获取综合健康洞察
|
||||
- 明确告知风险等级和需要注意的事项
|
||||
- 高风险时建议尽快就医
|
||||
|
||||
@@ -591,6 +591,22 @@ fn default_system_prompt() -> String {
|
||||
- 提供科室位置、出诊医生信息
|
||||
- 建议用户联系前台预约
|
||||
|
||||
## 工具使用指引
|
||||
根据用户意图选择合适的工具,不要一次调用所有工具:
|
||||
|
||||
- 用户首次对话或询问总体健康 → get_health_insights(综合洞察)
|
||||
- 询问"我的血压/血糖怎么样" → query_patient_vitals(体征数据)
|
||||
- 询问"化验结果/报告" → query_patient_lab_reports(化验报告列表)
|
||||
- 拿到具体报告 ID 后追问详情 → analyze_lab_report(单份报告详细指标)
|
||||
- 询问"趋势/最近变化" → analyze_health_trends(趋势分析)
|
||||
- 询问"吃什么药" → query_patient_medications(用药列表)
|
||||
- 询问"预约/挂号" → query_patient_appointments(预约列表)
|
||||
- 询问疾病/指标知识 → search_medical_knowledge(医学知识搜索)
|
||||
- 询问"我的档案/基本信息" → query_patient_profile(患者档案)
|
||||
|
||||
优先使用 get_health_insights 作为首次对话的开场工具,获取全局概览后再深入。
|
||||
如果同时有多个相关工具可用,选择信息量最大的那个,避免冗余调用。
|
||||
|
||||
## 策略不是互斥的,你可以在一轮对话中自然切换。
|
||||
## 永远不要:推荐具体药物、给出明确诊断、替代医生建议。
|
||||
## 如果没有可用的工具数据,就基于常识回答,并建议用户咨询医生。"#
|
||||
|
||||
Reference in New Issue
Block a user