// 织忆 MemoryWeave — 自优化引擎 package selfoptimize import ( "math" "sync" "time" ) // ─── 自优化仪表盘 ──────────────────────────────────────── type Dashboard struct { mu sync.RWMutex UsefulCount int `json:"useful_count"` NotUsefulCount int `json:"not_useful_count"` TotalRecalls int `json:"total_recalls"` HitCount int `json:"hit_count"` ClosedGaps int `json:"closed_gaps"` TotalGaps int `json:"total_gaps"` CascadeFixedTotal int `json:"cascade_fixed_total"` TotalFixes int `json:"total_fixes"` DeprecatedToday int `json:"deprecated_today"` DistillLossSum float64 `json:"distill_loss_sum"` DistillLossCount int `json:"distill_loss_count"` AutoResolvedConflicts int `json:"auto_resolved_conflicts"` TotalConflicts int `json:"total_conflicts"` } var Dash = &Dashboard{} // Metrics 返回 7 项核心指标 func (d *Dashboard) Metrics() map[string]float64 { d.mu.RLock() defer d.mu.RUnlock() usefulRate := 0.0 if d.UsefulCount+d.NotUsefulCount > 0 { usefulRate = float64(d.UsefulCount) / float64(d.UsefulCount+d.NotUsefulCount) } hitRate := 0.0 if d.TotalRecalls > 0 { hitRate = float64(d.HitCount) / float64(d.TotalRecalls) } gapRate := 0.0 if d.TotalGaps > 0 { gapRate = float64(d.ClosedGaps) / float64(d.TotalGaps) } cascadeRate := 0.0 if d.TotalFixes > 0 { cascadeRate = float64(d.CascadeFixedTotal) / float64(d.TotalFixes) } avgLoss := 0.0 if d.DistillLossCount > 0 { avgLoss = d.DistillLossSum / float64(d.DistillLossCount) } autoRate := 0.0 if d.TotalConflicts > 0 { autoRate = float64(d.AutoResolvedConflicts) / float64(d.TotalConflicts) } return map[string]float64{ "recall_usefulness_rate": math.Round(usefulRate*100) / 100, "recall_hit_rate": math.Round(hitRate*100) / 100, "gap_closure_rate": math.Round(gapRate*100) / 100, "cascade_fix_rate": math.Round(cascadeRate*100) / 100, "deprecated_per_day": float64(d.DeprecatedToday), "avg_distill_loss": math.Round(avgLoss*100) / 100, "auto_resolve_rate": math.Round(autoRate*100) / 100, } } func (d *Dashboard) RecordRecall(hit bool) { d.mu.Lock() defer d.mu.Unlock() d.TotalRecalls++ if hit { d.HitCount++ } } func (d *Dashboard) RecordFeedback(useful bool) { d.mu.Lock() defer d.mu.Unlock() if useful { d.UsefulCount++ } else { d.NotUsefulCount++ } } // ─── 知识缺口检测 ──────────────────────────────────────── type GapType string const ( GapUnknown GapType = "A" // 真不知道 GapSynonym GapType = "B" // 同义词不匹配 GapRecallFailed GapType = "C" // 召回失败 GapFragmented GapType = "D" // 碎片化 ) type Gap struct { Topic string `json:"topic"` Type GapType `json:"type"` MissCount int `json:"miss_count"` CreatedAt time.Time `json:"created_at"` Closed bool `json:"closed"` } type GapDetector struct { mu sync.RWMutex gaps map[string]*Gap misses map[string]int } func NewGapDetector() *GapDetector { return &GapDetector{ gaps: make(map[string]*Gap), misses: make(map[string]int), } } // RecordMiss 记录一次召回失败 func (gd *GapDetector) RecordMiss(topic string) *Gap { gd.mu.Lock() defer gd.mu.Unlock() gd.misses[topic]++ if gd.misses[topic] >= 3 { if _, exists := gd.gaps[topic]; !exists { gap := &Gap{ Topic: topic, Type: gd.classifyGap(topic), MissCount: gd.misses[topic], CreatedAt: time.Now(), } gd.gaps[topic] = gap return gap } } return nil } func (gd *GapDetector) classifyGap(topic string) GapType { // 简单启发式:大写缩写 → 同义词;中文 → 可能是真的不知道 for _, r := range topic { if r >= 'A' && r <= 'Z' { return GapSynonym } } return GapUnknown } func (gd *GapDetector) List() []*Gap { gd.mu.RLock() defer gd.mu.RUnlock() var result []*Gap for _, g := range gd.gaps { result = append(result, g) } return result } func (gd *GapDetector) Close(topic string) { gd.mu.Lock() defer gd.mu.Unlock() if g, ok := gd.gaps[topic]; ok { g.Closed = true } } // ─── 因果追踪 ──────────────────────────────────────────── type TraceEntry struct { MemoryID string `json:"memory_id"` Version int `json:"version"` Content string `json:"content"` Source string `json:"source"` // muchen_oral / config_parse / agent_infer / llm_distill Trigger string `json:"trigger"` // 什么触发了这次修改 UpdatedAt time.Time `json:"updated_at"` } type CausalTracker struct { mu sync.RWMutex entries map[string][]*TraceEntry // memory_id → version history deps map[string][]string // memory_id → depends_on[] } func NewCausalTracker() *CausalTracker { return &CausalTracker{ entries: make(map[string][]*TraceEntry), deps: make(map[string][]string), } } // RecordVersion 记录版本变更 func (ct *CausalTracker) RecordVersion(memoryID, content, source, trigger string) { ct.mu.Lock() defer ct.mu.Unlock() entry := &TraceEntry{ MemoryID: memoryID, Version: len(ct.entries[memoryID]) + 1, Content: content, Source: source, Trigger: trigger, UpdatedAt: time.Now(), } ct.entries[memoryID] = append(ct.entries[memoryID], entry) } // AddDependency A depends_on B func (ct *CausalTracker) AddDependency(a, b string) { ct.mu.Lock() defer ct.mu.Unlock() ct.deps[a] = append(ct.deps[a], b) } // GetAffected 当 memoryID 被修正时,返回所有依赖它的记忆 func (ct *CausalTracker) GetAffected(memoryID string, visited map[string]bool) []string { ct.mu.RLock() defer ct.mu.RUnlock() if visited == nil { visited = make(map[string]bool) } if visited[memoryID] { return nil } visited[memoryID] = true var affected []string for dependent, deps := range ct.deps { for _, d := range deps { if d == memoryID && !visited[dependent] { affected = append(affected, dependent) affected = append(affected, ct.GetAffected(dependent, visited)...) } } } return affected } // SourceTrust 来源信任度 func SourceTrust(source string) float64 { switch source { case "muchen_oral": return 1.0 case "muchen_feishu": return 0.95 case "config_parse": return 0.7 case "agent_infer": return 0.5 case "llm_distill": return 0.4 default: return 0.3 } } // IsVolatile 判断一条记忆是否易变(频繁修正) func (ct *CausalTracker) IsVolatile(memoryID string) bool { ct.mu.RLock() defer ct.mu.RUnlock() return len(ct.entries[memoryID]) >= 3 } // ─── 记忆预取 ──────────────────────────────────────────── type PrefetchGraph struct { mu sync.RWMutex coOccurs map[string]map[string]int // A → {B: count} } func NewPrefetchGraph() *PrefetchGraph { return &PrefetchGraph{coOccurs: make(map[string]map[string]int)} } func (pg *PrefetchGraph) RecordCoAccess(a, b string) { pg.mu.Lock() defer pg.mu.Unlock() if pg.coOccurs[a] == nil { pg.coOccurs[a] = make(map[string]int) } pg.coOccurs[a][b]++ } // GetPrefetch 获取某个 query 的预取候选项 func (pg *PrefetchGraph) GetPrefetch(query string) []string { pg.mu.RLock() defer pg.mu.RUnlock() related := pg.coOccurs[query] if related == nil { return nil } var result []string for topic, count := range related { total := 0 for _, c := range pg.coOccurs[query] { total += c } prob := float64(count) / float64(total) if prob > 0.6 { result = append(result, topic) } } return result }