# 把 Agent 的状态放进数据库

LLMS 索引： [llms.txt](/llms.txt)

---

一年前，我写过一篇文章叫《[**PGFS：将数据库作为文件系统**](/pg/pgfs/)》。当时是为了解决 Odoo 社区的一个需求：将文件与 PostgreSQL 数据库一起做 PITR，回滚到指定时间点。

方案运行得还不错。它用纯软件的方式，实现了原本需要昂贵 CDP 专用硬件才能实现的功能，也就是让文件系统与数据库一起回滚到任意时间点。性能也行，对于 Odoo、Dify 这类应用绰绰有余。

但最近我发现，这个方案吸引了不少意想不到的用户。他们不是来做 ERP 的，而是来 **存 AI Agent 状态** 的。

![把 Agent 的状态放进数据库](featured.webp)

做法其实很简单：通过 PGFS，把 PG 数据库挂载成一个本地目录。读写这个目录，实际上就是在读写远程的数据库。然后把 AI Agent 的工作目录、配置文件、记忆数据全都放进去。

这让我意识到，PGFS 这个东西，可能比我最初想象的要有用得多。至少我知道，一家做 OpenClaw 商业发行版的公司，已经在用 PGFS 方案作为底层记忆共享机制了。

------

## Agent 到底需不需要数据库？

在聊怎么做之前，先说说 “Why”。这是个被反复争论的问题。我的朋友蒋老板就经常跟我 Argue：AI Agent 不需要数据库，用个 SQLite 就行。

对于 To C 的本地单机单 Agent 场景，他说得也许没错。一个人用一个 Claude Code，状态就放在 `.claude/` 目录下，Git 管好代码，没什么问题。在这种场景下拿 PG 来存储状态，确实有点拿着锤子找钉子的感觉。

