feat(ai): Day 3 — GetHealthInsightsTool + 配额前置检查 + Token 预算限制

- 新增 GetHealthInsightsTool:聚合档案摘要+化验异常+体征异常,输出 InsightCard
- 注册到 Patient/MedicalStaff 沙箱(10 个 Tool 全部就位)
- chat_handler 添加 QuotaService 配额前置检查(月度 Token/患者日限额)
- AgentRunParams 新增 token_budget 字段,Orchestrator 每轮累计检查超预算强制结束
This commit is contained in:
iven
2026-05-19 10:56:09 +08:00
parent 6f088347ce
commit 8b59f2d7d9
5 changed files with 259 additions and 0 deletions

View File

@@ -9,6 +9,7 @@ use crate::agent::sandbox::{get_sandbox_config, resolve_role};
use crate::agent::tool::ToolContext;
use crate::agent::tools::AnalyzeHealthTrendsTool;
use crate::agent::tools::AnalyzeLabReportTool;
use crate::agent::tools::GetHealthInsightsTool;
use crate::agent::tools::QueryPatientProfileTool;
use crate::agent::tools::QueryPatientVitalsTool;
use crate::agent::tools::SearchMedicalKnowledgeTool;
@@ -75,6 +76,23 @@ where
// 从 settings 表加载 AI 配置(替代硬编码)
let config = config_resolver::load_ai_config(ctx.tenant_id, &ai_state.db).await;
// 配额前置检查
if let Err(e) = ai_state
.quota
.check_quota(ctx.tenant_id, body.patient_id)
.await
{
tracing::warn!(
tenant_id = %ctx.tenant_id,
patient_id = ?body.patient_id,
error = %e,
"Quota check failed"
);
return Err(erp_core::error::AppError::Validation(
"AI 使用配额已用尽,请稍后再试或联系管理员".into(),
));
}
// 构建 Agent 消息历史
let mut messages = vec![];
@@ -129,6 +147,7 @@ where
registry.register(std::sync::Arc::new(QueryPatientProfileTool));
registry.register(std::sync::Arc::new(AnalyzeLabReportTool));
registry.register(std::sync::Arc::new(AnalyzeHealthTrendsTool));
registry.register(std::sync::Arc::new(GetHealthInsightsTool));
// 根据用户角色获取沙箱配置
let user_role = resolve_role(&ctx.roles);
@@ -161,6 +180,7 @@ where
temperature: config.agent.temperature,
max_tokens: config.agent.max_tokens,
max_iterations: config.agent.max_iterations,
token_budget: None,
};
tracing::info!(