news 2026/7/11 2:15:20

Agent Memory 设计笔记:从短期上下文到长期经验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent Memory 设计笔记:从短期上下文到长期经验

echo-agent 前身为 2025 年 11 月启动的个人助理项目 fubot,最初面向长期陪伴型个人智能体,围绕认知记忆、上下文延续、用户偏好沉淀、任务闭环与持续自我优化展开。随着真实场景迭代,项目逐步形成多入口接入、统一事件模型、消息总线、Agent Loop、多模型抽象、工具调用、MCP 接入、任务调度、权限审批、运行轨迹、长期记忆和受控自演进等能力。目前已支持微信、QQ、CLI、Gateway、Webhook、Cron 等入口,服务用户超过 20 万、累计下载超过 50 万,是面向长期运行、记忆增强和可持续成长智能体的开源 Agent Runtime。

项目地址:https://github.com/fuyuxiang/echo-agent

你让 Agent “继续修复昨天那个测试失败”。

它打开仓库,重新跑测试,却忘了昨天已经确认过:这个项目不能直接用npm test,要先进子目录,再用pnpm。它也忘了你说过“先给结论,再展开原因”,于是又输出了一大段过程分析。

这不是单纯的上下文长度问题,而是 Agent 没有把长期有用的信息从会话噪声里提取出来。

记忆系统要解决的不是“把所有聊天记录塞回模型”,而是让 Agent 知道:什么值得记、记到哪里、何时召回、何时更新或忘记

问题入口

如果只看传统文本型 Chatbot,它的基本形态仍是:用户输入文本,模型返回文本。历史消息可以维持短期连贯性,但窗口被截断,或者新会话开始,它就很容易回到“第一次见面”的状态。

Agent 不一样。它会读文件、跑命令、修改代码、调用工具。它对用户偏好、项目事实、失败经验和环境约束的理解,会直接影响后续行动。

“这个项目使用 pytest”“用户偏好中文回答”“配置文件在config/default.yaml”“某次失败由路径策略阻断导致”,这些不是普通聊天记录,而是未来任务会反复用到的行为依据。

会话历史记录的是发生过什么;记忆记录的是以后还值得使用什么。

所以,记忆不是更长的上下文窗口,也不是完整聊天归档。它是一套选择性持久化机制:从大量交互中挑出少量稳定、有用、可归属的信息,并让这些信息在未来恰当地影响 Agent 行为。

概念边界

记忆系统最容易混淆三件事:session、compression 和 memory。

机制解决的问题典型内容主要风险
Session恢复会话发生过什么消息、工具调用、状态太长、太碎
Compression保住当前任务重点摘要、目标、未完成事项压错重点
Memory保存未来仍有价值的经验用户偏好、项目事实、调试教训写错后长期污染

Session 像操作日志,适合追溯。Compression 像会议纪要,适合让当前对话继续推进。Memory 更像工程师的长期经验库,适合在新任务、新会话、上下文压缩之后重新提供关键背景。

如果把所有 session 都当 memory,系统会被临时探索、错误尝试和过期状态污染。如果只依赖 compression,长期偏好和稳定项目事实又会随着窗口滚动被丢掉。

记忆分层

为了不停留在抽象层面,下面以 echo-agent 的实现为例。

echo-agent 把记忆分成四个层级:workingepisodicsemanticarchival

WorkingMemory是当前任务的短期缓存,只存在于进程内,不持久化。它适合保存“正在修改第 12 章”“下一步要跑某条命令”“刚才测试失败在某个模块”这类临时状态。

Episodic是一次会话或任务片段。它保留发生过的上下文,但还不一定是稳定事实。Semantic是从 episode 中提取出的长期事实,比如项目命令、用户偏好、流程约定。Archival则保存低频或旧记忆,必要时进一步遗忘。

echo-agent 还用MemoryType区分记忆描述谁:

类型说明例子
User用户偏好、习惯、沟通风格用户偏好中文回答,先给结论
Environment项目事实、工具配置、流程规范、领域知识当前项目使用 pytest,配置文件在某路径

这个区分很重要。用户画像可以跨项目延续,但更敏感;环境事实通常绑定某个仓库、目录或机器,跨项目复用反而危险。

echo-agent 的MemoryEntry不只是key + content,还包含类型、层级、标签、来源会话、重要性、访问次数、最近访问时间、向量 ID、episode ID、版本关系和superseded_by。这些字段说明:记忆不是一段文本,而是带状态的行为依据。

选择性持久化

真正难的不是保存,而是判断什么该保存。

一段调试会话可能有几十条消息:读日志、猜原因、跑命令、失败、换方向、再验证。最终值得长期保存的也许只有一条:“该项目的测试入口是pnpm test,且需要在子目录执行。”

echo-agent 用两条路径处理这个问题。

