跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
编程语言Agent RuntimeContext EngineeringAgent MemoryPrivacyLong-running Agents

《Agent Runtime 工程化》Agent Memory 越做越乱,本质上是 Runtime 问题

Agent Memory 越做越乱,本质上是 Runtime 问题 很多 Agent 项目做到第二个月,会开始加 memory。 一开始理由很正当: 然后大家很自然地做了一件事:把对话、文档、工具结果、用户偏好、项目摘要丢进向量库。 前几天

陈堂会发布于 —2 浏览
《Agent Runtime 工程化》Agent Memory 越做越乱,本质上是 Runtime 问题

Agent Memory 越做越乱,本质上是 Runtime 问题

很多 Agent 项目做到第二个月,会开始加 memory。

一开始理由很正当:

用户不想每次重复偏好。
长任务需要知道前面做过什么。
coding agent 应该记得项目结构。
客服 agent 应该记得用户历史。

然后大家很自然地做了一件事:把对话、文档、工具结果、用户偏好、项目摘要丢进向量库。

前几天效果不错。模型'记得'更多东西了,回答也更贴心。

再过一阵子,味道开始不对:

  • 用户新要求已经变了,Agent 还按旧偏好行动。
  • 一个项目里的事实被检索到另一个项目里。
  • 旧的错误总结反复影响新任务。
  • 用户说'忘掉这件事',系统只从 UI 隐藏,检索层还拿得到。
  • 历史摘要写得很像事实,但找不到原始证据。
  • Memory 里混进了模型自己的猜测,后面又被当作用户偏好。

这时候再调 embedding、调 topK、调 reranker,只能缓一缓。

根子不在那里。

Agent Memory 不是一个向量库功能。它是 Runtime 能力。

Memory 到底在改变什么

Memory 不是'多给模型一点背景'这么简单。

它会长期改变模型看到的上下文,也会改变模型的默认行为。一次错误写入可能影响后面很多 run。

比如 coding agent 记住:

这个项目不允许修改数据库 schema。

这是有用记忆。

但如果它又记住:

用户上次要求优先使用 Prisma migration。

下一次用户明确说'不要改 schema',旧记忆就可能和新指令冲突。模型不一定会自然分清'长期偏好''上一轮任务策略''当前明确约束'的优先级。

Runtime 必须帮它分清。

我会把 Memory 分成几类:

Session summary:当前会话压缩摘要。
User preference:用户长期偏好。
Project memory:某个 workspace 或 repo 的事实。
Run note:某次任务的结果和未完成事项。
Skill memory:可复用操作流程或团队约定。
External memory:来自 CRM、工单、知识库等系统的上下文。

这些东西不能混在一个桶里。

Session memory 和 Long-term memory 不是一回事

OpenAI Agents SDK 里有 sessions,用来自动维护 conversation history。LangGraph 文档里也会把短期记忆放在 thread state,把长期记忆放在跨 thread 的 store,通常还会用 namespace 区分范围。

这条边界很关键。

短期记忆解决的是'这次任务进行到哪里了'。它应该跟 run、turn、step、checkpoint 绑定。

长期记忆解决的是'以后还能不能用'。它应该有来源、作用域、TTL、审批、删除和审计。

短期记忆可以比较详细,因为它只服务当前任务。长期记忆必须克制,因为它会跨任务复用。

如果你把两者混在一起,系统迟早会出现这种问题:

用户上周临时要求'为了调试先跳过测试'
  ↓
Agent 记成长期偏好
  ↓
下周真实上线任务里继续跳过测试

这不是模型笨。是 memory 写入策略太随便。

写入比检索更危险

很多团队把精力放在检索:embedding 模型、topK、rerank、hybrid search。

这些当然重要。但我更关心写入。

谁有资格把一条信息写进 memory?

用户明确说'以后都这样'时,可以候选写入。模型从一次任务里推断出的偏好,不应该直接写。工具返回的事实可以写,但要带来源。用户审批记录应该进 audit log,不要靠自然语言摘要保存。

一个 memory entry 至少要长这样:

