feat(ai): Phase 1B 角色沙箱 — 三级权限隔离 + Tool 过滤 + 输出控制
- 新增 agent/sandbox.rs: UserRole/SandboxConfig/OutputFilter 三级模型 - resolve_role() 从 JWT roles 解析为 Patient/MedicalStaff/Admin - ToolRegistry.tool_definitions_filtered() 按角色白名单过滤 - orchestrator.run() 新增 allowed_tools 参数,Tool 执行时二次校验 - chat_handler 集成沙箱:角色 Prompt 后缀 + 患者免责声明追加
This commit is contained in:
@@ -5,6 +5,7 @@ use erp_core::types::{ApiResponse, TenantContext};
|
||||
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::QueryPatientVitalsTool;
|
||||
use crate::agent::{AgentOrchestrator, ToolRegistry};
|
||||
@@ -113,10 +114,22 @@ where
|
||||
)
|
||||
})?;
|
||||
|
||||
// 构建 ToolRegistry — Phase 0 只有 query_patient_vitals
|
||||
// 构建全局 ToolRegistry(所有已注册 Tool)
|
||||
let mut registry = ToolRegistry::new();
|
||||
registry.register(std::sync::Arc::new(QueryPatientVitalsTool));
|
||||
|
||||
// 根据用户角色获取沙箱配置
|
||||
let user_role = resolve_role(&ctx.roles);
|
||||
let sandbox = get_sandbox_config(&user_role);
|
||||
|
||||
tracing::info!(
|
||||
tenant_id = %ctx.tenant_id,
|
||||
user_id = %ctx.user_id,
|
||||
role = ?user_role,
|
||||
allowed_tools = ?sandbox.allowed_tools,
|
||||
"Sandbox resolved"
|
||||
);
|
||||
|
||||
let tool_ctx = ToolContext {
|
||||
tenant_id: ctx.tenant_id,
|
||||
user_id: ctx.user_id,
|
||||
@@ -125,6 +138,12 @@ where
|
||||
health_provider: ai_state.health_provider.clone(),
|
||||
};
|
||||
|
||||
// system_prompt 追加角色沙箱的 Prompt 后缀
|
||||
let system_prompt = format!(
|
||||
"{}{}",
|
||||
config.agent.system_prompt, sandbox.system_prompt_suffix
|
||||
);
|
||||
|
||||
let run_params = AgentRunParams {
|
||||
model: config.agent.model,
|
||||
temperature: config.agent.temperature,
|
||||
@@ -146,14 +165,15 @@ where
|
||||
|
||||
let provider_name = provider_arc.name().to_string();
|
||||
|
||||
// 执行 Agent ReAct 循环
|
||||
// 执行 Agent ReAct 循环(使用角色沙箱过滤后的 Tool 和 Prompt)
|
||||
let orchestrator = AgentOrchestrator::new(provider_arc, std::sync::Arc::new(registry));
|
||||
let result = orchestrator
|
||||
let mut result = orchestrator
|
||||
.run(
|
||||
&config.agent.system_prompt,
|
||||
&system_prompt,
|
||||
&mut messages,
|
||||
&tool_ctx,
|
||||
&run_params,
|
||||
Some(&sandbox.allowed_tools),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
@@ -161,6 +181,11 @@ where
|
||||
erp_core::error::AppError::Internal("AI 服务暂时不可用,请稍后再试".into())
|
||||
})?;
|
||||
|
||||
// 输出过滤:患者角色追加免责声明
|
||||
if sandbox.output_filter.append_disclaimer && !result.reply.is_empty() {
|
||||
result.reply.push_str(sandbox.output_filter.disclaimer_text);
|
||||
}
|
||||
|
||||
let message_id = uuid::Uuid::now_v7().to_string();
|
||||
|
||||
tracing::info!(
|
||||
|
||||
Reference in New Issue
Block a user