ApFramework 标志
发布日期

编码 Agent 的长期记忆:从会话上下文到代码结构

作者
  • 作者头像
    姓名
    Shoukai Huang
    Twitter
旧金山天际线与金色时刻
旧金山天际线(Photo by Kellen Riggin on Unsplash)

编码 Agent 的记忆系统,不能只靠保存聊天记录。它还要区分当前任务、行为规则、会话事件、工程决定、外部来源知识和代码结构,并决定哪些信息在什么时候进入上下文。

一、问题不在于有没有记忆,而在于记忆是否被组织

编码 Agent 的问题往往不在于它完全不会写代码,而在于不同会话之间缺少连续性:它知道当前文件,却不知道上次为什么这样改;能读懂某个函数,却不知道这个函数是哪个架构约束下形成的;可以根据文档回答问题,却未必知道项目已经做过哪些决定。

这些问题通常被归结为“上下文窗口不够大”或“需要接入长期记忆”。但只增加容量并不能解决信息错配。把团队规则、某次会话的临时状态、外部资料摘要和代码调用关系全部塞进一个索引文件,结果往往是文件越来越长,读取顺序越来越不清楚,旧信息和新事实也更容易混在一起。

长期上下文设计首先要区分信息类型:不同信息有不同的生命周期、维护者和可信度,也应该有不同的存储与更新机制。本文以“七层”作为分析坐标,讨论编码 Agent 如何从会话内的工作记忆,逐步连接到代码结构和来源证据。这里的七层不是固定标准,而是一种帮助工程设计定位问题的模型。

二、先区分六类信息

在实现记忆系统之前,可以先不看工具名称,只问六个问题。这里的“六类”是对工程信息的归纳;自动记忆另有一层,主要体现维护者和写入方式的区别,后文单独说明:

Agent 记忆类型与工程载体

这六类信息并不等于六个目录,也不要求每个项目都单独实现。它们的作用是提醒设计者:如果一个信息需要回答的问题不同,就不应该默认使用同一种记忆机制。

当前任务只服务本轮执行。它适合放在 prompt、临时任务文件或当前上下文中,任务结束后不必永久保存。它的失败方式是窗口被压缩、任务切换后信息消失。

规则描述 Agent 应该如何行动,例如项目约定、不可执行的操作、测试命令和读取顺序。规则应该短小、稳定,并且尽量由人或团队维护。规则文件不是知识百科;当它变成几百行的杂物清单,Agent 很可能只会快速扫过。

事件描述上一次发生了什么:修改了哪些文件、执行了哪些命令、留下了什么未完成事项。事件记忆可以来自会话日志、聊天导入或 SessionEnd hook。它解决的是“发生过什么”,并不自动回答“以后应该坚持什么”。

决定是从事件中提炼出来的可复用信息,例如“某个状态必须由账本统一管理,因为不同支付渠道的退款不能相互撤销”。它比会话日志更稳定,因为它保存了选择和理由,而不是完整复述过程。

来源知识记录论文、文档、规范或文章表达了什么。在本文讨论的知识库设计中,raw 保存不可变原文,wiki 保存经过编译的概念、判断、框架和交叉引用。来源知识不等于团队决定,引用一篇文章也不等于项目已经采纳其中的方案。

结构事实描述代码实体如何连接,例如函数调用、模块导入、测试影响范围和依赖关系。它和文本笔记互补:文本可以保存理由,结构图可以帮助定位影响面。结构图的边也需要区分抽取关系和推断关系,不能把 AST 结果直接当作完整的架构意图。

三、七层模型:价值在于分工,不在于数字

七层模型可以把上面的信息放到一条更完整的生命周期中。

第一层是上下文窗口。这是 Agent 当前能直接看到的工作记忆,速度快,但会随着清理、压缩或会话结束而消失。它更像 RAM,而不是硬盘:只装载完成当前任务所需的信息,不承担历史档案功能。

第二层是指令记忆。CLAUDE.md、AGENTS.md 或类似文件可以保存项目规则、命令、约定和读取顺序。以 Claude Code 为例,这类文件会在会话开始时作为上下文载入,但它们不是强制配置;如果某个动作必须被阻止,应使用工具调用前的 hook 等机制。至于“先读结构报告、再查决策和进度”的顺序,则属于项目自行约定的路由设计。

第三层是自动记忆。它记录 Agent 在使用过程中学到的用户偏好、项目习惯和经验,例如命名偏好、测试选择或某类错误不要重复尝试。它与团队指令的区别在于维护者不同:前者更像 Agent 的工作笔记,后者是人或团队明确制定的规则。两者不能因为都叫“记忆”就重复保存同一事实。