type MemoryEntry = {
  id: string;
  kind: "preference" | "project_fact" | "run_note" | "skill" | "external";
  scope: {
    userId?: string;
    workspaceId?: string;
    projectId?: string;
    sessionId?: string;
  };
  content: string;
  source: {
    type: "user" | "tool" | "trace" | "manual" | "external";
    ref: string;
  };
  status: "pending" | "approved" | "active" | "rejected" | "expired";
  confidence: "high" | "medium" | "low";
  createdAt: string;
  expiresAt?: string;
};

source.ref 很重要。

没有来源的记忆,后面就没法解释,没法删除,没法纠错。它会变成系统里的小纸条:看起来像事实,其实没人知道是谁写的。

摘要不是事实

长会话一定要压缩。否则 token 会炸。

但滚动摘要有一个危险:它会丢细节,也可能引入偏差。模型写摘要时,常常把'我们尝试过 A,但失败了'压成'使用 A 方案'。后面再把这个摘要喂给模型,Agent 就会沿着错误方向继续走。

所以摘要要写得像工程记录,而不是散文。

Summary range: run_12 step_1-step_8

User constraints:
- Do not modify database schema.
- Preserve existing CLI flags.

Completed:
- Located runtime loop in src/runtime/loop.ts.
- Added schema validation for read_file.

Open issues:
- run_command timeout still lacks AbortSignal cleanup.

Decisions:
- Keep ToolResult.content short; move full output to artifact.

Evidence:
- trace:run_12/step_6/tool_read_file

这段不漂亮,但很好用。

Memory 里的摘要应该能回答:覆盖范围是什么,哪些是用户约束,哪些是完成事项,哪些是未完成事项,证据在哪里。

摘要不能替代原始 trace。它只能是证据索引。

检索污染比你想得更常见

Memory 检索最怕'看起来相关'。

用户问:

帮我修一下 auth middleware 的测试。

检索出来:

上次用户为了临时排查,要求跳过 auth middleware 测试。

这条记忆文本上非常相关,语义上也相关。但对当前任务可能是毒药。模型可能以为跳过测试是用户偏好。

所以 Memory 检索不能只看相似度。

还要看:

  • 是否同一个用户?
  • 是否同一个 workspace?
  • 是否同一个项目?
  • 是否仍在有效期?
  • 是否和当前用户明确约束冲突?
  • 是否有来源证据?
  • 是否是模型推断,还是用户明确表达?

Runtime 应该在注入 memory 前做过滤和排序,而不是把 topK 直接塞进上下文。

type MemoryCandidate = {
  entry: MemoryEntry;
  relevance: number;
  scopeMatch: number;
  freshness: number;
  sourceTrust: number;
  conflict?: string;
};

如果发现冲突,应该优先保留当前用户指令,并把冲突写进 context report。

Memory 也要有权限和删除

OpenAI 的 ChatGPT memory 文档里,会强调用户可以查看、管理和删除已保存记忆。这个产品细节背后,其实是 Runtime 要求:长期影响模型的内容,用户应该能看见和控制。

企业 Agent 更是这样。

Memory 可能包含客户信息、内部项目、代码路径、错误日志、操作习惯、商业策略。你不能把它当普通缓存。

最小治理要有:

查看:用户能看到系统记住了什么。
来源:每条 memory 能追到来源。
删除:用户删除后,检索层也不能再返回。
作用域:不同用户、团队、workspace 隔离。
TTL:临时策略自动过期。
审批:模型建议写入时需要用户或 policy 批准。
审计:谁写入、谁修改、谁删除都有记录。

如果做不到这些,最好先不要做长期 memory。先做 session summary 和 run notes,风险小很多。

Memory 注入需要 fencing

Hermes 这类产品级 agent 项目里,memory manager 不是简单读写内容。它会处理 turn 前 prefetch、turn 后 sync、外部 provider tool schema 注入、context fencing、streaming scrubber,避免 memory context 标签或内部 system note 泄漏到用户可见输出。

这个点很实际。

Memory 注入给模型时,应该有清楚边界:

下面是可参考的长期记忆。
这些内容可能过期,不能覆盖当前用户明确要求。
如需基于其中事实行动,必须优先查证当前 workspace 或外部系统。

模型最终回答时,不应该把内部 memory 标签原样吐给用户。Trace 可以记录 memory id,用户界面可以显示'使用了哪些记忆',但内部提示不应泄漏。

这就是 context fencing。

我建议的 Memory Runtime 流程

