perf(chat): 回复效率 + 建议生成并行化优化
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- identity prompt 缓存: LazyLock<RwLock<HashMap>> 缓存已构建的 identity prompt, soul.md 更新时自动失效, 省去每次请求的 mutex + 磁盘 I/O (~0.5-1s) - pre-conversation hook 并行化: tokio::join! 并行执行 identity build 和 continuity context 查询, 不再串行等待 (~1-2s) - suggestion context 预取: 流式回复期间提前启动 fetchSuggestionContext, 回复结束时 context 已就绪 (~0.5-1s) - 建议生成与 memory extraction 解耦: generateLLMSuggestions 不再等待 memory extraction LLM 调用完成, 独立启动 (~3-8s) - Path B (agent stream) 补全 context: lifecycle:end 路径使用预取 context, 修复零个性化问题 - 上下文窗口扩展: slice(-6) → slice(-20), 每条截断 200 字符 - suggestion prompt 重写: 1 深入追问 + 1 实用行动 + 1 管家关怀, 明确角色定位, 禁止空泛建议
This commit is contained in:
@@ -7,8 +7,10 @@
|
||||
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tauri::Emitter;
|
||||
use tokio::sync::RwLock;
|
||||
use zclaw_growth::VikingStorage;
|
||||
|
||||
use crate::intelligence::identity::IdentityManagerState;
|
||||
@@ -16,6 +18,36 @@ use crate::intelligence::heartbeat::HeartbeatEngineState;
|
||||
use crate::intelligence::reflection::{MemoryEntryForAnalysis, ReflectionEngineState};
|
||||
use zclaw_runtime::driver::LlmDriver;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Identity prompt cache — avoids mutex + disk I/O on every request
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct CachedIdentity {
|
||||
prompt: String,
|
||||
#[allow(dead_code)] // Reserved for future TTL-based cache validation
|
||||
soul_hash: u64,
|
||||
}
|
||||
|
||||
static IDENTITY_CACHE: std::sync::LazyLock<RwLock<HashMap<String, CachedIdentity>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
|
||||
/// Invalidate cached identity prompt for a given agent (call when soul.md changes).
|
||||
pub fn invalidate_identity_cache(agent_id: &str) {
|
||||
let cache = &*IDENTITY_CACHE;
|
||||
// Non-blocking: spawn a task to remove the entry
|
||||
if let Ok(mut guard) = cache.try_write() {
|
||||
guard.remove(agent_id);
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple hash for cache invalidation — uses string content hash.
|
||||
fn content_hash(s: &str) -> u64 {
|
||||
use std::hash::{Hash, Hasher};
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
s.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
/// Run pre-conversation intelligence hooks
|
||||
///
|
||||
/// Builds identity-enhanced system prompt (SOUL.md + instructions) and
|
||||
@@ -29,10 +61,29 @@ pub async fn pre_conversation_hook(
|
||||
_user_message: &str,
|
||||
identity_state: &IdentityManagerState,
|
||||
) -> Result<String, String> {
|
||||
// Build identity-enhanced system prompt (SOUL.md + instructions)
|
||||
// Memory context is injected by MemoryMiddleware in the kernel middleware chain,
|
||||
// not here, to avoid duplicate injection.
|
||||
let enhanced_prompt = match build_identity_prompt(agent_id, "", identity_state).await {
|
||||
// Check identity prompt cache first (avoids mutex + disk I/O)
|
||||
let cache = &*IDENTITY_CACHE;
|
||||
{
|
||||
let guard = cache.read().await;
|
||||
if let Some(cached) = guard.get(agent_id) {
|
||||
// Cache hit — still need continuity context, but skip identity build
|
||||
let continuity_context = build_continuity_context(agent_id, _user_message).await;
|
||||
let mut result = cached.prompt.clone();
|
||||
if !continuity_context.is_empty() {
|
||||
result.push_str(&continuity_context);
|
||||
}
|
||||
debug!("[intelligence_hooks] Identity cache HIT for agent {}", agent_id);
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache miss — build identity prompt and continuity context in parallel
|
||||
let (identity_result, continuity_context) = tokio::join!(
|
||||
build_identity_prompt_cached(agent_id, "", identity_state, cache),
|
||||
build_continuity_context(agent_id, _user_message)
|
||||
);
|
||||
|
||||
let enhanced_prompt = match identity_result {
|
||||
Ok(prompt) => prompt,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
@@ -43,9 +94,6 @@ pub async fn pre_conversation_hook(
|
||||
}
|
||||
};
|
||||
|
||||
// Cross-session continuity: check for unresolved pain points and recent experiences
|
||||
let continuity_context = build_continuity_context(agent_id, _user_message).await;
|
||||
|
||||
let mut result = enhanced_prompt;
|
||||
if !continuity_context.is_empty() {
|
||||
result.push_str(&continuity_context);
|
||||
@@ -240,6 +288,8 @@ pub async fn post_conversation_hook(
|
||||
warn!("[intelligence_hooks] Failed to update soul with agent name: {}", e);
|
||||
} else {
|
||||
debug!("[intelligence_hooks] Updated agent name to '{}' in soul", name);
|
||||
// Invalidate cache since soul.md changed
|
||||
invalidate_identity_cache(agent_id);
|
||||
}
|
||||
}
|
||||
drop(manager);
|
||||
@@ -340,21 +390,34 @@ async fn build_memory_context(
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
/// Build identity-enhanced system prompt
|
||||
async fn build_identity_prompt(
|
||||
/// Build identity-enhanced system prompt and cache the result.
|
||||
async fn build_identity_prompt_cached(
|
||||
agent_id: &str,
|
||||
memory_context: &str,
|
||||
identity_state: &IdentityManagerState,
|
||||
cache: &RwLock<HashMap<String, CachedIdentity>>,
|
||||
) -> Result<String, String> {
|
||||
// IdentityManagerState is Arc<tokio::sync::Mutex<AgentIdentityManager>>
|
||||
// tokio::sync::Mutex::lock() returns MutexGuard directly
|
||||
let mut manager = identity_state.lock().await;
|
||||
|
||||
// Read current soul content for hashing
|
||||
let soul_content = manager.get_file(agent_id, crate::intelligence::identity::IdentityFile::Soul);
|
||||
let soul_hash = content_hash(&soul_content);
|
||||
|
||||
let prompt = manager.build_system_prompt(
|
||||
agent_id,
|
||||
if memory_context.is_empty() { None } else { Some(memory_context) },
|
||||
).await;
|
||||
|
||||
// Cache the result
|
||||
drop(manager); // Release lock before acquiring write guard
|
||||
{
|
||||
let mut guard = cache.write().await;
|
||||
guard.insert(agent_id.to_string(), CachedIdentity {
|
||||
prompt: prompt.clone(),
|
||||
soul_hash,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(prompt)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user