fix(growth): AUD-11 反馈信任度启动集成 + AUD-12 日志格式优化
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

AUD-11: FeedbackCollector 内部 lazy-load 机制
- save() 首次调用自动从持久化存储加载信任度记录
- load() 使用 or_insert 策略,不覆盖内存中较新记录
- GrowthIntegration.initialize() 保留为可选优化入口
- 移除无法在 &self 中间件中使用的 ensure_feedback_loaded

AUD-12: 日志格式优化
- ProfileSignals 新增 signal_count() 方法
- extractor.rs 使用 signal_count() 替代 has_any_signal() as usize
This commit is contained in:
iven
2026-04-19 00:15:50 +08:00
parent 0fd78ac321
commit 72b3206a6b
4 changed files with 61 additions and 4 deletions

View File

@@ -293,7 +293,7 @@ impl MemoryExtractor {
"[MemoryExtractor] Combined extraction: {} memories, {} experiences, {} profile signals",
combined.memories.len(),
combined.experiences.len(),
combined.profile_signals.has_any_signal() as usize,
combined.profile_signals.signal_count(),
);
return Ok(combined);
}

View File

@@ -69,6 +69,8 @@ pub struct TrustRecord {
pub struct FeedbackCollector {
trust_records: HashMap<String, TrustRecord>,
viking: Option<Arc<VikingAdapter>>,
/// 是否已从持久化存储加载信任度记录
loaded: bool,
}
impl FeedbackCollector {
@@ -76,6 +78,7 @@ impl FeedbackCollector {
Self {
trust_records: HashMap::new(),
viking: None,
loaded: false,
}
}
@@ -84,6 +87,7 @@ impl FeedbackCollector {
Self {
trust_records: HashMap::new(),
viking: Some(viking),
loaded: false,
}
}
@@ -105,8 +109,10 @@ impl FeedbackCollector {
for entry in entries {
match serde_json::from_str::<TrustRecord>(&entry.content) {
Ok(record) => {
// 只合并不覆盖:保留内存中的较新记录
self.trust_records
.insert(record.artifact_id.clone(), record);
.entry(record.artifact_id.clone())
.or_insert(record);
count += 1;
}
Err(e) => {
@@ -127,7 +133,19 @@ impl FeedbackCollector {
}
/// 将信任度记录持久化到 VikingAdapter
pub async fn save(&self) -> Result<usize, String> {
/// 首次调用时自动从存储加载已有记录,避免覆盖
pub async fn save(&mut self) -> Result<usize, String> {
// 首次保存前自动加载已有记录,防止丢失历史数据
if !self.loaded {
if let Err(e) = self.load().await {
tracing::debug!(
"[FeedbackCollector] Auto-load before save failed (non-fatal): {}",
e
);
}
self.loaded = true;
}
let viking = match &self.viking {
Some(v) => v,
None => return Ok(0),
@@ -418,7 +436,7 @@ mod tests {
#[tokio::test]
async fn test_save_without_viking_returns_zero() {
let collector = FeedbackCollector::new();
let mut collector = FeedbackCollector::new();
let saved = collector.save().await.unwrap();
assert_eq!(saved, 0);
}

View File

@@ -443,6 +443,17 @@ impl ProfileSignals {
|| self.preferred_tool.is_some()
|| self.communication_style.is_some()
}
/// 有效信号数量
pub fn signal_count(&self) -> usize {
let mut count = 0;
if self.industry.is_some() { count += 1; }
if self.recent_topic.is_some() { count += 1; }
if self.pain_point.is_some() { count += 1; }
if self.preferred_tool.is_some() { count += 1; }
if self.communication_style.is_some() { count += 1; }
count
}
}
/// 进化事件

View File

@@ -116,6 +116,34 @@ impl GrowthIntegration {
self.config.enabled
}
/// 启动时初始化:从持久化存储恢复进化引擎的信任度记录
///
/// **注意**FeedbackCollector 内部已实现 lazy-load首次 save() 时自动加载),
/// 所以此方法为可选优化 — 提前加载可避免首次反馈提交时的延迟。
/// 在中间件持有 GrowthIntegration 的场景中,由于 `&self` 限制无法调用此方法,
/// lazy-load 机制会兜底处理。
pub async fn initialize(&mut self) -> Result<()> {
if let Some(ref mut engine) = self.evolution_engine {
match engine.load_feedback().await {
Ok(count) => {
if count > 0 {
tracing::info!(
"[GrowthIntegration] Loaded {} trust records from storage",
count
);
}
}
Err(e) => {
tracing::warn!(
"[GrowthIntegration] Failed to load trust records: {}",
e
);
}
}
}
Ok(())
}
/// Enable or disable auto extraction
pub fn set_auto_extract(&mut self, auto_extract: bool) {
self.config.auto_extract = auto_extract;