Cherry Studio 内置 Agent 的长期记忆机制:深入解析 FACT.md 的设计与实现
2026/9/13 6:05:57 网站建设 项目流程

Cherry Studio 内置 Agent 的长期记忆机制:深入解析 FACT.md 的设计与实现

【免费下载链接】cherry-studioAI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio

本指南聚焦 Cherry Studio 内置 Agent(Cherry Assistant 与 Cherry Support)的跨会话长期记忆文件memory/FACT.md,说明它的职责边界、持久化保证、写入与回读机制,以及它和JOURNAL.jsonl、产品清单(manifest)之间的分工。读完本文,你将理解内置 Agent 记忆目录的完整文件布局,掌握哪些信息该写入 FACT.md、哪些信息必须走memory工具或查询 manifest,并能从源码层面验证这套机制的实现原理。

FACT.md 是什么

在 Cherry Studio 的 Agent 数据目录中,memory/FACT.md被定义为Long-term knowledge(长期知识)文件,其唯一用途是存放跨会话学习到的关于用户的稳定事实,例如:

  • 用户偏好(preferences);
  • 环境特性(environment quirks);
  • 已解决的问题(resolved issues)。

该文件的头部注释对此做了明确声明:

This file is for facts you learn about the user across sessions (preferences, environment quirks, resolved issues, etc.). It isnotoverwritten on app updates - your customizations persist.

即:它不会在应用升级时被覆盖,用户的自定义内容会一直保留。这也是 FACT.md 与一般缓存/临时文件最本质的区别——它属于“用户数据”而非“产品数据”。

当前仓库中,两个内置 Agent 均携带同构的 FACT.md 模板:

  • cherry-assistant 的 FACT.md
  • cherry-support 的 FACT.md

两者内容完全一致,说明 FACT.md 是内置 Agent 的通用记忆契约,而非某个 Agent 的专属配置。

记忆目录的完整布局:四类文件的职责分工

从 PromptBuilder 的源码注释 可以完整还原 Agent 数据目录的文件布局:

文件语义用途更新方式
SOUL.md你是谁(HOW)名字、性格、语气、沟通风格;未配置 System Prompt 时的角色定义Read + Edit 工具直接编辑
USER.md用户是谁(WHO)姓名、偏好、时区、个人上下文Read + Edit 工具直接编辑
memory/FACT.md你知道什么(WHAT)活跃项目、技术决策、持久知识(6 个月以上仍有效)仅通过memory工具update动作写入
memory/JOURNAL.jsonl何时发生了什么(WHEN)一次性事件、会话笔记(追加式日志)仅通过memory工具append/search

这套布局的核心原则是每个文件有独占职责,禁止跨文件重复信息。其中 FACT.md 与 JOURNAL.jsonl 的区别尤其关键:

  • FACT.md:存放“6 个月后仍然重要的知识”,由memory工具的update动作整体覆盖写;
  • JOURNAL.jsonl:存放“一次性事件、已完成任务、会话笔记”,由memory工具的append动作逐条追加,且不加载进上下文,需要时通过search查询。

memory工具的描述里有一条非常实用的判据:

Before writing to FACT.md, ask: will this still matter in 6 months? If not, use append instead.

(写 FACT.md 之前先问自己:这件事 6 个月后还重要吗?如果否,就用 append 写入日志。)

为什么 FACT.md 不会被应用更新覆盖

这一保证并非凭空承诺,而是由“内置 Agent 预置(provisioning)”机制的实现决定的。内置 Agent 的模板目录与用户数据目录是分离的:

  • 模板存放在feature.agents.builtin路径下(即仓库中的 resources/builtin-agents 目录);
  • 用户实例化后产生的实际数据(SOUL.md、USER.md、memory/ 等)位于独立的 Agent 数据目录。

builtinAgentDefinition.ts中通过getBuiltinAgentTemplateDirectory读取模板、loadBuiltinAgentDefinition解析 agent.json,预置过程只负责初始化模板文件,并不会在应用升级时重新覆盖已经存在的用户数据文件。这一点与 FACT.md 中 "not overwritten on app updates" 的声明相互印证——升级流程只同步产品侧模板,尊重用户侧的既有记忆。

产品知识不入 FACT.md:与 manifest 的分工

