7.3 分层记忆:会话内、跨会话与知识库


7.3 分层记忆:会话内、跨会话与知识库

本节摘要:压缩管"这个会话装得下",记忆管"会话之外还记得什么"。把记忆按生命周期分三层:会话内记忆就是 messages 本身加工作区——引用化(3.3 节)把文件系统当作窗口的外存,是这一层的核心技巧;跨会话记忆是落盘的结构化条目——项目约定文件(CLAUDE.md 式,随仓库走、团队共享)、会话存档(任务结束时的摘要简报,下次同仓库开工时注入)、用户偏好(风格与惯例);知识库是检索式外存——当"要记的东西"大到无法整块注入(全部历史工单、全部内部文档),就从"注入"退到"按需检索"。每层各有介质、写入时机、读取时机与失效方式,本节给出对照表与 memory.py 最小实现,最后讲记忆的三个坑:陈旧误导、膨胀、跨用户泄漏。记忆与上下文的系统展开,另见 《Hello-Agents:智能体实战教程》第 8~9 章。

学习目标

阅读完本节,你应当能够:

  1. 画出三层记忆的介质 / 写入 / 读取 / 失效对照表。
  2. 设计跨会话记忆的条目 schema 与遗忘策略。
  3. 说明"注入 vs 检索"的切换判据。
  4. 识别记忆的三个坑及对策。

一、三层对照表

介质 写入时机 读取时机 失效方式
会话内 messages + 工作区文件 循环每步(3.1 节) 每步供料(7.1 节) 会话结束即逝(压缩是它的瘦身术,7.2 节)
跨会话 项目约定文件(CLAUDE.md 式)、会话存档、用户偏好 任务结束时摘要落盘;约定由人维护 会话开始时注入 L1/L5 交界 项目重构后过时;需冲突合并与上限
知识库 检索索引(向量库或全文索引,方案不限) 异步构建,与任务解耦 任务中按需检索(作为工具暴露) 文档更新滞后;检索质量决定价值

读表的要点:越靠下的层,读写与任务的耦合越松。会话内记忆每步都动;跨会话记忆一个会话动两次(开始注入、结束落盘);知识库与任务完全解耦,只是工具表里多了一个 search_docs(第 4.1 节:检索类工具,低危可 allow)。

二、会话内:messages + 引用化

这层基本就是第 3.3 节 + 本章前两节的内容,只补一个总括:harness 的两级存储结构——窗口是高速小存储,工作区文件系统是大慢存储,引用化是两者之间的指针。读过大文件后上下文里只留 app.py(约 800 行,含 auth 模块),要用再 read_file 取段。这个结构决定了很多设计:驱逐敢丢旧输出(盘上还有)、压缩敢简化历史(简报里保留了路径)、工具表里 read 类工具永远值得有分页参数。

三、跨会话:约定、存档与偏好

三类内容、三种治理:

类型 例子 写入者 治理要点
项目约定 CLAUDE.md 式文件:构建命令、代码规范、"别动的目录" 人(团队评审) 随仓库走 = 随 git 版本化;不进模型自主写权限(5.1 节)
会话存档 任务结束时的摘要简报(7.2 节同款结构) harness(自动) 同一工作区最多留 N 份;注入时声明"项目可能已变化"
用户偏好 "提交信息用中文""先跑测试再提 PR" harness(经用户确认后沉淀) 可查看、可删除——记忆必须对用户透明

memory.py 最小实现(会话存档半边):

# memory.py —— 跨会话记忆存取(写法示意,以实际工程为准) import json, time from pathlib import Path STORE = Path(".mini_harness") / "memory.json" def load() -> dict: if STORE.exists(): return json.loads(STORE.read_text(encoding="utf-8")) return {"sessions": []} def save_session_summary(task: str, summary: str, limit: int = 50) -> None: """任务结束时写入一条会话存档;上限防膨胀(示意)。""" mem = load() mem["sessions"].append({"workspace": str(Path.cwd().resolve()), "task": task, "summary": summary, "ts": time.strftime("%Y-%m-%d %H:%M")}) mem["sessions"] = mem["sessions"][-limit:] STORE.parent.mkdir(exist_ok=True) STORE.write_text(json.dumps(mem, ensure_ascii=False, indent=1), encoding="utf-8") def context_inject(limit: int = 3) -> str: """新会话供料时注入:同工作区最近 limit 条存档。""" ws, mem = str(Path.cwd().resolve()), load() rows = [s for s in mem["sessions"] if s["workspace"] == ws][-limit:] if not rows: return "" return "近期会话回顾(仅供参考,项目可能已变化):\n" + "\n".join( f"- {s['ts']} {s['task']}:{s['summary'][:120]}" for s in rows)

注意 context_inject 里那句免责声明不是装饰——它是防"陈旧记忆误导"的第一道闸(见第五节)。

四、知识库:从注入退到检索

跨会话记忆解决"几十条经验",知识库解决"几千份文档"。切换判据很简单:当要记的内容大到无法整块注入预算(7.1 节),且任务只用到其中小部分时,从"注入"退到"检索"——把 search_docs(query) 做成工具(第 4.1 节分类学:检索类,低危),模型按需调用。实现方案(全文索引 / 向量检索 / 混合)不影响 harness 侧的设计:对 harness 而言它只是一个只读工具 + 一个异步构建流水线。不要过早上知识库——大部分团队前两年的"记忆需求",一个约定文件加会话存档就覆盖了。

五、记忆的三个坑

形态 对策
陈旧误导 存档说"配置在 config.py",项目早已重构为 yaml 注入时带时间戳与免责声明;命中失败时模型以现场探查为准(工具优先于记忆)
膨胀 条目只增不减,注入本身吃掉预算 条目上限 + 定期合并(同主题旧条目合并为一条);注入走 pinned 之外的可驱逐层
跨用户泄漏 A 用户的偏好被注入 B 用户的会话 记忆按(工作区 × 用户)双键隔离;用户偏好层永不进共享存储

本节要点回顾

  1. 三层记忆:会话内(messages + 引用化两级存储)、跨会话(约定 / 存档 / 偏好,读写各两次)、知识库(检索式外存,与任务解耦)。
  2. 跨会话治理:约定由人维护并版本化;存档自动落盘加上限;偏好转透明可删。
  3. 切换判据:内容大到注不进预算且只用小部分 → 从注入退到检索;不要过早上知识库。
  4. 三个坑:陈旧(时间戳 + 现场优先)、膨胀(上限 + 合并)、泄漏(双键隔离)。

至此供料的三件套——预算、压缩、记忆——齐了。但上下文工程管的是"进",还有一条"出"的暗线:每一步执行之后,谁来把检查、测试、修复自动串起来?下一章:Hook 与反馈回路。

延伸阅读:同站教程库《opencode》。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U