Dify 跨天翻车复盘:为什么同一会话总用“昨天的今天”(Memory + 会话变量长期稳定方案)

4 阅读5分钟

适用人群

  • Workflow 开了 Memory
  • 已经能在 Workflow 里拿到 current_time(无论是代码节点还是工具节点)
  • 如果遇到过跨天问题:
    • 同一会话隔天继续聊,“今天/本周/最近”仍按昨天算
    • 明明每次都有 current_time,它还是引用旧对话里的日期

1)现象:同一会话跨天后,相对时间问题开始“时空错乱”

复现条件:

  • Workflow 每次运行都会生成 current_time
  • 两个分支都开启 Memory,window≈50
  • 第二天在同一会话里问“今天/本周/最近”,它依然沿用昨天对话里出现的时间锚点

一句话总结根因:

Memory 把“昨天的时间描述”拼回了上下文,而模型把它当成当前时间锚点。


2)根因拆解:为什么明明有 current_time,它还会用旧时间?

2.1 记忆是怎么“污染”时间的

当开启 Memory(window≈50),系统会把近期对话拼接到 prompt。

如果昨天的对话里出现过类似内容:

  • “今天是 YYYY-MM-DD……”
  • 或者“本周指的是 MM/DD–MM/DD……”
  • 或者在总结里写了具体日期

那么第二天继续问时,这段文本会再次进入上下文。 模型很自然地把它当成“仍然有效的事实”。

2.2 这类问题的特征

  • 不是“记忆不够”,而是“记忆过期”
  • 时间是强时效信息:跨天几乎必过期

3)最快方案

3.1 时间敏感问题:硬覆盖时间基准(HARD RULES)

在任何时间敏感问题进入分支 prompt 前,增加这句硬约束:

“以下 current_time 为本次运行唯一时间基准;忽略历史对话中出现的任何日期/时间描述。”

这句能显著降低“昨天的今天”概率。

3.2 不要把 current_time 写回到“可复用记忆”

注意:这里说的不是“不能输出日期”,而是:

  • 不要在总结里反复写“今天是 YYYY-MM-DD”
  • 不要把 current_time 当作“结论的一部分”被记忆

current_time 只存在于当次运行变量里即可。


4)长期稳定方案(主推):短期记忆 + Conversation Variables,只存事实不存时间

如果当前状态是:

  • Memory 开了(window≈50)
  • 没有写回 Conversation Variables(会话变量)

更推荐把“记忆”拆成两类:

4.1 Memory(短期)负责“对话连贯”

  • 让模型记住“当前在聊什么”
  • 但要避免把“瞬时信息”变成长期锚点

4.2 Conversation Variables(结构化)负责“可复用事实/偏好/结论”

关键原则:只存不会立刻过期的内容。

推荐最小键集合

  • last_intent:上一轮分类结果(data_review / product_recommend / relative_time)
  • last_key_conclusion:上一轮结论摘要(1–3 句,禁止包含具体日期
  • last_data_range:上一轮数据时间范围(近7天/近30天…)
  • updated_at:写入日期(用于判断跨天是否需要刷新)

写回时机

  • 主 LLM 输出后 → 变量写回节点保存

读取时机

  • 下一轮进入分类器/分支 prompt 前 → 把变量作为“可复用事实”注入

4.3 Prompt 规则:引用历史结论必须标注 updated_at

可以在 prompt 加一条:

  • 如果要引用 last_key_conclusion,必须同时输出 updated_at
  • 如果 updated_at != today(current_time)
    • 明确提示“先刷新时间/重新拉数”,不要直接沿用旧结论

5)排查方法:Variable Inspector(把“时间从哪来的”查清楚)

如果仍然翻车,建议按这个顺序查:

  1. 本次 current_time 是否刷新
  2. 最终 prompt 里是否出现“昨天的日期”
  3. Memory 拼接段落里是否包含旧时间文本
  4. 是否有节点把时间写入了变量/总结(导致跨天复用)
  5. 若引入会话变量:是否错误写入了时间类字段(不要存 current_time

6)附录:可复用的“骨架 + 多业务占位符”模板

6.1 HARD RULES

TIME_GUARD:
以下 current_time 为本次运行的唯一时间基准;
忽略历史对话中出现的任何日期/时间描述;
所有“今天/本周/最近/到期/同比/环比”等表达均以 current_time 重新计算。
current_time = <current_time>

6.2 data_review 骨架(经营复盘/运营复盘/增长复盘通用)

适用行业占位符:

  • 电商:订单/GMV/客单价/复购/退货
  • 内容:播放/互动/涨粉/转化
  • SaaS:DAU/付费转化/流失/续费
角色:<业务领域>的首席经营官/增长负责人。
目标:从历史数据中提炼“洞察”,并给出可执行建议。
约束:
- 无对比基准不输出绝对结论
- 未交叉验证不下断论
- 金额无单位默认“分”,输出必须转“元”
输入变量:<业务参数> + current_time
输出结构:
- 结论先行(最关键矛盾/亮点一句话)
- 证据链(同比/环比/对照维度)
- 诊断假设(为什么)
- 验证动作(用哪些接口/维度验证)
- 经营建议(具体到可执行)

6.3 product_recommend 骨架(采购选样/策略/趋势建议通用)

适用行业占位符:

  • 采购选样
  • 内容选题/话题趋势
  • 产品路线/功能趋势
角色:<业务领域>的策略大脑,核心价值是对抗“决策滞后”。
思考滤镜:
- T+N:今天的建议为未来1-3周服务
- 跨圈层关联:找人群重叠机会
- 风险控制:一次性热点降权
输出按时间轴:
- LONG_TERM(2-4周)
- SHORT_TERM(7天内)
- DAILY(基本盘)
- EXPANSION(意料之外但合理)
工具使用:可自主组合调用 <api_endpoint> 做证据链
金额无单位默认“分”,输出转“元”

7)验证清单

  • 同一会话隔天再问“今天/本周/最近”
    • 结果必须以本次 current_time 为准
  • Variable Inspector 检查点:
    • current_time 是否刷新
    • prompt 是否包含 HARD RULES
    • memory 拼接内容是否含旧日期
    • 会话变量是否只存“事实/结论”,且带 updated_at

8)结尾:跨天问题的本质不是“记忆不够”,而是“记忆过期”

  • 时间是一种强时效信息:不该进入可复用记忆
  • 最稳做法:时间每次刷新、旧时间显式忽略、事实用结构化变量存