第四层是情景记忆。会话日志和聊天导入让 Agent 知道上一次做了什么。一种实用的读写闭环包括:会话结束时保存完成项、决定、待办和关联笔记;新会话再读取最近状态。若需要在模型判断之外阻止或记录某些操作,可以配置 hook;具体能否写入日志、是否调用模型,取决于 hook 的实现,不能一概而论。

第五层是陈述性或决策记忆。它把“发生过什么”进一步提炼成“我们决定了什么,以及为什么”。完整日志更像日记,不能直接当作知识。决定笔记应该有明确的适用范围、理由和来源链接,并允许未来被新代码或新证据修正。

第六层是编译知识。它把外部 raw source 转换成结构化 wiki。在本文的知识库实践中,LLM Wiki 不只生成摘要,还会建立概念关系、同步相关页面,并通过 lint 检查矛盾、孤儿笔记和过时声明。在这种设计中,查询不必每次从原文重新开始;但 raw 仍然是回溯和纠错的入口。

第七层是结构记忆。它从代码的抽象语法树中提取函数、类、模块以及调用、导入、依赖等关系。它回答的是文本笔记不容易直接回答的问题:这个节点连接了什么,修改它可能影响哪些测试,哪些模块是系统的枢纽。

这七层可以合并,也可以拆得更细。实际设计应该根据任务复杂度、代码规模、风险和维护能力决定。把它们当成坐标系,比把“七”当成必须完成的清单更有用。

四、从文件夹集合到上下文供应链

分层只是起点。如果各层之间没有读取顺序和链接,系统仍然可能变成一组互不相干的文件夹。

Agent 上下文供应链与回写回路

一个较完整的任务流可以这样理解:当前任务先触发规则和读取路由;路由决定是否读取用户偏好、最近事件、项目决定、来源知识或代码结构;Agent 据此缩小需要打开的文件范围;执行和验证完成后,结果再回写到日志、决定笔记、Wiki 或结构索引。

这里的关键不是某个命令的名字,而是关系是否可追溯。例如,一条决定笔记可以链接到实现该决定的代码节点,代码节点可以关联写下决定的会话日志,会话日志再链接到支持该决定的原始资料。这样,当代码变化、决定过期或资料出现冲突时,维护者能沿着链条定位问题,而不是重新搜索整个项目。

在这套参考模型中,作者用“memory graph”而不是“memory stack”,强调的不只是上下层次,还有横向关系。规则层需要知道其他层的入口;事件层需要连接决定;知识层需要连接来源;结构层需要连接代码和文档。没有这些边,层数越多,导航成本可能越高。

五、知识编译:从运行时检索到持久化上下文

传统 RAG 通常在收到问题后,从资料库中检索相关片段,再让模型在当前请求中完成综合。它适合需要按问题召回资料的场景;如果关系和冲突没有提前整理,查询阶段还要重新发现它们。

LLM Wiki 把部分工作前移到摄入阶段。原始资料保存在 raw/,编译后的页面保存在 wiki/,顶层 schema 规定页面如何命名、携带什么 metadata,以及如何回指来源。之后的 query 读取已经形成的概念和关系;lint 负责检查内容是否互相矛盾、是否缺少引用、是否出现没有入口的孤儿页面。

Wiki 和 RAG 解决的问题不同:运行时检索适合召回新资料和细节,编译知识适合保存稳定概念、判断和框架;向量检索适合语义粗筛,图适合关系导航,provenance 负责说明信息从哪里来。具体系统是否组合这些能力,需要根据资料规模、更新频率和维护成本决定。

知识编译也有成本。摘要可能丢失原文细节,自动交叉引用可能建立错误关系,旧 Wiki 可能和新代码不一致。因此,长期知识必须保留 raw 来源,关键结论要带证据位置,来源作者的陈述、基于来源的推论和项目自己的决定也要分开标记。

六、结构记忆:文本知道“说了什么”,代码图知道“如何连接”

规则、日志、决定和 Wiki 主要处理语言信息。它们可以说明“为什么采用某个方案”,但不一定能直接算出“修改某个函数会影响哪些路径”。结构记忆补充的正是这部分信息。

代码图可以把函数、类、模块和文档作为节点,把调用、导入、依赖等关系作为边。它帮助 Agent 先定位相关节点,再读取对应文件,减少从整个仓库开始搜索的需要。对于大型仓库,这种导航是否优于增加文本,需要结合实际查询和维护成本评估。

