fix(audit): 第五轮审计修复 — 反思LLM分析、语义路由、并行执行、错误中文化
- P2: 反思引擎接入 LLM 深度行为分析 (analyze_patterns_with_llm) - P3-M6: 语义路由 RuntimeLlmIntentDriver 真实 LLM 匹配 - P3-L1: V2 Pipeline execute_parallel 改用 buffer_unordered 真正并行 - P3-S10: Rust 用户可见错误提示统一中文化 累计修复 27 项,完成度 ~72% → ~78%
This commit is contained in:
@@ -19,6 +19,10 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
// Re-export from zclaw-runtime for LLM integration
|
||||
use zclaw_runtime::driver::{CompletionRequest, ContentBlock, LlmDriver};
|
||||
|
||||
// === Types ===
|
||||
|
||||
@@ -187,9 +191,33 @@ impl ReflectionEngine {
|
||||
}
|
||||
|
||||
/// Execute reflection cycle
|
||||
pub fn reflect(&mut self, agent_id: &str, memories: &[MemoryEntryForAnalysis]) -> ReflectionResult {
|
||||
// 1. Analyze memory patterns
|
||||
let patterns = self.analyze_patterns(memories);
|
||||
pub async fn reflect(
|
||||
&mut self,
|
||||
agent_id: &str,
|
||||
memories: &[MemoryEntryForAnalysis],
|
||||
driver: Option<Arc<dyn LlmDriver>>,
|
||||
) -> ReflectionResult {
|
||||
// 1. Analyze memory patterns (LLM if configured, rules fallback)
|
||||
let patterns = if self.config.use_llm {
|
||||
if let Some(ref llm) = driver {
|
||||
match self.analyze_patterns_with_llm(memories, llm).await {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
tracing::warn!("[reflection] LLM analysis failed, falling back to rules: {}", e);
|
||||
if self.config.llm_fallback_to_rules {
|
||||
self.analyze_patterns(memories)
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tracing::debug!("[reflection] use_llm=true but no driver available, using rules");
|
||||
self.analyze_patterns(memories)
|
||||
}
|
||||
} else {
|
||||
self.analyze_patterns(memories)
|
||||
};
|
||||
|
||||
// 2. Generate improvement suggestions
|
||||
let improvements = self.generate_improvements(&patterns, memories);
|
||||
@@ -282,7 +310,65 @@ impl ReflectionEngine {
|
||||
result
|
||||
}
|
||||
|
||||
/// Analyze patterns in memories
|
||||
/// Analyze patterns using LLM for deeper behavioral insights
|
||||
async fn analyze_patterns_with_llm(
|
||||
&self,
|
||||
memories: &[MemoryEntryForAnalysis],
|
||||
driver: &Arc<dyn LlmDriver>,
|
||||
) -> Result<Vec<PatternObservation>, String> {
|
||||
if memories.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
// Build memory summary for the prompt
|
||||
let memory_summary: String = memories.iter().enumerate().map(|(i, m)| {
|
||||
format!("{}. [{}] (重要性:{}, 访问:{}) {}",
|
||||
i + 1, m.memory_type, m.importance, m.access_count, m.content)
|
||||
}).collect::<Vec<_>>().join("\n");
|
||||
|
||||
let system_prompt = r#"你是行为分析专家。分析以下 Agent 记忆条目,识别行为模式和趋势。
|
||||
|
||||
请返回 JSON 数组,每个元素包含:
|
||||
- "observation": string — 模式描述(中文)
|
||||
- "frequency": number — 该模式出现的频率估计(1-10)
|
||||
- "sentiment": "positive" | "negative" | "neutral" — 情感倾向
|
||||
- "evidence": string[] — 支持该观察的证据(记忆内容摘要,最多3条)
|
||||
|
||||
只返回 JSON 数组,不要其他内容。如果没有明显模式,返回空数组。"#
|
||||
.to_string();
|
||||
|
||||
let request = CompletionRequest {
|
||||
model: driver.provider().to_string(),
|
||||
system: Some(system_prompt),
|
||||
messages: vec![zclaw_types::Message::assistant(
|
||||
format!("分析以下记忆条目:\n\n{}", memory_summary)
|
||||
)],
|
||||
max_tokens: Some(2048),
|
||||
temperature: Some(0.3),
|
||||
stream: false,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = driver.complete(request).await
|
||||
.map_err(|e| format!("LLM 调用失败: {}", e))?;
|
||||
|
||||
// Extract text from response
|
||||
let text = response.content.iter()
|
||||
.filter_map(|block| match block {
|
||||
ContentBlock::Text { text } => Some(text.as_str()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("");
|
||||
|
||||
// Parse JSON response (handle markdown code blocks)
|
||||
let json_str = extract_json_from_llm_response(&text);
|
||||
|
||||
serde_json::from_str::<Vec<PatternObservation>>(&json_str)
|
||||
.map_err(|e| format!("解析 LLM 响应失败: {} — 原始响应: {}", e, &text[..text.len().min(200)]))
|
||||
}
|
||||
|
||||
/// Analyze patterns in memories (rule-based fallback)
|
||||
fn analyze_patterns(&self, memories: &[MemoryEntryForAnalysis]) -> Vec<PatternObservation> {
|
||||
let mut patterns = Vec::new();
|
||||
|
||||
@@ -633,7 +719,6 @@ pub fn pop_restored_result(agent_id: &str) -> Option<ReflectionResult> {
|
||||
|
||||
// === Tauri Commands ===
|
||||
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
pub type ReflectionEngineState = Arc<Mutex<ReflectionEngine>>;
|
||||
@@ -679,7 +764,7 @@ pub async fn reflection_reflect(
|
||||
state: tauri::State<'_, ReflectionEngineState>,
|
||||
) -> Result<ReflectionResult, String> {
|
||||
let mut engine = state.lock().await;
|
||||
Ok(engine.reflect(&agent_id, &memories))
|
||||
Ok(engine.reflect(&agent_id, &memories, None).await)
|
||||
}
|
||||
|
||||
/// Get reflection history
|
||||
@@ -785,3 +870,28 @@ mod tests {
|
||||
assert!(!patterns.iter().any(|p| p.observation.contains("待办任务")));
|
||||
}
|
||||
}
|
||||
|
||||
// === Helpers ===
|
||||
|
||||
/// Extract JSON from LLM response, handling markdown code blocks and extra text
|
||||
fn extract_json_from_llm_response(text: &str) -> String {
|
||||
let trimmed = text.trim();
|
||||
|
||||
// Try to find JSON array in markdown code block
|
||||
if let Some(start) = trimmed.find("```json") {
|
||||
if let Some(content_start) = trimmed[start..].find('\n') {
|
||||
if let Some(end) = trimmed[content_start..].find("```") {
|
||||
return trimmed[content_start + 1..content_start + end].trim().to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to find bare JSON array
|
||||
if let Some(start) = trimmed.find('[') {
|
||||
if let Some(end) = trimmed.rfind(']') {
|
||||
return trimmed[start..end + 1].to_string();
|
||||
}
|
||||
}
|
||||
|
||||
trimmed.to_string()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user