FACT.md 还给出了一条硬性约束

For Cherry Studio product knowledge, follow thecherry-assistant-guideskill and query the current package manifest throughmcp__assistant__product_info. The manifest does not include release history. Do not duplicate product facts here, or they will go stale silently.

翻译过来即:

  1. 关于 Cherry Studio 的产品知识,应遵循cherry-assistant-guideskill;
  2. 通过 MCP 工具mcp__assistant__product_info查询当前安装包的产品清单(manifest);
  3. manifest 不包含版本发布历史;
  4. 不要把产品事实复制到 FACT.md,否则它们会在没有提示的情况下悄悄过期(go stale silently)。

这一设计背后是“单一事实来源(single source of truth)”原则:产品事实由安装包内的 manifest 动态提供,会随版本更新而自动刷新;FACT.md 是用户记忆,一旦写入产品事实,就会与安装包脱节,造成“记忆与现状不符”的陈旧问题。同理,builtinAgentDefinition.ts中也有类似的设计意图:内置 Agent 的展示/搜索描述由 i18n 拥有(agent.builtin.cherry_assistant.description),而不是在 bundle 中复制一份,因为 bundle 副本会成为“易漂移的第二个事实来源”。

结合内置 Agent 的职责来看:cherry-support(产品反馈 Agent)的指令明确要求“产品回答必须以当前安装包为准”(见 cherry-support 的 agent.json),这正是 FACT.md 要求查询 manifest 的落地场景。

写入机制:memory 工具的 update/append/search

FACT.md 的写入不是通过普通文件编辑,而是必须经过memory工具。该工具定义在 src/main/ai/agents/tools/memoryTools.ts,输入 schema 支持三种动作:

参数类型说明
actionstring(必填)update:整体覆盖 FACT.md(仅持久知识);append:追加 JOURNAL 日志条目;search:查询日志
contentstringFACT.md 的完整 Markdown 内容(update必填)
textstring日志条目文本(append必填)
tagsstring[]日志条目标签,可选项(用于append
querystring搜索词——大小写不敏感的子串匹配(用于search
tagstring按标签过滤(可选,用于search
limitinteger最大返回条数,默认 20(用于search

update:原子化覆盖 FACT.md

memoryUpdate的实现值得关注(memoryTools.ts#L113-L139):

  1. 校验content必须为非空字符串;
  2. 解析memory目录并定位FACT.md(大小写不敏感匹配);
  3. 在同一目录下创建临时文件.FACT.md.<uuid>.tmp,以0o600权限写入新内容;
  4. 再次校验目录与目标文件均为“真实文件且非符号链接”;
  5. 通过rename(tmpPath, factPath)原子替换。

这种“先写临时文件再 rename”的流程保证了即使在写入中途发生异常,也不会留下半截损坏的 FACT.md;异常路径中临时文件会被清理。同时,withNoFollow在非 Windows 平台加入O_NOFOLLOW标志,配合lstat检查isSymbolicLink(),从安全角度拒绝了符号链接指向文件——防止记忆文件被链接到任意路径。

测试用例 memoryTools.test.ts#L46-L54 验证了update的原子写入:调用后 FACT.md 内容精确等于传入的content,且返回Memory updated.

append:追加式事件日志

memoryAppend使用O_APPEND | O_CREAT | O_WRONLY打开JOURNAL.jsonl(同样拒绝符号链接),将形如{ ts: <ISO 时间戳>, tags: [...], text: "..." }的 JSON 对象追加为一行。该文件采用JSONL(JSON Lines)格式,天然支持追加与逐行解析。

search:日志检索

memorySearch对每行执行JSON.parse,按query(大小写不敏感子串)与tag(精确匹配)过滤,最后取最后limit条并逆序返回(即最新的在前)。损坏的行会被跳过并记录 warning。测试 memoryTools.test.ts#L56-L64 验证了“追加三条、按 tag 搜索后返回最新优先”的行为(['v2', 'v1'])。

安全护栏

memory工具还包含多项路径安全校验:

  • getAgentDataPath通过agentService.getAgent校验 Agent 存在性,并用assertAgentDataDirectory强制解析后的路径必须与上下文中的agentDataPath完全一致(路径不匹配抛InternalError);
  • memory目录必须是“真实目录且非符号链接”;
  • 文件名解析使用大小写不敏感匹配(跨平台一致体验)。

这些逻辑均有测试覆盖,例如 memoryTools.test.ts#L78-L83 验证了路径不匹配时抛错。

回读机制:FACT.md 如何进入 Agent 上下文

记忆不仅要“写得进”,还要“读得出”。FACT.md 的回读由 PromptBuilder 负责,包含两条路径:

  1. Memories 区块buildMemoriesSection):始终生成## Memories小节,加载 SOUL.md / USER.md / FACT.md 的内容,分别包裹在<soul><user><facts>标签中;
  2. Agent Knowledge 区块buildFactsSection):专门回读memory/FACT.md,生成## Agent Knowledge小节,并把内容放入<facts>...</facts>。源码注释将其描述为“跨会话学习回路的回忆侧(recall side)”:

agents write durable knowledge to FACT.md viamcp__agent-memory__memoryaction="update", and this method loads it back into the system prompt at the start of the next session so the agent remembers what it learned.

(Agent 通过memory工具的 update 动作把持久知识写入 FACT.md;下一次会话开始时,本方法把它重新加载进系统提示,让 Agent 记住它学到的东西——例如之前失败的参数形状、项目约定、用户的纠正。)

该区块还明确要求 Agent 把 FACT.md 内容当作 ground truth(基准事实),除非有直接证据表明其错误,此时应通过memory工具update更新 FACT.md,使后续会话同样受益。这构成了一个完整的学习闭环:会话中沉淀 → 写入 FACT.md → 下个会话回读 → 纠错后再写入。

此外,readCachedFile实现了基于 mtime 的缓存(TTL 30 分钟),并对文件做了真实文件校验(拒绝符号链接)、路径越界校验(realpath 后必须位于期望根目录内),回读路径同样具备安全防护。

写入准则速查

综合 FACT.md 模板、memory工具说明与 PromptBuilder 的实现,可归纳出以下可执行的判据:

信息类型是否写入 FACT.md正确去向
用户偏好、环境特性、已解决问题✅ 是memory工具update
6 个月后仍重要的技术决策/项目知识✅ 是memory工具update
一次性事件、已完成任务、会话笔记❌ 否memory工具append到 JOURNAL.jsonl
Cherry Studio 产品知识(功能、概念、限制)❌ 否cherry-assistant-guideskill +mcp__assistant__product_info查询 manifest
产品发布历史❌ 否(manifest 也不包含)不写入记忆,直接面向用户说明

在 Cherry Support 场景中的实际意义

本文开头提到的 FACT.md 来自 cherry-support 的模板。作为内置的“产品反馈”Agent(其职责为答疑解惑、使用帮助、问题排查、反馈整理,见 agent.json),它面对的是大量重复出现的用户环境问题——某用户的代理配置、某平台的特有行为、某个已排查过的报错。这些正是 FACT.md 的典型适用场景:跨会话记住“这位用户的网络环境”“上次排查到一半的问题状态”“用户偏好的沟通方式”,从而让下一次对话无需从零开始。

而“Cherry Studio 产品知识必须查 manifest”的约束,则确保 Support Agent 的回答始终跟随当前安装包版本,不会因为 FACT.md 里残留的旧知识而给出过时指引——这与 src/main/ai/agents/tools/memoryTools.ts 中“update 覆盖写 + 不重复产品事实”的设计互为表里。

总结

FACT.md 是 Cherry Studio 内置 Agent 长期记忆体系的核心文件,它通过与 SOUL.md(人格)、USER.md(用户画像)、JOURNAL.jsonl(事件日志)的职责切分,以及“产品事实查 manifest、用户事实写 FACT.md”的边界约定,实现了三个关键保证:跨会话持久、应用升级不丢失、永不陈旧。其写入路径(memory工具)与回读路径(PromptBuilder)均经过源码级安全校验(符号链接拒绝、路径越界检查、原子替换、mtime 缓存),并有完整的单元测试支撑。对开发者而言,这套设计是一份可复用的“Agent 长期记忆”参考实现:用独占文件划分记忆类型、用专用工具封装写入契约、用动态数据源取代静态复制,从而避免知识过期。

【免费下载链接】cherry-studioAI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询