feat(memory): 记忆 P2(项目索引物化 / decay 回写 / 作用域写规则 / 静默吞点 + loop 级只读红线测试)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

This commit is contained in:
AskaEth committed 2026-10-05 11:47:39 +08:00
1 parent 9b903a89bc
commit 509dc412eb
12 files changed
+660 -55

No files matched your search

+21
View File
@@ -2,6 +2,7 @@ package memory
import (
"context"
"errors"
"fmt"
"log/slog"
"sort"
@@ -211,6 +212,10 @@ func NewRetriever(store *Store, opts ...RetrieverOption) *Retriever {
}
if store != nil {
store.attachVectorIndex(r.vindex)
// 项目索引同时接到写入路径:项目作用域记忆的 ProjectID 落的索引
// 条目因此始终存在(见 store_project.go),Retriever.projectFor 才
// 有东西可解析。
store.attachProjectIndex(r.projectStore)
}
return r
}
@@ -293,6 +298,9 @@ func (r *Retriever) Retrieve(ctx context.Context, personaID, query string, topK
if len(results) > topK {
results = results[:topK]
}
// 命中即使用:把返回命中的衰减物化回写 decay_weight(design §2,
// 裁决 Q3)。失败只记日志,绝不影响本次检索结果。
r.persistDecay(ctx, results, relevance, now)
return results, nil
}
@@ -432,12 +440,25 @@ func (r *Retriever) vectorIndexScores(ctx context.Context, items []MemoryItem, q
// 没有项目索引存储、条目不是
// 项目作用域、或条目不带 ProjectID 时返回 nil。加载失败按「无
// 项目」处理,而不是让整次检索失败(design §3 项目索引各角色可查)。
//
// 加载失败**必须留下带来源的日志**(审计 2026-10-05 §7 静默吞点):
// 「项目行不存在」(ErrProjectNotFound,项目记忆的 project_id 悬空)是
// 数据状态,按 Debug 记;其余错误(存储故障等)按 Warn 记,使真实的
// 项目索引故障不会被当成「这条记忆本来就没项目」而无限静默。两条都不
// 影响检索结果,条目照常返回,只是不带 Project。
func (r *Retriever) projectFor(ctx context.Context, it MemoryItem) *projectindex.Project {
if r.projectStore == nil || it.Scope != ScopeProject || strings.TrimSpace(it.ProjectID) == "" {
return nil
}
p, err := r.projectStore.GetProject(ctx, it.ProjectID)
if err != nil {
if errors.Is(err, projectindex.ErrProjectNotFound) {
r.log.Debug("memory: project link not found, result returned without project",
"project_id", it.ProjectID)
} else {
r.log.Warn("memory: project link lookup failed, result returned without project",
"project_id", it.ProjectID, "error", err)
}
return nil
}
return p