diff --git a/crates/erp-ai/src/service/analysis.rs b/crates/erp-ai/src/service/analysis.rs index bbfebdd..c352f0b 100644 --- a/crates/erp-ai/src/service/analysis.rs +++ b/crates/erp-ai/src/service/analysis.rs @@ -8,6 +8,7 @@ use erp_core::types::Pagination; use crate::dto::{AnalysisType, GenerateRequest}; use crate::entity::ai_analysis; use crate::error::{AiError, AiResult}; +use crate::knowledge::KnowledgeSource; use crate::prompt::PromptRenderer; use crate::provider::AiProvider; use crate::sanitization::SanitizationService; @@ -17,6 +18,7 @@ pub struct AnalysisService { pub sanitizer: SanitizationService, pub renderer: PromptRenderer, pub db: sea_orm::DatabaseConnection, + pub knowledge_source: Option>, } impl AnalysisService { @@ -26,9 +28,15 @@ impl AnalysisService { sanitizer: SanitizationService::new(), renderer: PromptRenderer::new(), db, + knowledge_source: None, } } + pub fn with_knowledge_source(mut self, source: std::sync::Arc) -> Self { + self.knowledge_source = Some(source); + self + } + /// 执行流式分析 — 返回 SSE 事件流 pub async fn stream_analyze( &self, @@ -63,6 +71,33 @@ impl AnalysisService { tracing::info!(analysis = %analysis_id, tenant = %tenant_id, r#type = %analysis_type.as_str(), "发起 AI 分析"); + // 0.5 知识库上下文注入 + let system_prompt = if let Some(ref ks) = self.knowledge_source { + let query = crate::knowledge::KnowledgeQuery { + tenant_id, + analysis_type: analysis_type.as_str().to_string(), + patient_context: None, + query_text: None, + }; + match ks.get_context(&query).await { + Ok(ctx) if ctx.confidence > 0.0 => { + tracing::info!( + source = %ctx.source, + confidence = ctx.confidence, + "知识库上下文注入" + ); + format!("{}\n\n=== 知识库参考 ===\n{}", system_prompt, ctx.context_text) + } + Ok(_) => system_prompt, + Err(e) => { + tracing::warn!(error = %e, "知识库查询失败,跳过注入"); + system_prompt + } + } + } else { + system_prompt + }; + // 1. 渲染 Prompt let user_prompt = self.renderer.render(&user_template, &sanitized_data)?; diff --git a/crates/erp-server/src/main.rs b/crates/erp-server/src/main.rs index 7a0b8fa..71cf3e0 100644 --- a/crates/erp-server/src/main.rs +++ b/crates/erp-server/src/main.rs @@ -519,12 +519,13 @@ async fn main() -> anyhow::Result<()> { default_claude = default_claude.with_base_url(base_url.clone()); } - let analysis = std::sync::Arc::new( - erp_ai::service::analysis::AnalysisService::new( - Box::new(default_claude), - db.clone(), - ), - ); + let analysis_svc = erp_ai::service::analysis::AnalysisService::new( + Box::new(default_claude), + db.clone(), + ).with_knowledge_source(std::sync::Arc::new( + erp_ai::knowledge::structured_source::StructuredKnowledgeSource::new(db.clone()), + )); + let analysis = std::sync::Arc::new(analysis_svc); let prompt = std::sync::Arc::new(erp_ai::service::prompt::PromptService::new(db.clone())); let usage = std::sync::Arc::new(erp_ai::service::usage::UsageService::new(db.clone())); let suggestion = std::sync::Arc::new(erp_ai::service::suggestion::SuggestionService);