
用 Markdown 文件核查 AnyModelBot 的长期记忆:定位、读取与 journal 审计
用 Markdown 文件核查 AnyModelBot 的长期记忆:定位、读取与 journal 审计
AnyModelBot 把智能体的长期记忆存成磁盘上的普通 Markdown 文件,而不是藏在向量库里。这篇教程讲清 team / bot / group 三种记忆作用域的文件路径、MEMORY.md 与 topics 的结构、300 / 4000 / 16000 字符与 40 个主题的上限、写入前的密钥过滤、journal.jsonl 审计日志的字段与查询命令,并给出从建机器人到验证记忆落盘、验证密钥被拒、核对 journal 的完整流程。
AnyModelBot 是一个本地优先的智能体应用,可以跑在 Windows、macOS、Linux 上,也可以跑在 Docker 主机里。它和很多同类产品不一样的地方在于:长期记忆不是藏在向量数据库里,而是以普通 Markdown 文件的形式放在数据目录下。这意味着不用打开应用,用任何编辑器就能读、能改、能 diff、能备份。这篇教程只讲一件事——怎么自己打开这些文件,确认智能体到底记住了什么、什么时候记的、有没有把不该记的东西写进去。适合已经装好 AnyModelBot、想核对记忆内容或排查记忆问题的使用者。
需要先说明一点:AnyModelBot 本身不在本地跑大模型,推理需要网络。记忆文件在本地,但模型调用不是。所以「本地优先」指的是数据落在你自己的磁盘上,不是指离线可用。
准备工作
安装与启动方式
有两种方式可以跑起来,任选其一:
- 从 Releases 下载桌面版安装包,按平台安装后启动。
- 按 README 里的 Docker 步骤启动容器。容器内数据目录固定为
/data,通常挂一个名为amb-data之类的卷。
如果直接用源码跑(npm start),数据目录默认是当前工作目录下的 ./data,可以用环境变量 AMB_DATA_DIR 覆盖。
模型接入
启动后需要登录一次 Modelflare,或者直接填入自己的官方 API Key。走 Modelflare 时是一个账号调用 70 多个模型、按 token 计费;走自己的 Key 时请求直接发到对应厂商,不经过 Modelflare。具体可用模型、计费方式与额度以官网当前信息为准,本文不列具体数字。
数据目录在哪
记忆文件全部位于数据目录下的 memory/ 子目录。各运行方式对应的数据目录如下:
| 运行方式 | 数据目录 |
|---|---|
| 桌面版 · Windows | %APPDATA%\anymodel bot\data |
| 桌面版 · macOS | ~/Library/Application Support/anymodel bot/data |
| 桌面版 · Linux | ~/.config/anymodel bot/data |
| 源码运行 | ./data(可用 AMB_DATA_DIR 覆盖) |
| Docker 容器内 | /data |
下文用 $DATA 代指你的数据目录,实际执行时替换成上表对应的路径。
你需要知道的三个作用域
记忆不是一个巨大的单文件,而是按作用域分开存放的。理解这三个作用域,是读懂目录结构的前提:
| 作用域 | 含义 | 数据目录下的路径 |
|---|---|---|
| bot | 属于某一个机器人 | memory/bots/<botId>/ |
| group | 应用内的机器人分组共享 | memory/groups/<groupKey>/ |
| team | 整个安装实例共享 | memory/team/ |
每个作用域内部结构相同:一个 MEMORY.md 放短条目和主题索引,一个 topics/ 目录放深入展开的主题笔记。记忆根目录下还有一个 journal.jsonl,记录每一次增删。
操作步骤
第一步:列出记忆目录
先确认目录结构和你预期一致。Linux 桌面版示例:
ls -R ~/.config/anymodel\ bot/data/memory
macOS 示例:
ls -R "$HOME/Library/Application Support/anymodel bot/data/memory"
已经在 Docker 里跑的情况:
docker exec amb ls -R /data/memory
这里假设容器名为 amb,按你自己的容器名替换。
第二步:读 MEMORY.md
MEMORY.md 是每个作用域的入口文件,里面是短条目加一个主题索引。典型内容长这样:
# 机器人
- 偏好简短回答 [source: chat; added: 2026-11-09]
- 日报每天 17:00 发出 [source: chat; added: 2026-11-09]
## Index
- [[project]] — 2 条
每条记忆后面都带着来源和添加日期,方便你判断这条信息是什么时候、通过什么渠道进来的。索引区列出的是主题名和条目数,主题正文不在这个文件里。
批量查看所有机器人的 MEMORY.md:
sed -n '1,80p' ~/.config/anymodel\ bot/data/memory/bots/*/MEMORY.md
Docker 下:
docker exec amb sh -c 'cat /data/memory/bots/*/MEMORY.md'
第三步:读主题笔记
当一个话题积累到需要展开时,内容会落到 topics/<topic>.md。主题名会经过 validTopic 规范化成小写、连字符分隔的形式;memory、index 这类保留名会被拒绝,不会成为主题文件名。
主题正文不会每次全部塞进提示词。智能体通过 remember、forget 和召回类工具按需读取,所以你在文件里看到的内容,不一定每一轮对话都进了模型上下文。
第四步:核对容量上限
源码里写死的上限是字符数,不是模糊的 token 估算。对照下表检查你的文件有没有接近上限:
| 对象 | 常量 | 上限 |
|---|---|---|
| 单条条目 | ENTRY_MAX | 300 字符 |
| MEMORY.md 正文 | MEMORY_MAX | 4000 字符 |
| 单个主题文件 | TOPIC_MAX | 16000 字符 |
| 单个作用域的主题文件数 | TOPICS_MAX | 40 个 |
接近上限时,条目会被截断或写入失败,具体表现取决于调用路径。用 wc -m 可以快速量一下:
wc -m "$DATA/memory/bots/<botId>/MEMORY.md"
wc -m "$DATA/memory/bots/<botId>/topics/"*.md
第五步:验证密钥过滤
每次 remember 调用都会先跑一遍 looksSecret() 检查。它覆盖的模式包括:OpenAI 风格的 sk-…、GitHub token、AWS 的 AKIA…、Slack 的 xox…、Google 的 AIza…、Stripe 的 sk_live_… / rk_live_…、Hugging Face 的 hf_…、PEM 私钥、形似 JWT 的字符串,以及「密码是 …」这类措辞。
匹配到的一行不会被写入。注意这不是「加密后保存」,而是直接拒绝写入——设计上宁可失败,也不让记忆目录变成凭据保险箱。
验证方法:在对话里让机器人记住一个形似 sk- 开头的假字符串,然后回到 MEMORY.md 里找,应该找不到。这个模式列表并不完备,误报和漏报都是需要反馈的问题。
第六步:读 journal.jsonl
每一次成功的添加或删除,都会往 memory/journal.jsonl 追加一行 JSON。字段含义:
| 字段 | 含义 |
|---|---|
at | Unix 毫秒时间戳 |
scope | 作用域,如 team、bot:<id>、group:<key> |
file | MEMORY 或主题名 |
op | add 或 remove |
text | 条目正文 |
by | 触发来源,多数是 chat 或 tool |
一行示例:
{"at":1731168000000,"scope":"bot:abc","file":"MEMORY","op":"add","text":"偏好简短回答","by":"chat"}
常用查询:
tail -n 50 "$DATA/memory/journal.jsonl"
grep '"file":"project"' "$DATA/memory/journal.jsonl"
Docker 下:
docker exec amb tail -n 20 /data/memory/journal.jsonl
这个日志是只追加的,没有轮转机制,长期使用后文件会变大,需要自己留意。
第七步:理解模型实际看到什么
记忆进入模型上下文有两条路径:
- 快照:每段对话开始时,
MemoryStore.snapshot()按 team → bot → group 的顺序,把各作用域MEMORY.md里的短条目拼成一份冻结的 Markdown,同时列出主题名供按需召回。这个前缀的字节序列保持稳定,内容没变时能复用 prompt cache。 - 召回与检索:主题正文不会每轮全量注入,而是由智能体调用 remember、forget 和召回类工具按需读取。
另外,通用的 bash 和文件工具看不到记忆目录,这是有意隔离的。
一个完整示例
下面从零走一遍,验证记忆确实落盘、密钥确实被拒、journal 确实有记录。以 Linux 桌面版为例。
1. 启动并登录
安装桌面版或按 README 的 Docker 步骤启动,登录一次 Modelflare,或填入自己的官方 API Key。
2. 建机器人
新建一个机器人,写一段简短的 persona,权限保持默认的 Workspace——它只能在自己的文件夹内写,越界需要审批。
3. 让它记住一条偏好
在对话里说「偏好简短回答」这类你确实希望保留的偏好,让它记住。
4. 确认落盘
ls -R ~/.config/anymodel\ bot/data/memory
sed -n '1,80p' ~/.config/anymodel\ bot/data/memory/bots/*/MEMORY.md
应该能在对应 bot 的 MEMORY.md 里看到那条条目,带 [source: chat; added: …] 标注。
5. 确认密钥被拒
再让它记住一个形似 sk- 开头的假字符串,然后重新读 MEMORY.md,这一行不应该出现。
6. 确认 journal 有记录
tail -n 20 ~/.config/anymodel\ bot/data/memory/journal.jsonl
应该能看到第 3 步那条 add 记录,scope 是 bot:<id>,by 是 chat。
7. 切换模型,确认作用域不变
在对话中用 /model 切换模型再切回来。记忆文件的路径和作用域不会因为换模型而改变——作用域是机器人和分组的概念,和模型厂商无关。
注意事项
文件权限与写入方式
文件以 0600 模式创建,目录是 0700。写入采用先写临时文件再 rename 的方式,避免留下写了一半的 Markdown。
删除行为
在应用内删除一个分组时,dropGroup 会删掉该分组的记忆目录。删除机器人时,它的对话也会一起消失。需要保留历史的话,记忆备份要自己做——这个产品不提供云端同步。
数据边界
留在本机的内容:对话(SQLite)、记忆文件、工作区、密钥。离开本机的内容:所选模型为了作答需要的东西,包括提示词、用到的记忆、文件、工具结果。本地控制台监听 127.0.0.1,桌面版每次启动会生成新的 UI token。开启电脑操作、让模型看屏幕时,截图也会离开本机。通过聊天渠道(如 WeChat、Feishu)收发的消息同样会离开本机。
经 Modelflare 的请求会在 Modelflare 侧留下请求日志;用官方 API Key 的调用直接发往对应厂商,不经过 Modelflare。图像和视频生成目前只走 Modelflare。
已知限制
- 不是离线本地大模型,推理需要网络。
- 不是密码管理器。看起来像密钥的字符串会被有意跳过,记忆目录不能当凭据库用。
- 不是云同步产品。笔记本休眠时,定时规则不会执行。
- 没有独立的移动端应用。手机侧是通过已有的聊天应用,和已经启动的桌面端或容器里的机器人对话。
- 电脑操作使用内置的 Cua 驱动,在 macOS 上处于 Beta。
- Feishu 渠道目前只支持私聊。
- 不要把 3600 端口直接暴露到公网,这一点和 README 的提醒一致。
关于过滤器的反馈
密钥过滤的模式列表既不完整也可能误伤。误报(正常内容被拒)和漏报(密钥被写入)是两类不同的失败,反馈时最好分开描述,并给出可复现的最小输入,这样更容易定位。