package memory import ( "math" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/embedding" ) // 本文件收拢语义打分的辅助件:内存余弦相似度与「索引没答上、改走 // 内存回退」的一次性告警。它们的用量小但分散,独立成文件是为了让 // retrieve.go 保持可读(文件 ≤500 行,AGENTS §10)。 // cosineSim 计算两个向量的余弦相似度,由调用方夹到 [0,1]。 // 长度为零或不一致的向量得 0。 func cosineSim(a, b embedding.Vector) float64 { if len(a) == 0 || len(b) == 0 || len(a) != len(b) { return 0 } var dot, na, nb float64 for i := range a { dot += float64(a[i]) * float64(b[i]) na += float64(a[i]) * float64(a[i]) nb += float64(b[i]) * float64(b[i]) } if na == 0 || nb == 0 { return 0 } return dot / (math.Sqrt(na) * math.Sqrt(nb)) } // warnSemanticFallback 报告一次「接入了向量索引但在候选集内无命中, // 已改走内存余弦」。它每个检索器只报一次:该状态在一次运行里 // 基本不变(索引尚未写入或 embedder 维度不匹配),逐次 Retrieve // 重复告警只会淹没有用日志。索引报错本身由 vectorIndexScores 以 // Warn 记录,这里用 Debug 区分「已知会回退」与「真的出错了」。 func (r *Retriever) warnSemanticFallback() { r.seedMu.Lock() defer r.seedMu.Unlock() if r.fallbackWarned { return } r.fallbackWarned = true r.log.Debug("memory: vector index had no candidate hit, using in-memory cosine fallback") }