幻兽帕鲁1.0版本最终Boss战通关视频 枯星龙怎么打
2026-07-11 3393541
2026-07-11 0
发布时间:2026-07-09
标签:AI Agent|LLM|Memory|上下文工程|工程实践
系列导航
上一篇:AI Agent 工程实践(02):为什么 Rules 要分层?
下一篇:待定(Review 机制 / Benchmark / Audit Trail)
本文是 AI Agent 工程实践 系列的第 03 篇。
在 系列第 02 篇 里,我讲了 Rules 怎么分层——那解决的是"规则该在什么时候出现"。这一篇讲一个更棘手的问题:记忆该记什么、记多久。
几乎所有 Agent 框架都在宣传"我们有 Memory"。教程也都在教你怎么"把历史对话存起来,下次再喂回去"。听起来很美好——Agent 有了记忆,就像人一样能积累经验。我照做了。然后遇到一连串问题:
上下文越来越臃肿。 每开一次对话,Agent 先"回忆"一大堆历史,token 消耗蹭蹭涨,响应越来越慢。
关键信息被稀释。 当前任务真正需要的那几条,淹没在几百条陈年记忆里。模型的注意力被无关信息分走,输出质量反而下降。
旧信息污染新决策。 上个项目用的是 FastAPI,这个项目用 Flask,可它"记得"FastAPI,于是不停给我推 FastAPI 的写法。
记忆之间开始打架。 我三个月前说"喜欢详细注释",上周又说"代码尽量精简"。两条都被记着,Agent 到底该听谁的?
一句话概括:加了记忆,Agent 没变聪明,反而被自己的记忆拖垮了。 这不是"有没有记忆"的问题,是"怎么管理记忆"的问题——和 Rules 分层一样,本质是规模问题。
最朴素的想法:把所有历史对话都存下来,下次对话时全部塞回上下文。"记得越多越聪明"嘛。
结果:上下文迅速膨胀到几千 token 起步。更糟的是,模型在长上下文里出现了典型的"迷失在中间"(Lost in the Middle)现象——放在开头和结尾的信息还记得,夹在中间的关键约束直接被忽略。
记得多 ≠ 用得上。
既然全量太重,那就只保留最近 20 条消息,老的丢掉。简单粗暴。
结果:短期是清爽了,但把"这个项目用红涨绿跌配色"这种说过一次、长期有效的关键约定也一起丢了。过几轮它又开始问"配色用什么"。滑动窗口砍掉的不是噪声,是按时间一刀切,而重要性和时间根本不成正比。
两次尝试指向同一个教训:记忆的问题,不能用"记多少"来解决,要用"怎么分类、怎么流转"来解决。
我把 Agent 一周的上下文导出来做了个统计,按"这条信息在后续任务里被真正用到"来分类:
| 记忆类型 | 举例 | 后续被用到的比例 |
|---|---|---|
| 当前任务上下文 | 正在改的文件、当前报错 | ~95% |
| 项目级约定 | 技术栈、目录规范、命名 | ~70% |
| 用户长期偏好 | 语言、代码风格、汇报格式 | ~60% |
| 一次性事实 | 某次临时路径、搜索结果 | ~3% |
| 闲聊 / 情绪 | 随口的玩笑、寒暄 | ~1% |
pie title Agent 上下文里的信息价值分布"高频复用(值得长期记)" : 20"当前会话有用(用完即弃)" : 25"噪声(记了反而添乱)" : 55
问题不在"记得多少",而在所有记忆被平等对待、生命周期完全相同:一次性的临时路径和"这个项目用 Flask"这种长期约定,被存在同一个地方、同样长久地活着、同样默认加载。
正确思路是给记忆分层,让不同价值的信息走不同的"寿命"和"加载策略":短期记忆用完即弃,长期记忆按需晋升,噪声定期清理。
这其实和上一篇的 Rule RAG 是同一个哲学:不在推理时把所有东西硬塞给模型,而是让对的信息在对的时候出现。 Rules 管的是"规则何时出现",Memory 管的是"记忆何时出现"——两者都是**上下文工程(Context Engineering)**的一部分。
我把记忆拆成四层,每层有不同的存活时间和加载策略:
| 层级 | 存什么 | 生命周期 | 是否默认加载 |
|---|---|---|---|
| Conversation(对话层) | 当前对话的原始消息流 | 会话内,session 结束即弃 | 是(但滚动裁剪) |
| Working Memory(工作记忆) | 本次会话提炼的关键状态、当前任务进度 | 单次会话 | 是(精简版) |
| Long Memory(长期记忆) | 跨会话的持久约定:项目记忆 + 用户记忆 | 长期,可更新 | 按需检索 |
| Archive(归档层) | 冷数据、历史日志、过期记忆 | 永久但压缩 | 否,仅显式检索 |
信息在这四层之间单向流动 + 定期回收:新信息先进对话层,被判定为"有长期价值"才晋升到长期记忆,长期记忆里过时的再降级到归档。
这是最容易被忽略、也最关键的一刀。很多 Agent 把两者混成一个大 memory,于是换个项目就开始串味。
判据很简单:问一句"换个项目还成立吗?" 成立的进用户记忆,不成立的进项目记忆。"我喜欢中文回复"是用户记忆;"这个项目用红涨绿跌"是项目记忆。分开存,才不会拿 A 项目的约定去污染 B 项目。
| 指标 | 全量回灌 | 分层 + 生命周期 |
|---|---|---|
| 每次对话默认加载的记忆量 | 全部历史(数百条) | 精简工作记忆 + 3 条常驻(个位数) |
| 换项目时的串味 | 频繁(旧栈污染新项目) | 基本消除(项目记忆隔离) |
| 关键长期约定的存活 | 易被滑动窗口误删 | 稳定(晋升到长期层) |
| 上下文噪声占比 | ~55% | 显著下降(噪声不晋升) |
关键点:越往下越持久、越精炼;只有对话层是易失的,其余都要落盘。晋升(promotion)是主动决策,不是自动全存。
我把落盘的记忆按"归属"组织,一眼就能看出哪些跟人走、哪些跟项目走:
# 用户级(跨项目,跟人走)~/.agent/└── MEMORY.md # 用户长期记忆:语言、风格、习惯项目级(仅当前项目)
用配置显式声明每层的寿命和晋升条件,而不是让它们"自然生长":
# memory-policy.yaml — 记忆生命周期策略conversation:scope: session# 会话内有效max_messages: 30# 滚动裁剪,超出丢弃persist: false# 不落盘working_memory:scope: sessionpersist: falsedistill: true # 会话结束前蒸馏关键状态,决定是否晋升long_memory:project:# 项目记忆scope: project# 仅当前项目生效max_chars: 3000 # 超出触发蒸馏压缩user: # 用户记忆scope: global # 跨项目生效max_chars: 4000promotion:rule: "reused >= 2 OR user_explicit == true" # 复用≥2次 或 用户明确要求 才晋升archive:trigger: "not_hit_days > 30" # 30 天未命中 → 降级归档compress: truettl_days: 365# 归档超期清理
def on_new_info(info: Info, ctx: Context) -> None:"""一条新信息进来时的处理"""# 1. 一律先进对话层ctx.conversation.append(info)# 2. 与当前任务相关 → 提炼进工作记忆if relevant_to_current_task(info, ctx.task):ctx.working_memory.upsert(info)def on_session_end(ctx: Context) -> None:"""会话结束时决定谁能"活下来" """for item in ctx.working_memory:if should_promote(item): # 复用≥2 或 用户明确要求target = "user" if is_cross_project(item) else "project"long_memory.write(item, scope=target) # 关键:分流到项目/用户# 对话层直接丢弃,不落盘def cleanup(long_memory: LongMemory) -> None:"""定期清理:去重、降级、蒸馏"""long_memory.dedup()# 合并重复/冲突项,保留最新for item in long_memory.stale(days=30):archive.move(item) # 长期未命中 → 归档if long_memory.over_limit():long_memory.distill()# 超出容量 → 蒸馏压缩
代码不多,但把三个动作说清楚了:分流写入、按条件晋升、定期清理。 这三个动作缺一个,记忆迟早失控。
| 候选方案 | 优点 | 缺点 | 为什么不选 |
|---|---|---|---|
| 全量回灌历史 | 实现最简单,"绝不遗漏" | 上下文爆炸、迷失在中间、噪声稀释注意力 | 记得多不等于用得上,规模一大必崩 |
| 滑动窗口(只留最近 N 条) | 上下文恒定、实现简单 | 按时间一刀切,误删长期约定 | 重要性和时间不成正比,砍错了对象 |
| 全部塞向量库,用时检索 | 容量无上限、语义召回 | 召回噪声多、无生命周期、冷热不分 | 只解决"存",没解决"该不该记、记多久" |
| 四层 + 生命周期 | 冷热分层、项目/用户隔离、可晋升可清理 | 需设计晋升与清理策略 | 选择理由:唯一同时管住"记什么、记多久、给谁"的方案 |
分层不是越多越好。 如果你的 Agent 只是个单轮问答机器人,压根不需要跨会话记忆——一个滑动窗口就够了。不要在不需要长期记忆的地方强行搭四层。 向量检索也不是对立面:它可以作为 Archive 层的召回手段,和分层是互补而非二选一。