一个稳妥的流程是:

Turn started
  ↓
Load session summary
  ↓
Retrieve scoped memory candidates
  ↓
Filter by user / workspace / TTL / source trust
  ↓
Detect conflicts with current user request
  ↓
Inject selected memories with fencing
  ↓
Run agent loop
  ↓
Generate memory write candidates
  ↓
Require approval or policy decision
  ↓
Write active memory with source ref
  ↓
Trace all read/write decisions

这看起来比'向量库 topK'麻烦。

但生产环境要的就是这层麻烦。它能防止模型把一次性任务策略写成长期偏好,也能防止跨用户、跨项目、跨 workspace 的信息串线。

最小实现可以很朴素

第一版不需要上复杂系统。

你可以先用 SQLite 或 JSONL:

type MemoryStore = {
  search(query: MemoryQuery): Promise<MemoryCandidate[]>;
  propose(entry: MemoryDraft): Promise<MemoryEntry>;
  approve(id: string, actor: string): Promise<void>;
  delete(id: string, actor: string): Promise<void>;
  list(scope: MemoryScope): Promise<MemoryEntry[]>;
};

先支持:

  • session_summary
  • run_note
  • user_preference
  • project_fact

每条都带 source、scope、status、expiresAt。

检索先别追求智能。先保证不会串用户、不会串项目、不会拿 expired memory、不会把 pending memory 注入模型。

这比一个'效果很惊艳但谁也管不住'的 memory 系统更适合生产。

最后

Memory 做乱,通常不是向量库做错了。

是 Runtime 没有回答几个问题:

谁写入?
写到哪里?
作用域是什么?
有效期多久?
来源在哪?
谁批准?
如何删除?
如何进入上下文?
和当前用户要求冲突时谁优先?
出了问题怎么追?

这些问题不性感,也不适合做 demo 视频。但它们决定了 Agent Memory 会成为能力,还是成为污染源。

参考资料

  • OpenAI Help: Memory FAQ
  • OpenAI Agents SDK Docs: Sessions
  • LangGraph Docs: Memory overview
  • LangGraph Docs: Add and manage memory
  • LangChain Blog: Memory for agents

推荐阅读

  • 我为什么写《Agent Runtime 工程化》
  • 手写一个 100 行 Agent Loop
  • 给 Agent Loop 加 Max Iteration

目录

  1. Agent Memory 越做越乱,本质上是 Runtime 问题
  2. Memory 到底在改变什么
  3. Session memory 和 Long-term memory 不是一回事
  4. 写入比检索更危险
  5. 摘要不是事实
  6. 检索污染比你想得更常见
  7. Memory 也要有权限和删除
  8. Memory 注入需要 fencing
  9. 我建议的 Memory Runtime 流程
  10. 最小实现可以很朴素
  11. 最后
  12. 参考资料
  13. 推荐阅读
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 在 Linux 桌面里跑 Windows 应用:Winboat 实战笔记
  • AI 编程工具深度对比:Trae、Cursor、Copilot 与 Windsurf
  • 论文阅读--Agent AI 探索多模态交互的前沿领域(一)
  • OpenCode 开源 AI 编程助手使用教程
  • Linux diff 与 patch 命令实战指南
  • 网络安全工程师职业定义、核心技能与认证体系详解
  • Python 为何如此流行?深度解析其核心优势与应用场景
  • 大疆无人机如何导出日志并解析
  • 前端 WebSocket 通信实战与最佳实践
  • OpenClaw 进阶教程:记忆系统、定时任务、多模型与子代理解析
  • Python 爬虫实战指南:从基础请求到分布式框架
  • Kubernetes Python 客户端实战教程
  • Java IO 核心:BufferedReader、BufferedWriter、PrintStream 与 PrintWriter 详解
  • AI 辅助编程工具:GitHub Copilot 安装与使用指南
  • 基于 Rokid AR 眼镜的聚会游戏助手开发实践
  • 百瑞互联 BR8654A02 蓝牙 6.0 SOC 芯片规格介绍
  • Windows 7 安装 Python 3.9+ 配置指南
  • 前端加密:常用方式与使用示例
  • GitHub Copilot 学生认证教程(2026 版)
  • openclaw-termux:在 Android 上部署 OpenClaw AI Gateway

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online