**但是，一旦场景稍微复杂一点，数据库就是不可避免的。** 正如图灵奖得主、PG [**祖师爷 Stonebraker 所说：这是 AI Agent 发展的必由之路。**](https://mp.weixin.qq.com/s?__biz=MzU5ODAyNTM5Ng==&mid=2247490789&idx=1&sn=149e6591161328e2702ec726383b1018&scene=21#wechat_redirect)

什么叫“稍微复杂一点”？

**多 Agent 协作。** 你开始用并行的 Sub-Agents 来分工：一个负责写代码，一个负责写测试，一个负责审查。它们之间需要沟通任务状态、共享上下文。用 Markdown 文件做任务队列？能跑，但很脆弱。

**从单人到团队。** 你一个人 Vibe Coding 的时候无所谓，但当团队里有三五个人，每个人都有自己的 Agent 在干活，就需要一个地方来协调。当出现跨设备、跨个体、跨组织协作的时候，数据库就要比笔记本上的目录方便多了。

**To B 场景。** 企业级应用天然需要集中存储、审计、权限控制。你需要 CDP 能力，随时回滚到任意时间点，需要灵活地快照、分叉、共享，还要处理好并发争用与数据一致性。

**To C 的终极形态。** 现在你的 Agent 是跑在一台机器上，独占这个机器的环境。但如果你真的想实现类似 Jarvis 那样的愿景，也就是让 Agent 运行在你所有的设备上，提供统一的使用体验，那么这些 Agent 必然需要一个共享的记忆。

当复杂度开始升高，你早晚会开始使用数据库来解决这些问题。除非你准备在文件系统上重新发明一个蹩脚的数据库。

那么，数据库到底能给 AI Agent 提供什么独特的价值？

我认为有两个杀手锏。

------

## 杀手锏一：时光机

第一个，是 **时间点恢复**（Point-in-Time Recovery, PITR）。

在现有的 AI Agent 工作流里，如果 Agent 把事情搞砸了，是很难办的。特别是当 Agent 完全依赖文件系统和 Git 来管理状态时，你是个纯代码开发者，又构建了良好的 Git 工作流，能及时 commit 和 push，那还好说。但现实是，很多状态并不在 Git 里：Agent 的配置文件、中间产出、临时数据、工作记忆……这些东西一旦被误操作，就回不来了。

Claude 误删代码库的案例已经出现了，更不用说那些没有被版本管理的数据。

你可能会说：我可以用 Git 或者 ZFS 做快照。可以，但有两个问题。**第一**，快照是离散的时间点，你只能回到“上一个快照”，而不能回到“3 分 27 秒之前”那个精确的时刻，比如误删除发生的前一秒。**第二**，你得显式地管理这些快照：什么时候做、保留多久、怎么清理。这本身就是运维负担。

以前，想实现“回到任意时间点”这种能力，只有两条路：要么买昂贵的 CDP 硬件，要么自己实现一套复杂的日志系统。

PGFS 给了第三条路：**把文件系统的所有写入都变成数据库的写入，借助 PostgreSQL 的 WAL 日志，天然获得 PITR 能力。**

具体来说：当你往 PGFS 挂载的目录写文件时，数据实际上写进了 PG 的 `jfs_blob` 表里。文件操作和数据库操作共用同一套 WAL 日志。当你做 PITR 回滚时，数据库和文件系统会同时回到指定的时间点，精确到每个操作的微秒时间戳。

![PGFS 让文件系统与数据库一起做 PITR](pgfs-pitr.png)

**这意味着你的 Agent 拥有了一台时光机：不管它做了什么，你都可以把一切恢复到任意一个时间点。** 代码、数据、配置、记忆，全部一起回滚，没有任何不一致。

这还带来了一个额外的能力：**瞬间克隆与分支**。因为代码状态本质上也是数据库里的数据，你可以基于某个时间点创建一个新的数据库实例，里面的文件状态和数据库状态完全一致。就像 Git 的 branch，但连数据库里的业务数据也一起分支了。让不同的 Agent 在不同的“分支”上工作，互不干扰。搞砸了？回滚。想试试另一条路？Fork 一个新环境。这是纯文件系统方案做不到的。

对于 AI Agent 来说，这个能力的价值怎么强调都不过分。它让你有了一个“无限撤销”的安全网，或者说，一个可以随时存档 / 读档的游戏存档系统。

------

## 杀手锏二：共享大脑

如果你只有一个人、一个 Agent，那确实不需要共享。但是当你开始用并行的 Agents、Sub-Agents 时，就需要一个高效沟通的地方。

目前的单机模式是怎么做的？在项目目录里写一个 Markdown 文件当 To-Do List，手动派发任务，让 Sub-Agent 去执行。一个人的时候勉强能跑。但如果用一张数据库表来记录任务，所有 Agent 都从里面取活、更新状态、上报结果，这就是一个天然的任务调度中心。不需要文件锁，不需要轮询，数据库的 MVCC 和 `NOTIFY/LISTEN` 天然解决并发问题。

更重要的是：**文件目录很难简单地共享给其他人。** 你可以用 FTP、NFS，但配置麻烦，安全性也是问题。

而 PGFS 的共享方式非常优雅。设想这样一个架构：

1. 你有一台云服务器，上面运行着一套 Pigsty（包含 PostgreSQL）。
2. 在上面创建一个 PGFS 挂载点，比如 `/fs`。
3. 所有项目代码、Agent 配置、共享记忆，都放在这个目录下。
4. 团队里的任何一个人，只要知道数据库连接串，就可以用一行命令把这个目录挂载到自己的本地机器。

![通过 PGFS 共享工作空间](pgfs-shared-workspace.png)

**一行连接串，一行挂载命令，就可以让多个人、多台机器、多个 Agent 共享同一个工作空间。**

我现在自己的工作方式就是这样：一个基于 Pigsty 的 Monorepo，所有项目都在里面。云服务器上可以直接用 Claude Code 干活，同时把云端的 PGFS 挂载到本地，实现本地读写。多平台、多实例、无缝同步。

可以每个人负责一个子项目，在一个整体 Repo 里面协作。

再往远了想：如果你真的想要一个 Jarvis 风格的数字管家，它肯定需要一个集中的地方来存储状态。你不能让每个 Agent 都有自己独立的记忆，否则你得到的不是一个助理，而是一群互不知情的虾兵蟹将。

多个 Agent 共享记忆，最自然的方式就是建一个中枢：云端一台虚拟机，跑一套 Pigsty，通过一个 URL 把数据库挂载到本地。每一个 Agent 都可以读写共享状态，同时保留各自的私有记忆。

![多个 Agent 共享记忆](pgfs-agent-memory.png)

当然除了上面两点之外，还有很多其他的好处，ACID、高可用、可观测性、备份恢复、复制 / CDC 工具，这里就不一一展开了。

## 怎么做：Pigsty 的 JUICE 模块

说了这么多“为什么”，来说说“怎么做”。底层能力一年前就有了。当时我已经把 JuiceFS 打包到了 Pigsty 里。在 Pigsty 4.0 版本中，正式发布了 **JUICE 模块**，把整个流程做成了声明式配置，一键部署。

### 什么是 JuiceFS？

JuiceFS 是一款高性能的 POSIX 兼容分布式文件系统。架构很简洁：一个元数据引擎 + 一个数据存储后端。元数据引擎管理文件目录树和属性，数据存储后端存放文件内容。

PGFS 的核心设计就是：**JuiceFS 支持用 PostgreSQL 同时作为元数据引擎和数据存储后端。** 所有的文件元数据和文件内容都存在 PG 里，共享同一套 WAL 日志。（TimescaleDB 最近出了一个 TigerFS，提供类似功能，但成熟度偏低。我也已经打包整合了。）

### 声明式一键部署

在 Pigsty 的 vibe 配置模板中，就已经提供了一个配置好的例子。只要你在一台全新的 Linux 服务器上执行这几行命令，那么你在 `/fs` 这个目录上就已经拥有一个预先定义并挂载好的 PGFS 了。

```bash
curl -fsSL https://repo.pigsty.io/get | bash
cd ~/pigsty
./configure -c vibe -g   # 使用 vibe 模式，生成随机密码
./deploy.yml             # 部署基础设施和 PostgreSQL
./juice.yml              # 部署 JuiceFS 文件系统
```

你对这个默认定义的 `/fs` 目录下的所有文件读写都会落在数据库里，而你也可以将这个数据库同时挂载到其他目录，甚至是多个不同电脑上的本地目录，实现目录共享。而这一切都是通过一段简短配置定义的：

```yaml
juice_instances:
  jfs:
    path: /fs
    meta: postgres://dbuser_meta:DBUser.Meta@10.10.10.10:5432/meta
    data: --storage postgres --bucket 10.10.10.10:5432/meta \
      --access-key dbuser_meta --secret-key DBUser.Meta
    port: 9567
```

就这么简单。系统会自动完成 JuiceFS 的格式化、挂载、开机自启配置和监控集成。

你也可以轻松依葫芦画瓢定义多个 JuiceFS 实例，或者把同一个实例共享挂载到多台不同的机器上面去：

```yaml
app:
  hosts:
    10.10.10.11: {}
    10.10.10.12: {}
  vars:
    juice_instances: {...}
```

最妙的是，不仅仅是这些 Linux 服务器可以共享挂载，对于 macOS 和 Windows 用户，你也可以把云端的 PGFS 挂载到本地：

```bash
juicefs mount "postgres://dbuser_meta:DBUser.Meta@10.10.10.10:5432/meta" ~/work -d
```

**一行连接串就是你的“共享云盘”入口。** 比 NFS、FTP 简单太多。我最近准备弄一个一键配置脚本，在 macOS 和 Windows 上一次性配置好 JuiceFS，只需要填一个 URL，就可以立即把所有事情都配好。

当然，对于老司机来说，一看就知道怎么回事了：你只需要把 Claude Code、Codex、OpenClaw 在家目录下的 dot 目录移动到这个挂载上来的共享工作目录，然后软链接回原位，你的 Agent 状态就存储到数据库中了。

而且最棒的是，性能也还不错。和原生文件系统比，PGFS 的吞吐量肯定差一些。但实测数据并不差，文件读写大概在百 MB/s 上下的吞吐量，而且 JuiceFS 也有本地缓存机制，对于 Odoo、Coding Agent 之类的场景肯定是绰绰有余了。

当然，最棒的特性莫过于当 Agent 把你的环境搞砸了，你可以使用 PITR 一键回滚到任意时间点的黑魔法。

------

## 总结

回到最初的问题：AI Agent 到底需不需要数据库？

对于单人单机的简单场景，确实不一定需要，SQLite 也可能够了。但 Agent 的世界正在变得越来越复杂，多 Agent 协作、团队共享、状态持久化、容错回滚。这些需求一旦出现，数据库就不是可选项，而是基础设施。

PGFS 通过 Pigsty 的 JUICE 模块，给 AI Agent 提供了两个杀手锏能力：

1. **时光机**：基于 PITR 的任意时间点回滚，代码、数据、配置、记忆一起恢复。还能瞬间克隆和分支，让 Agent 在不同的“存档”上并行实验。
2. **共享大脑**：多 Agent、多人、多机器共享同一个工作空间和记忆。一行连接串，一行挂载命令。

这两个能力，是纯文件系统方案做不到的。以前实现这些需要几十万的 CDP 硬件。现在？一台云服务器，一套开源软件，四行命令，一分钱都不要。

**这才是数据库在 AI 时代的正确打开方式。**