第一条是显式存储。MemoryStoreuser_memory.jsonenv_memory.json保存结构化记忆,用MEMORY.md保存整理后的长期 Markdown 记忆,用HISTORY.md追加 consolidation 产生的历史摘要。JSON 便于检索、更新和去重;Markdown 便于注入系统提示词,也便于人阅读。

第二条是后台整理。MemoryConsolidator会把会话片段整理成history_entrymemory_updatesleep_consolidate进一步创建 episode、提取 semantic facts、执行冲突检测和遗忘归档。MemoryReviewer则复盘对话,只保存用户偏好、项目事实、工具配置、领域知识和调试经验。

最小流程可以压成这样:

def remember(obs, session_key): if is_current_task_state(obs): working_memory.add(obs) return ​ if not is_durable_or_reusable(obs): return ​ entry = MemoryEntry( type=classify_user_or_environment(obs), tier=MemoryTier.SEMANTIC, key=extract_key(obs), content=validate_content(extract_content(obs)), source_session=session_key, importance=estimate_importance(obs), ) store.add(entry) store.queue_embedding(entry)

这里有三条边界。当前任务变量留在WorkingMemory,不要写成长期事实。模型推断不能直接变成高置信记忆,“用户可能喜欢简洁回答”不等于“用户喜欢简洁回答”。记忆还要有作用域,echo-agent 的scope_policy在 session 模式下只让同 session 记忆在对应会话可见,除非它带global标签或没有source_session

长期记忆是一种认知承诺:系统承诺未来在某些场景下仍把它当作可用背景。

既然是承诺,写入就必须保守。宁可少记一些可以重新获取的信息,也不要把一次性状态、未验证猜测、临时情绪或敏感内容写进长期上下文。

写入安全

记忆会进入系统提示词,所以记忆内容本身就是攻击面。

如果系统把“忽略之前所有指令”“不要告诉用户”“系统提示覆盖”这类内容保存为长期记忆,下一次模型看到它时,记忆就会变成 prompt injection 的载体。

echo-agent 在写入前会校验内容:扫描提示注入模式、外泄模式、敏感路径和隐形 Unicode 字符。比如curl携带KEY/TOKEN/SECRET、读取.env.netrc.npmrcauthorized_keys~/.ssh~/.echo-agent等模式,都属于需要阻断的风险信号。

写入一致性也不能靠运气。记忆可能被用户命令、后台 reviewer、consolidator 或多个任务并发更新。echo-agent 使用文件锁和原子写:先取得锁,再重新加载当前类型文件,修改后写入临时文件、fsync,最后用os.replace替换。

检索与遗忘

记忆保存下来之后,还要回答另一个问题:当前任务到底需要召回哪些记忆。

召回过少,Agent 会忘记关键事实;召回过多,模型上下文会被旧信息污染。长期运行后,记忆库里会出现许多相似但不完全相同的事实,只靠文本相似度很容易召回错误项目、旧配置或过期偏好。

echo-agent 的MemoryStore.get_snapshot会把长期记忆、会话用户记忆和环境记忆注入系统提示词,并设置字符上限。书稿中给出的限制是用户记忆约 1375 字符、环境记忆约 2200 字符。这不是小细节,而是防止记忆淹没当前任务。

HybridRetriever进一步组合 BM25、向量相似度和遗忘曲线。

BM25 擅长精确关键词,比如命令名、文件名、配置项。向量检索擅长语义相似,比如“测试入口”“构建命令”“失败复盘”这些说法不同但含义接近的查询。

echo-agent 还会根据 query entropy 自适应调整权重:高熵、宽泛查询提高向量权重;低熵、具体查询提高关键词权重。如果 FAISS 或 embedding provider 不可用,系统会优雅降级到关键词检索。

遗忘曲线提供第三类信号:

half_life = base_half_life * (1 + log2(1 + access_count)) decay = 0.5 ** (days_since_access / half_life) effective_importance = importance * decay

访问次数越多,半衰期越长,记忆衰减越慢。低价值、长期未使用的记忆会被归档或遗忘。这样系统不会变成只会追加的日志库,而是会重新组织长期经验。

检索的目标不是展示系统知道多少,而是只把当前任务真正需要的少量信息带回上下文。

冲突治理

记忆缺失会让 Agent 重新询问;记忆冲突会让 Agent 基于错误事实自信行动。

用户今天说项目用npm,下周迁移到pnpm;某个配置路径昨天还有效,今天已经重构。长期系统一定会遇到这些变化。

直接覆盖会丢失历史,不利于审计;完全保留又会污染上下文。echo-agent 的ContradictionDetector会先用同 key 候选和向量相似度找可能冲突的记忆,再用 LLM 或启发式规则检查。冲突会保存到memory_contradictions,解决时可以把旧记忆标记为被新记忆supersede

