222 lines
5.8 KiB
Go
222 lines
5.8 KiB
Go
// 织忆 MemoryWeave — 被动验证器 (PassiveValidator) P1/P2/P3 三层匹配
|
|
package selfoptimize
|
|
|
|
import (
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// ─── 被动验证器 ──────────────────────────────────────────
|
|
|
|
// ValidationLevel 验证层级
|
|
type ValidationLevel int
|
|
|
|
const (
|
|
P1_ExactMatch ValidationLevel = 1 // 精确匹配:牧尘再次提到同一事实
|
|
P2_PartialMatch ValidationLevel = 2 // 部分匹配:子串/同义词
|
|
P3_ImpliedMatch ValidationLevel = 3 // 隐含验证:牧尘基于该记忆做出的决策成功
|
|
)
|
|
|
|
// ValidationRecord 单条验证记录
|
|
type ValidationRecord struct {
|
|
MemoryID string `json:"memory_id"`
|
|
Level ValidationLevel `json:"level"`
|
|
MatchedBy string `json:"matched_by"` // 匹配到的内容片段
|
|
Confidence float64 `json:"confidence"` // 当前信任度
|
|
LastSeen time.Time `json:"last_seen"`
|
|
PassiveHits int `json:"passive_hits"` // 被动匹配次数
|
|
}
|
|
|
|
// PassiveValidator 被动验证引擎
|
|
type PassiveValidator struct {
|
|
mu sync.RWMutex
|
|
records map[string]*ValidationRecord // memory_id → record
|
|
boostP1 float64 // P1 信任度提升 (default 0.1)
|
|
boostP2 float64 // P2 信任度提升 (default 0.05)
|
|
boostP3 float64 // P3 信任度提升 (default 0.15)
|
|
maxConf float64 // 最大信任度 (default 0.99)
|
|
}
|
|
|
|
var Validator = NewPassiveValidator()
|
|
|
|
func NewPassiveValidator() *PassiveValidator {
|
|
return &PassiveValidator{
|
|
records: make(map[string]*ValidationRecord),
|
|
boostP1: 0.10,
|
|
boostP2: 0.05,
|
|
boostP3: 0.15,
|
|
maxConf: 0.99,
|
|
}
|
|
}
|
|
|
|
// Validate 牧尘的新输入到达时,检查是否验证了已有记忆
|
|
func (pv *PassiveValidator) Validate(userInput string, existingMemories []MemoryForValidation) []*ValidationRecord {
|
|
pv.mu.Lock()
|
|
defer pv.mu.Unlock()
|
|
|
|
var validated []*ValidationRecord
|
|
|
|
for _, mem := range existingMemories {
|
|
level := pv.checkMatch(userInput, mem.Content)
|
|
if level == 0 {
|
|
continue
|
|
}
|
|
|
|
record, exists := pv.records[mem.ID]
|
|
if !exists {
|
|
record = &ValidationRecord{
|
|
MemoryID: mem.ID,
|
|
Confidence: mem.QualityScore,
|
|
PassiveHits: 0,
|
|
}
|
|
pv.records[mem.ID] = record
|
|
}
|
|
|
|
record.Level = level
|
|
record.MatchedBy = extractMatchFragment(userInput, mem.Content)
|
|
record.LastSeen = time.Now()
|
|
record.PassiveHits++
|
|
|
|
// 按层级提升信任度
|
|
switch level {
|
|
case P1_ExactMatch:
|
|
record.Confidence = minConf(record.Confidence+pv.boostP1, pv.maxConf)
|
|
case P2_PartialMatch:
|
|
record.Confidence = minConf(record.Confidence+pv.boostP2, pv.maxConf)
|
|
case P3_ImpliedMatch:
|
|
record.Confidence = minConf(record.Confidence+pv.boostP3, pv.maxConf)
|
|
}
|
|
|
|
validated = append(validated, record)
|
|
}
|
|
return validated
|
|
}
|
|
|
|
// checkMatch 三层匹配检测
|
|
func (pv *PassiveValidator) checkMatch(userInput, memoryContent string) ValidationLevel {
|
|
// P1: 精确匹配 — memoryContent 是 userInput 的子串(或相反)
|
|
if strings.Contains(userInput, memoryContent) || strings.Contains(memoryContent, userInput) {
|
|
return P1_ExactMatch
|
|
}
|
|
|
|
// P2: 部分匹配 — 关键词重叠 > 60%
|
|
overlap := keywordOverlap(userInput, memoryContent)
|
|
if overlap > 0.6 {
|
|
return P2_PartialMatch
|
|
}
|
|
|
|
// P3: 隐含匹配 — 共享实体引用
|
|
entities1 := extractEntities(userInput)
|
|
entities2 := extractEntities(memoryContent)
|
|
if sharedEntities(entities1, entities2) {
|
|
return P3_ImpliedMatch
|
|
}
|
|
|
|
return 0 // 无匹配
|
|
}
|
|
|
|
// GetConfidence 获取某条记忆的被动验证信任度
|
|
func (pv *PassiveValidator) GetConfidence(memoryID string) float64 {
|
|
pv.mu.RLock()
|
|
defer pv.mu.RUnlock()
|
|
if record, ok := pv.records[memoryID]; ok {
|
|
return record.Confidence
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// GetRecords 获取所有验证记录(按 confidence 降序)
|
|
func (pv *PassiveValidator) GetRecords() []*ValidationRecord {
|
|
pv.mu.RLock()
|
|
defer pv.mu.RUnlock()
|
|
var records []*ValidationRecord
|
|
for _, r := range pv.records {
|
|
records = append(records, r)
|
|
}
|
|
if records == nil {
|
|
return []*ValidationRecord{}
|
|
}
|
|
return records
|
|
}
|
|
|
|
// ─── 辅助函数 ──────────────────────────────────────────
|
|
|
|
type MemoryForValidation struct {
|
|
ID string
|
|
Content string
|
|
QualityScore float64
|
|
}
|
|
|
|
func keywordOverlap(a, b string) float64 {
|
|
wordsA := strings.Fields(strings.ToLower(a))
|
|
wordsB := strings.Fields(strings.ToLower(b))
|
|
setA := make(map[string]bool, len(wordsA))
|
|
for _, w := range wordsA {
|
|
setA[w] = true
|
|
}
|
|
overlap := 0
|
|
for _, w := range wordsB {
|
|
if setA[w] {
|
|
overlap++
|
|
}
|
|
}
|
|
if len(wordsA) == 0 || len(wordsB) == 0 {
|
|
return 0
|
|
}
|
|
return float64(overlap) / float64(maxInt(len(wordsA), len(wordsB)))
|
|
}
|
|
|
|
func extractEntities(text string) []string {
|
|
// 简单启发式:提取大写开头的词和中文专有名词
|
|
words := strings.Fields(text)
|
|
var entities []string
|
|
for _, w := range words {
|
|
if len(w) > 1 && (w[0] >= 'A' && w[0] <= 'Z') {
|
|
entities = append(entities, w)
|
|
}
|
|
}
|
|
return entities
|
|
}
|
|
|
|
func sharedEntities(a, b []string) bool {
|
|
set := make(map[string]bool, len(a))
|
|
for _, e := range a {
|
|
set[e] = true
|
|
}
|
|
for _, e := range b {
|
|
if set[e] {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func extractMatchFragment(userInput, memoryContent string) string {
|
|
// 返回重叠部分
|
|
if idx := strings.Index(userInput, memoryContent); idx >= 0 {
|
|
return memoryContent
|
|
}
|
|
// 返回共享关键实体
|
|
entities := extractEntities(memoryContent)
|
|
if len(entities) > 0 {
|
|
return strings.Join(entities, ", ")
|
|
}
|
|
return memoryContent[:minInt(50, len(memoryContent))]
|
|
}
|
|
|
|
func minConf(a, b float64) float64 {
|
|
if a < b { return a }
|
|
return b
|
|
}
|
|
|
|
func maxInt(a, b int) int {
|
|
if a > b { return a }
|
|
return b
|
|
}
|
|
|
|
func minInt(a, b int) int {
|
|
if a < b { return a }
|
|
return b
|
|
}
|