面试知识库

M5 · 跨会话偏好记忆与个性化#

简历 Bullet Point: 跨会话偏好记忆系统:独立记忆管家(curator)会话结束后统一判定与矛盾消解,LLM 只提供 slug,去重键由代码从 polarity/category/domain/slug 确定性派生;like 走偏好词并入检索词、dislike 走关键词双档(hard 淘汰仅限用户授权 / soft 减分含 Attenuator 语义路)+ 行为亲和(收藏→弱加分);三层记忆分治(长期 Store / 会话级 P_t / 行为历史)


开场钩子#

用户第一轮说”不要塑料的”,item_picker 正确淘汰了塑料商品。第二轮(新会话)用户说”推荐旅行包”——结果里出现了塑料材质的包。“不要塑料”在上一次会话里,这次没有了。

这逼出了长期记忆系统:偏好必须跨会话持久化


一、模块运作流程#

1.1 三层记忆分治#

存储生命周期写入时机
长期偏好PreferenceStore(SQLite 默认)永久curator 会话结束后扫
会话级 P_tSessionState单次会话planner/picker 逐轮更新
行为历史turns.json单次会话每轮追加

1.2 记忆 Schema#

PreferenceEntry 四个结构化字段:

  • polarity: like / dislike(封闭枚举)
  • category: brand / material / style / price / feature / general(封闭枚举)
  • domain: 自由文本(如 “travel_bag”)
  • slug: LLM 提供的原子标识(如 “no_plastic”)
  • dedup_key: 由 polarity_category_domain_slug 代码派生,不手拼

SessionState (P_t) 五个结构化字段:

  • current_intent / slots / rejected_options / open_questions / decisions_made
  • rejected_options 由 item_picker 机械灌入(不经 curator 猜测)

1.3 记忆管家 curator#

会话结束后独立运行,扫本轮对话提取偏好。核心原则:

  • LLM 只负责识别偏好和提供 slug,去重键由代码派生
  • 矛盾消解:新偏好与已有偏好极性冲突 → 覆盖并重置 confidence
  • 同义复述命中去重键 → 覆盖 + 提置信

1.4 偏好执行双通道#

like 通道:偏好词并入检索词(planner 输出的 prefer_keywords 拼进 query 一起编码),不再做向量级 user 塔融合(实践中零调用、按减法原则移除)

dislike 通道

  • dislike-hard(仅 source="user"blocking=True):item_picker 确定性淘汰(材质/标题含关键词 → 直接删),中文原子词跨语言匹配
  • dislike-soft(agent 学到的 / 弱表达):Attenuator 减分但不淘汰,含关键词命中路 + 语义路

授权分档核心决策:硬淘汰权只由用户显式授予,agent 学到的一律只减分——双重校验 is_blocking = blocking and source == "user"

1.5 偏好注入分层#

dislike-hard 永远全量注入 prompt(安全类不能漏),其余超阈值走语义 top-k。


二、踩坑实录#

坑 1:embedding 对否定编码弱#

  • “不要塑料”和”要塑料”向量距离很近。dislike 不能走向量通道,改关键词硬过滤。

坑 2:手拼 key 导致去重失效#

  • key 手动拼接容易拼错或不一致。改成 dedup_key 由代码从四个结构化字段派生。

坑 3:shopping_summary 写偏好被 curator 取代#

  • 早期 summary 的 new_preferences 直接落库。改成 curator 统一负责,summary 不再写偏好。

坑 4:中文硬约束跨语言失效#

  • “塑料”匹配不到英文”plastic”。加中文原子词→英文关键词映射。

三、面试问答#

Q1: 为什么 LLM 只提供 slug 而不是完整 key?#

LLM 生成的 key 不稳定——同一偏好可能产出不同 key。slug 是最小原子标识,dedup_key 由代码从 polarity/category/domain/slug 确定性派生,不依赖 LLM 一致性。

Q2: 为什么 like 和 dislike 走不同通道?#

embedding 对否定编码弱——“不要塑料”和”要塑料”距离近。like 走偏好词并入检索词(拼进 query 文本编码),dislike 走关键词匹配(硬淘汰或 Attenuator 减分)。两通道完全分离。向量级 user 塔融合原先做了但实践中长期零调用,已按减法原则移除。

Q3: rejected_options 为什么不经 curator?#

item_picker 精确知道哪些候选被淘汰了、因为什么原因。机械灌入不需要 LLM 猜测。


四、诚实边界#

维度做了没做
长期存储SQLAlchemy/DB 统一后端(SQLite/PostgreSQL)分布式存储
偏好提取curator 单次 LLM 调用多轮对话连续追踪
个性化偏好词并入检索 + 行为亲和(收藏→弱加分)向量级 user 塔融合(已删,零调用)
跨语言normalize_terms 中英归一 + term_hits 词边界判定完整多语言同义词库