fix(growth): MEDIUM-10 Experience 添加 tool_used 字段
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

根因: Experience 结构体没有 tool_used 字段,PatternAggregator 从
context 字段提取工具名(语义混淆),导致工具信息不准确。

修复:
- experience_store.rs: Experience 添加 tool_used: Option<String> 字段
  (#[serde(default)] 兼容旧数据),Experience::new() 初始化为 None
- experience_extractor.rs: persist_experiences() 从 ExperienceCandidate
  的 tools_used[0] 填充 tool_used,同时填充 industry_context
- pattern_aggregator.rs: 改用 tool_used 字段提取工具名,不再误用 context
- store_experience() 将 tool_used 加入 keywords 提升搜索命中率
This commit is contained in:
iven
2026-04-18 22:58:47 +08:00
parent 3c6581f915
commit 7cdcfaddb0
3 changed files with 13 additions and 4 deletions

View File

@@ -45,13 +45,16 @@ impl ExperienceExtractor {
Outcome::Partial => "partial", Outcome::Partial => "partial",
Outcome::Failed => "failed", Outcome::Failed => "failed",
}; };
let exp = crate::experience_store::Experience::new( let mut exp = crate::experience_store::Experience::new(
agent_id, agent_id,
&candidate.pain_pattern, &candidate.pain_pattern,
&candidate.context, &candidate.context,
candidate.solution_steps.clone(), candidate.solution_steps.clone(),
outcome_str, outcome_str,
); );
// 填充 tool_used取 tools_used 中的第一个作为主要工具
exp.tool_used = candidate.tools_used.first().cloned();
exp.industry_context = candidate.industry_context.clone();
store.store_experience(&exp).await?; store.store_experience(&exp).await?;
count += 1; count += 1;
} }

View File

@@ -48,6 +48,9 @@ pub struct Experience {
/// Which trigger signal produced this experience. /// Which trigger signal produced this experience.
#[serde(default)] #[serde(default)]
pub source_trigger: Option<String>, pub source_trigger: Option<String>,
/// Primary tool/skill used to resolve this pain point.
#[serde(default)]
pub tool_used: Option<String>,
} }
impl Experience { impl Experience {
@@ -72,6 +75,7 @@ impl Experience {
updated_at: now, updated_at: now,
industry_context: None, industry_context: None,
source_trigger: None, source_trigger: None,
tool_used: None,
} }
} }
@@ -124,6 +128,9 @@ impl ExperienceStore {
if let Some(ref industry) = exp.industry_context { if let Some(ref industry) = exp.industry_context {
keywords.push(industry.clone()); keywords.push(industry.clone());
} }
if let Some(ref tool) = exp.tool_used {
keywords.push(tool.clone());
}
let entry = MemoryEntry { let entry = MemoryEntry {
uri, uri,

View File

@@ -52,11 +52,10 @@ impl PatternAggregator {
let total_reuse: u32 = experiences.iter().map(|e| e.reuse_count).sum(); let total_reuse: u32 = experiences.iter().map(|e| e.reuse_count).sum();
let common_steps = Self::find_common_steps(&experiences); let common_steps = Self::find_common_steps(&experiences);
// 从 context 字段提取工具名context 存储的是触发工具/来源标识) // 从 tool_used 字段提取工具名
// Experience 结构没有独立的 tools 字段context 作为来源标识使用
let tools: Vec<String> = experiences let tools: Vec<String> = experiences
.iter() .iter()
.map(|e| e.context.clone()) .filter_map(|e| e.tool_used.clone())
.filter(|s| !s.is_empty()) .filter(|s| !s.is_empty())
.collect::<std::collections::HashSet<_>>() .collect::<std::collections::HashSet<_>>()
.into_iter() .into_iter()