From 4c62074a616884b2e24c9fa6515110a24c58a928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=94=AF?= Date: Sun, 6 Sep 2026 00:32:27 +0800 Subject: [PATCH] =?UTF-8?q?fix(consolidate):=20=E6=8C=89=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E5=88=86=E7=BB=84=E6=89=B9=E9=87=8FLLM=E5=86=B3=E7=AD=96,?= =?UTF-8?q?=E6=B6=88=E9=99=A4O(n=C2=B2)=E8=B0=83=E7=94=A8=E9=A3=8E?= =?UTF-8?q?=E6=9A=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原实现每对高相似记忆调一次LLM → limit=100产生4950对 → 223s+未完成 → 每天processed=0(非namespace过滤bug)。改为: 外层目标i,内层收集 全部高相似候选,每目标一次LLM(UpdatePrompt原生支持多候选)。 验证: limit=20 → 4.3s返回 processed=1 updated=1; limit=100 2min(受 llama单slot排队限制)对每日低频可用。 --- go/internal/api/server.go | 64 ++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/go/internal/api/server.go b/go/internal/api/server.go index 5797efd..6109241 100644 --- a/go/internal/api/server.go +++ b/go/internal/api/server.go @@ -864,40 +864,54 @@ func NewServer() http.Handler { ignored := 0 errors_ := 0 + // 按目标分组整合:外层 i 为目标,内层收集所有高相似候选, + // 每个目标只调一次 LLM(UpdatePrompt 原生支持多候选),避免 O(n²) LLM 调用风暴。 + // 2026-09-06 fix(t_04 ④): 原实现每对相似记忆调一次 LLM → limit=100 产生 4950 对 + // → 跑 223s+ 未完成 → 每天 processed=0(不是 namespace 过滤 bug)。 for i := 0; i < len(mems); i++ { + // 收集所有与 mems[i] 高相似的候选(j > i 且未处理) + var cands []distill.MemoryCandidate for j := i + 1; j < len(mems); j++ { + if mems[j].Content == "" { + continue + } sim := distill.TextSimilarity(mems[i].Content, mems[j].Content) if sim < 0.5 { continue } - // 高相似 → LLM 决策(以 j 为目标,i 为候选) - result, err := routes.DistillEngineRef.ConsolidateMemory( - distill.MemoryCandidate{ID: mems[j].ID, Content: mems[j].Content}, - []distill.MemoryCandidate{{ID: mems[i].ID, Content: mems[i].Content}}, - ) - if err != nil { - errors_++ - continue - } - processed++ - switch result.Action { - case "update": - if result.NewMemory != "" { - if err := ldb.UpdateMemoryContent(mems[j].ID, result.NewMemory, "consolidate"); err != nil { - log.Printf("[consolidate] update failed %s: %v", mems[j].ID, err) - } else { - updated++ - } - } - case "delete": - if err := ldb.SoftDelete(mems[j].ID, "consolidate: conflict"); err != nil { - log.Printf("[consolidate] delete failed %s: %v", mems[j].ID, err) + cands = append(cands, distill.MemoryCandidate{ID: mems[j].ID, Content: mems[j].Content}) + } + if len(cands) == 0 { + continue + } + + // 一次 LLM 决策:目标 mems[i] + 全部高相似候选 + result, err := routes.DistillEngineRef.ConsolidateMemory( + distill.MemoryCandidate{ID: mems[i].ID, Content: mems[i].Content}, + cands, + ) + if err != nil { + errors_++ + continue + } + processed++ + switch result.Action { + case "update": + if result.NewMemory != "" { + if err := ldb.UpdateMemoryContent(mems[i].ID, result.NewMemory, "consolidate"); err != nil { + log.Printf("[consolidate] update failed %s: %v", mems[i].ID, err) } else { - deleted++ + updated++ } - default: - ignored++ } + case "delete": + if err := ldb.SoftDelete(mems[i].ID, "consolidate: conflict"); err != nil { + log.Printf("[consolidate] delete failed %s: %v", mems[i].ID, err) + } else { + deleted++ + } + default: + ignored++ } }