mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-15 12:15:16 +00:00
refactor(memory): 裁剪与召回收敛到唯一入口 memoryPass
把「踢出去(prune)」与「取进来(recall)」从两处各写一遍,收敛为 memoryPass(query, trigger, prune, recall) 单一入口,统一: - 同一份清洗后的 query(避免噪声带偏相关性打分); - 同一次 token 预算与召回截断; - 同一条带 trigger 的审计日志(谁、据什么触发了哪种操作)。 落地: - 新增 memorypass.go:memoryPass + pruneByQuery(原 pruneOnInput 的执行体); - pruneOnInput 只解析声明,执行委托 memoryPass; - stepToolAfter 的裁剪/召回改为一次 memoryPass 调用(去掉重复的 topK 逻辑); - 抽出 recallText,输入侧 buildTaskMemoryContext 与工具侧 recallTextFor 共用; - 输入侧召回 query 改用 CleanInput(清洗文本),与裁剪侧同一语义; - QQ qq_get_history 补齐声明 ContextPolicy=prune + RecallPolicy=auto (内容类工具:真实聊天正文既当轮用完即裁,又据正文召回)。 测试:新增 memorypass_test.go,锁死 no-op / 两轴同时生效 / 正交不互相触发 / 输入侧用清洗 query。go build/vet 干净,internal/... 全绿,qq 插件模块测试通过。
This commit is contained in:
@ -44,27 +44,49 @@ func (a *Agent) buildMemoryContext(input string, maxTokens int) string {
|
||||
//
|
||||
// 默认 auto(保持“每条输入都召回”的既有行为);输入/注入声明
|
||||
// recall_policy=none 时返回空串,从而不注入记忆。策略与裁剪(ContextPolicy)正交。
|
||||
//
|
||||
// query 取**清洗后**的输入(通道 Cleaner 的输出),与裁剪侧同一套语义:
|
||||
// 原始输入里的 ANSI/base64/JSON 包装会把相关性打分带偏。清洗为空时回退原文。
|
||||
func (a *Agent) buildTaskMemoryContext(f *TaskFrame, input string, maxTokens int) string {
|
||||
if f != nil && !a.recallDeclared(f.Evt) {
|
||||
if f == nil {
|
||||
return a.recallText(input, "input", maxTokens)
|
||||
}
|
||||
if !a.recallDeclared(f.Evt) {
|
||||
return ""
|
||||
}
|
||||
return a.buildMemoryContext(input, maxTokens)
|
||||
query := strings.TrimSpace(f.CleanInput)
|
||||
if query == "" {
|
||||
query = input
|
||||
}
|
||||
trigger := "input"
|
||||
if f.Evt != nil && f.Evt.Source != "" {
|
||||
trigger = "input:" + f.Evt.Source
|
||||
}
|
||||
return a.recallText(query, trigger, maxTokens)
|
||||
}
|
||||
|
||||
// recallTextFor 以 query 触发一次记忆召回,返回可注入的文本(空串表示无)。
|
||||
// recallTextFor 以 query 触发一次记忆召回,按当前预算截断,返回可注入的文本。
|
||||
//
|
||||
// 这是“召回”侧的单一入口:与 Prune 共用同一份**清洗后**的 query,
|
||||
// 使“取进来”(召回)与“踢出去”(裁剪)落在同一个相关性过程上。
|
||||
// trigger 仅用于日志溯源(如 "tool:qq_get_message")。
|
||||
func (a *Agent) recallTextFor(query, trigger string) string {
|
||||
if query == "" || a.indexer == nil {
|
||||
return ""
|
||||
}
|
||||
memTokens := 0 // 0 = 不截断
|
||||
if a.provider != nil {
|
||||
if a != nil && a.provider != nil {
|
||||
memTokens = ComputeTokenBudget(a.provider, a.systemPrompt).MemoryTokens
|
||||
}
|
||||
text := a.buildMemoryContext(query, memTokens)
|
||||
return a.recallText(query, trigger, memTokens)
|
||||
}
|
||||
|
||||
// recallText 是召回侧的共同实现:query → 记忆索引文本(空串表示无)。
|
||||
//
|
||||
// 输入侧的 buildTaskMemoryContext 与工具侧的 recallTextFor 都收敛到这里,
|
||||
// 使“同一份 query、同一次预算、同一条审计日志”只写一遍。
|
||||
func (a *Agent) recallText(query, trigger string, maxTokens int) string {
|
||||
if a == nil || query == "" || a.indexer == nil {
|
||||
return ""
|
||||
}
|
||||
text := a.buildMemoryContext(query, maxTokens)
|
||||
if text == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user