但结构图不应被理解为自动生成的完整架构知识。AST 能抽取代码中存在的关系,却不能总是知道一条关系背后的业务理由;推断得到的边也不应和直接抽取的边使用同样的可信度。结构图应该允许标记来源、置信度和更新时间,并能在人类修正后重新生成或保留覆盖规则。

这与 Skill 和 Context Graph 的分工相似。Skill 负责描述一类任务通常应该怎么做,Context Graph 负责描述当前仓库里什么事实成立。一个只有 Skill 的 Agent 可能会按照通用流程绕过本项目的架构约束;一个只有结构图的 Agent 知道代码事实,却未必知道完成任务的标准流程。两者需要在上下文路由中协同,而不是互相替代。

七、如何渐进式建设

不必一开始就建设完整的七层系统。可以先从最容易验证的环节开始,再根据项目暴露的问题增加记忆层。

第一步,写一份短小的规则文件,明确项目约定、常用命令和读取顺序。即使其他记忆层还不存在,路由先建立起来也能减少无目的的文件遍历。

第二步,建立最小会话日志。记录本次完成了什么、修改了什么、还有什么未完成,以及下一次应该从哪里开始。日志不必追求完整转录,关键是让下一次会话能够恢复工作状态。

第三步,把高价值决定从日志中提炼出来。只有反复会影响实现的选择,才值得成为永久笔记;一次性的临时讨论不必全部写入长期知识。决定应带理由、边界和来源链接。

第四步,对高复用来源建立 raw → wiki 编译流程。先从少量、确实会反复使用的材料开始,持续维护索引和证据,不要把所有网页收藏都自动转成 Wiki 页面。

第五步,当项目规模或依赖复杂度达到一定程度后,再加入结构图和自动化更新 hook。结构图的价值与代码关系密度有关;对几十行脚本建立完整图谱,收益可能低于维护成本。

第六步,为自动写入增加治理:置信度、人工确认、过期策略、冲突检测和定期 lint。记忆越接近自动决策,越需要明确哪些内容可以直接使用,哪些内容只能作为候选线索。

八、边界:记忆系统也会腐烂

长期记忆并不是一次写入、永久正确。项目会改名,架构会迁移,外部资料会过时,曾经合理的决定也可能被新约束推翻。记忆系统如果没有更新时间、来源和失效机制,最终会从“帮助 Agent 理解项目”变成“让 Agent 更有把握地使用旧信息”。

至少有四类问题需要持续处理:旧决定与新代码冲突;结构图没有随着提交更新;自动记忆把偶然偏好当成稳定规则;编译 Wiki 只增加页面却没有清理和反向链接。它们都不是单纯的检索问题,而是知识治理问题。

因此,记忆系统的评价标准不应该只是“保存了多少内容”,还要看 Agent 是否能在有限上下文中找到正确层级的信息,结论是否能回到来源,错误信息能否被发现和修正,以及维护成本是否低于每次重新读取。

九、结语:把记忆设计成上下文供应链

编码 Agent 的长期记忆可以从一个简单问题开始:当前任务需要知道什么,项目希望长期保留什么,哪些信息需要回到来源核查,哪些事实只有代码结构才能说明?

七层模型提供了一套方便的坐标:上下文窗口负责当前工作,规则层负责行为,事件层负责历史,决定层负责理由,编译知识负责来源,结构记忆负责代码关系。它不是固定标准,也不是一次性实施清单。

这些层可以通过读取路由、交叉链接和回写机制形成供应链。这样,Agent 才能从“上一次发生了什么”继续追溯到“我们为什么这样决定”,再定位到“这条决定在代码中如何实现”;新的工作结果也可以回到日志、决定笔记或结构索引中。

对于小项目,几条清晰规则和一份高质量日志可能已经足够;对于长期维护的大型代码库,决定笔记、来源编译和结构图会逐渐成为同一套记忆基础设施的不同部分。建设顺序可以不同,但分类、路由、来源和回流这四个问题不能被一个更大的 prompt 自动解决。

附录:参考文章

本文的七层坐标系参考了 Rajat S. Lakhina 的文章《The Seven-Layer Memory Graph for Coding Agents: How Claude Code, Graphify, Obsidian and Karpathy’s…》。文中日期沿用知识库导入记录;如需作为正式出版信息使用,应再以原始页面的发布日期为准。原文讨论了上下文窗口、指令记忆、自动记忆、情景记忆、陈述性记忆、编译知识和结构记忆,并将它们组织成 memory graph。

本文没有把原文中的工具组合、Graphify 性能数字或个人实践顺序当作普遍结论,而是结合知识库中已有的 Context Graph、LLM Wiki、知识自进化和 provenance 笔记,重新整理为面向编码 Agent 的分析框架。

原文来源:Medium 原文