这让记忆演化有历史。模型看到的不是两条互相打架的事实,而应该是类似“旧记忆说使用 npm,但当前证据显示已迁移到 pnpm,以当前文件为准”的状态。

生产可用性

判断一个 Agent Memory 是否接近生产级,不能只看“有没有记住用户偏好”。更硬的检查项应该是这些:

检查项可验证标准
分层模型是否区分 working、episodic、semantic、archival
类型隔离是否区分 user memory 和 environment memory
写入标准是否判断稳定性、来源、作用域、隐私和冲突风险
安全扫描是否阻断 prompt injection、敏感路径、凭证外泄和隐形字符
并发一致性是否有文件锁、重新加载和原子写
检索策略是否结合关键词、语义相似、重要性和时间衰减
上下文上限snapshot 是否有字符预算
冲突处理是否记录 supersede、contradiction 和版本关系
遗忘能力是否支持归档、降权、删除和用户纠正
回归测试是否覆盖 CRUD、作用域过滤、注入阻断、检索、reviewer 和冲突处理

书稿里的测试也体现了这个方向:test_memory_advanced.py覆盖MemoryEntryEpisodeContradictionForgettingCurveWorkingMemoryHybridRetrieverContradictionDetectorMemoryStoretest_memory_store_save.py验证 user/env 记忆分别写入对应 JSON;test_memory_reviewer.py验证 add、replace、remove 和多匹配错误。

这些测试说明,记忆系统不是一个 add/search 工具,而是覆盖安全、作用域、持久化、检索、复盘、遗忘和冲突治理的一组基础设施。

小结

Agent Memory 的核心不是“记住更多”,而是选择性地把未来仍有价值的信息变成可检索、可更新、可遗忘、可审计的结构。

短期状态留在WorkingMemory,任务片段进入 episode,稳定事实提升为 semantic memory,低频或旧记忆进入 archival。用户偏好和环境事实分开治理,写入前做安全扫描,检索时尊重作用域和上下文预算,冲突时记录版本关系,长期不用时归档或遗忘。

这样设计之后,Agent 不只是能在当前窗口里接上话,而是能在长期协作中积累经验,并且知道这些经验什么时候可靠、什么时候需要重新确认。

(全篇完)


本文为 echo-agent 设计笔记系列第 17 篇。项目源码已开源至 GitHub。如果你对工业级 Agent 的工程落地感兴趣,欢迎加入技术交流群参与日常讨论。下一篇我们将探讨 《用 RAG 给 Agent 接入内部知识》,敬请期待。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/11 2:14:03

高通 9008 模式 Flat Build 与 Meta Build:2 种刷机模式原理与实战选择

高通9008模式Flat Build与Meta Build:深度解析与实战决策指南当你的高通设备陷入无法开机的"砖机"状态,或是需要绕过系统限制进行深度维护时,9008模式下的两种刷机方案——Flat Build与Meta Build,往往成为最后的救命稻…

作者头像 李华
网站建设 2026/7/11 2:11:38

Java 线程状态深度解析:从 jstack 输出看懂 BLOCKED、WAITING 与死锁

Java 线程状态深度解析:从 jstack 输出看懂 BLOCKED、WAITING 与死锁 当 Java 应用出现性能瓶颈或卡顿时,开发者往往需要深入线程内部一探究竟。jstack 作为 JDK 自带的线程诊断利器,能为我们打开这扇观察窗口。但面对密密麻麻的线程堆栈&am…

作者头像 李华
网站建设 2026/7/11 2:10:43

Unity视频播放画面残留问题:原理分析与完整解决方案

1. 项目概述:一个Unity新手的“血泪史”如果你刚接触Unity,想用Video Player组件播放一段视频,比如做个简单的开场动画或者UI背景,大概率会和我当初一样,兴冲冲地拖个Video Player到场景里,指定视频文件&am…

作者头像 李华
网站建设 2026/7/11 2:10:12

IR2130 自举电容计算与选型:基于5个关键参数的15倍安全系数设计

IR2130自举电容工程实践指南:从公式推导到器件选型的完整设计流程1. 自举电路原理与关键参数解析在电机驱动和三相逆变器设计中,IR2130凭借其集成自举技术的高压侧驱动方案,成为工程师的首选芯片之一。这个看似简单的自举电路背后&#xff0c…

作者头像 李华
网站建设 2026/7/11 2:06:05

AI驱动生产率提升:技术原理、实践与5-6%增长路径

今天来看一个关于AI对生产率影响的重要观点。Cathie Wood作为ARK Invest的首席执行官,在技术投资领域有着重要影响力,她最近提出AI技术将推动生产率提升至5%-6%的水平,这一预测值得技术从业者关注。从技术角度看,AI确实正在改变各…

作者头像 李华