Files
HomeAgent/internal/agent
JianFeeeee 71e2b83a76 fix(memory): 掐断 doc_query 的自激震荡 —— 工具输出与回填事件都不进记忆
用户指出(2026-10-22):doc_query 的结果走 NoMemory 路径,否则会对记忆块
产生自激震荡。核实后确认**两个入口都开着**。

## 回路

    doc_query
      ├─ ① 工具返回值含被召回事件的正文片段 → 作为 ToolResults 进 context
      │     → 参与向量化/关键词/蒸馏 → 同一内容被**重新注入**记忆
      ├─ ② 回填事件本身(带原 Source、完整 Blocks)进 L1
      │     → Prune 因相关而保留它们(挤掉真正的新事件)
      │     → 下一轮 Prune 又把它们归档回 L2
      └─ ⇒ 下次 doc_query 再召回同一批:块在 L1↔L2 之间反复搬迁

## ① 工具输出:doc_query 未声明 NoMemory

基础设施早就有(textForVector 里按 ToolDef.NoMemory 跳过工具输出),
但 doc_query 是**内置工具**,它的声明无处安放:
StageHost.ToolDef 只覆盖插件工具,内置工具由 executeToolCallInner 的
switch 分派,不经过注册。

修法:
- internal/sdk/tool.go:BuiltinToolDef 加 NoMemory 字段(与 ToolDef.NoMemory
  同义,两条路必须能声明同一件事)
- internal/agent/core/tooldefs.go:declareNoMemoryTool + noMemoryOf,
  由 init() 里**显式名单**登记 doc_query
- internal/agent/core/context.go:textForVector 同时查插件 ToolDef 与
  内置声明表(原来只查前者)

★ 为什么在 init 显式登记、不靠 toolDefWith 构造时登记:
  工具表是按需构造的(受 `if a.docStore != nil` 之类条件控制),
  而 textForVector 可能在构造之前被调用 ⇒ 声明会"时有时无"。
  实测踩到:构造前查 noMemoryOf("doc_query") 得到 false。

★ declareParallelTool 顺带改为**按字段合并**(原来整体覆盖):
  同一工具可能同时声明 parallel 与 noMemory,覆盖会让后登记的那项
  静默丢失 —— 声明丢一个是最难察觉的一类问题。

## ② 回填事件:加 ContextEvent.NoMemory

ContextEvent 新增 NoMemory 字段(此前只有 ToolDef/ChannelDef 有)。
restoreDocEvents 回填时置位(含存量降级路径),于是:

- textForVector 直接返回 "" ⇒ 不向量化、不参与关键词/蒸馏
- PruneWithProtected 归档前过滤掉它们 ⇒ 不再产生新的 L2 副本

语义与 ToolDef.NoMemory 一致:**原文仍在上下文可读**,只是不进计算、
不再产生新记忆。这是「回填是为了让模型读到原文」的本意。

## 判据(3 条,钉住两个入口 + 一个后果)

selfexcite_test.go:
- DocQueryDeclaresNoMemory:声明可查 + 工具输出不进 textForVector
- RestoredEventsNotReArchived:回填事件带 NoMemory 标记 + Prune 后
  L2 里不出现含回填内容的新文档(真跑 Prune 验证回路)
- RestoredEventsDontCrowdOutNewOnes:回填事件不被向量化(否则会
  参与相关性打分、挤掉新事件)

变异全部被抓住:
- Prune 不过滤 NoMemory → 「回填事件被 Prune 又归档回了 L2」
- restoreDocEvents 不置 NoMemory → 「没有 NoMemory 标记」+ 回路成立
- init 不登记 doc_query → 「未声明 NoMemory」

## 验证

- go build ./... / go vet ./... 干净
- go test ./... -count=1:58 包 0 失败
- 公开 SDK(third_party/homeagent-sdk)未改动 —— 改的是 internal/sdk
2026-10-22 20:16:57 +08:00
..