feat(ai): 集成知识库到 AnalysisService — system_prompt 自动注入临床规则
Phase 3 Task 23: AnalysisService 新增可选 knowledge_source, stream_analyze 前自动查询 L1/L2/L3 知识并注入 system_prompt
This commit is contained in:
@@ -8,6 +8,7 @@ use erp_core::types::Pagination;
|
|||||||
use crate::dto::{AnalysisType, GenerateRequest};
|
use crate::dto::{AnalysisType, GenerateRequest};
|
||||||
use crate::entity::ai_analysis;
|
use crate::entity::ai_analysis;
|
||||||
use crate::error::{AiError, AiResult};
|
use crate::error::{AiError, AiResult};
|
||||||
|
use crate::knowledge::KnowledgeSource;
|
||||||
use crate::prompt::PromptRenderer;
|
use crate::prompt::PromptRenderer;
|
||||||
use crate::provider::AiProvider;
|
use crate::provider::AiProvider;
|
||||||
use crate::sanitization::SanitizationService;
|
use crate::sanitization::SanitizationService;
|
||||||
@@ -17,6 +18,7 @@ pub struct AnalysisService {
|
|||||||
pub sanitizer: SanitizationService,
|
pub sanitizer: SanitizationService,
|
||||||
pub renderer: PromptRenderer,
|
pub renderer: PromptRenderer,
|
||||||
pub db: sea_orm::DatabaseConnection,
|
pub db: sea_orm::DatabaseConnection,
|
||||||
|
pub knowledge_source: Option<std::sync::Arc<dyn KnowledgeSource>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnalysisService {
|
impl AnalysisService {
|
||||||
@@ -26,9 +28,15 @@ impl AnalysisService {
|
|||||||
sanitizer: SanitizationService::new(),
|
sanitizer: SanitizationService::new(),
|
||||||
renderer: PromptRenderer::new(),
|
renderer: PromptRenderer::new(),
|
||||||
db,
|
db,
|
||||||
|
knowledge_source: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_knowledge_source(mut self, source: std::sync::Arc<dyn KnowledgeSource>) -> Self {
|
||||||
|
self.knowledge_source = Some(source);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// 执行流式分析 — 返回 SSE 事件流
|
/// 执行流式分析 — 返回 SSE 事件流
|
||||||
pub async fn stream_analyze(
|
pub async fn stream_analyze(
|
||||||
&self,
|
&self,
|
||||||
@@ -63,6 +71,33 @@ impl AnalysisService {
|
|||||||
|
|
||||||
tracing::info!(analysis = %analysis_id, tenant = %tenant_id, r#type = %analysis_type.as_str(), "发起 AI 分析");
|
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
|
// 1. 渲染 Prompt
|
||||||
let user_prompt = self.renderer.render(&user_template, &sanitized_data)?;
|
let user_prompt = self.renderer.render(&user_template, &sanitized_data)?;
|
||||||
|
|
||||||
|
|||||||
@@ -519,12 +519,13 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
default_claude = default_claude.with_base_url(base_url.clone());
|
default_claude = default_claude.with_base_url(base_url.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let analysis = std::sync::Arc::new(
|
let analysis_svc = erp_ai::service::analysis::AnalysisService::new(
|
||||||
erp_ai::service::analysis::AnalysisService::new(
|
Box::new(default_claude),
|
||||||
Box::new(default_claude),
|
db.clone(),
|
||||||
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 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 usage = std::sync::Arc::new(erp_ai::service::usage::UsageService::new(db.clone()));
|
||||||
let suggestion = std::sync::Arc::new(erp_ai::service::suggestion::SuggestionService);
|
let suggestion = std::sync::Arc::new(erp_ai::service::suggestion::SuggestionService);
|
||||||
|
|||||||
Reference in New Issue
Block a user