feat(dispatcher): 长期偏好记忆抽取(补全记忆闭环)

memorize 的 TODO 落地:写回阶段(异步、离热路径)从本轮对话用 LLM 抽取用户
长期稳定偏好 → 与已有画像去重 → memory_upsert 登记。

- extractMemory:模型/工具不可用或输入过短则跳过;复用 llmCtx 超时;
  抽取 prompt 只取长期偏好、忽略一次性信息。
- 纯逻辑(可单测):parsePrefs(容忍 json 代码围栏)、parseProfile(把 memory_get
  渲染的"- 维度:值"解析回 map,兼容全/半角冒号)、filterNewPrefs(新增/变更才留,
  同批同 key 去重)。
- 单测覆盖三者;LLM 抽取调用沿用已验证的 pool.Chat 模式。

至此记忆闭环:召回(memory_get) + 历史写回 + 偏好自动抽取 全通。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-06-18 12:47:49 +08:00
parent aa3139da68
commit 9c19bb44f1
3 changed files with 158 additions and 2 deletions
@@ -172,8 +172,8 @@ func (o *Orchestrator) memorize(t *contract.Task, answer string) {
log.Printf("[eino] (writeback) task %s 已落会话历史 session=%s", t.ID, sid)
}
if uid != "" {
log.Printf("[eino] (writeback) task %s 待抽取 user=%s 的新偏好记忆", t.ID, uid)
// TODO: 抽取 LLM → 去重/更新 → memory_upsert
// 从本轮对话抽取长期偏好 → 去重 → memory_upsert(离开热路径,已在 goroutine 内)。
o.extractMemory(context.Background(), uid, dsl.Compile(t.Graph).Query, answer)
}
}