AI Agent

单库单 Agent:一场被简化了的数据库革命

在上一个月对 Turso 演进路线的拆解中,我们探讨过 从每个租户一库到每个 Agent 一库:Turso 的产品赌注与竞争版图:把原本为多租户设计的物理隔离 SQLite 数据库,进一步缩小到单个 Agent 甚至单次任务的粒度。在之前的 AI 智能体文件系统调研 中我们也提到过,AI 任务最容易卡住的地方往往不是记忆召回,而是执行状态的隔离与恢复。到了 7 月 20 日,Turso 正式发布了白皮书 Building AI Agent Databases: A Complete Guide to Database-per-Agent Architecture,不仅系统化地提出了 Database-per-Agent 理念,还针对不同的部署环境给出了四种典型的架构模式。

白皮书发布后,大家的讨论重点迅速从这个产品赌注划不划算,变成了在真实的 Multi-Agent 系统里到底怎么落地。不少团队看完了白皮书,觉得一个 Agent 给一个库非常优雅,急着往生产环境搬,结果刚跑没多久就踩了坑:有的团队发现数据跨库后搞得四分五裂,有的团队发现想查个全局分析报表比登天还难。这篇文章就是工程落地上的拓展,我们跳过商业视角,聊聊 Turso 提出的四种模式怎么按场景演进、真正能落地的 Hub-and-Spoke 分层怎么搭,以及白皮书里没提、但落到代码里会把你折腾够呛的几处物理归属陷阱与工程坑。

引言:从商业赌注到白皮书落地

当你的系统里跑着几千个自主 Agent 时,后端最先撑不住的通常不是 CPU,而是数据库。平时写 Web 服务,大家习惯用一个中心数据库打天下。要处理多租户,无非是在表里加个 tenant_id 加 WHERE 过滤,或者在同个 DB 里按租户开 schema。这套模式跑了十几年一点问题没有,因为微服务的数据形状是固定的,生命周期也是线性的。但 Agent 一来,这套老经验瞬间就不好使了。

设想个线上场景:几千个 Code Agent 或客服 Agent 同时在跑,每个 Agent 都在写自己的对话上下文、探索过的路径、试错记录和临时偏好。如果你把这些数据全塞进同一个数据库的 agent_memory 表里,靠 WHERE agent_id = ? 来硬撑隔离,痛点很快就会爆发。最先崩掉的是并发,几千个 Agent 同时高频读写同一张大表,索引锁争用会把数据库性能拉垮;接着是脆弱的安全边界,只要代码里哪位兄弟少写了一句 WHERE 条件,Agent A 就能直接读到 Agent B 甚至其他租户的私有记忆;更头疼的是事后清理,当一个 Agent 跑完任务或者中途失控报错需要注销时,你得在几十张关联表里把它的记录一行行检索出来擦掉,级联删除脚本写得再小心也总有遗漏,久而久之数据库里全是一清不掉的孤儿数据。

正如我们在本系列第一篇里拆解的,Turso 官网 提出的核心设计理念是 Databases are files, not processes(数据库是文件,不是常驻进程)。既然数据库就是一个文件,那就别把数据库当成昂贵的服务器。在 Turso 新一代云平台 上通过 API 开一个独立库就是一次毫秒级网络调用;Agent 任务结束了,直接调 API 删掉整个库文件,一行残留数据都不留。这种利用轻量文件实现物理隔离的思路听着很像银弹,但为什么不少团队跟进后,反而让自己绕进了数据副本分裂的死胡同?

共享数据库是怎么在 Agent 时代失效的?

想把这事彻底想明白,得先看共享数据库到底跟 Agent 哪里合不来。微服务的核心是功能边界清晰,账单服务管账单表,用户服务管用户表,大家的数据形状一清二楚。但 Agent 不一样,它本质上是个带着临时状态乱跑的探索者。在共享数据库里,所有 Agent 都被硬塞进同一套 schema 格式里,但现实中不同 Agent 的记忆形状差得太远了:客服 Agent 需要存大段自然语言,Code Agent 需要存 AST 树、文件遍历路径和单测输出,数据分析 Agent 需要存中间推导出来的结构化 JSON。强行搞一套最大公约数 schema,要么字段多到无法维护,要么大家干脆摆烂,把数据全压成 JSON 字符串存入 blob 字段;一旦存了 blob,关系型数据库最核心的 SQL 索引和结构化查询能力直接废了一半。

另一个死穴是生命周期。有的 Agent 跑五分钟就干完活,有的 Agent 得连续跑几个月。共享数据库没法给不同寿命的对象应用不同的物理存储策略,最后只能按最极端的大容量去给所有 Agent 配资源,浪费显而易见。

从单库到 Hub-and-Spoke:Turso 四种架构 Pattern 的演进前置路径

在探讨具体的落地方案前,我们先来看 Turso 白皮书里给出的四种部署模式。关于具体模式的配置可查阅 Turso Agent Databases 指南文档。理解了场景差异,就会发现它们并不是平行选项,而是系统从小到大演进的四个台阶:

  1. Bread and Butter 模式
    最基础的生产形态。每个 Agent 在云端配一个 Turso 数据库,Serverless 环境里的 Agent 直接调 API 连接。这直接搞定了绝大多数在线 Agent 的 Scratchpad 隔离问题。
  2. Fully Isolated, Embedded 模式
    适合跑在桌面、手机或者边缘设备上的 Agent。数据库直接就是本地的一个 .db 文件,读写完全没有网络延迟,离线也能跑,数据物理不出设备,合规省心。
  3. Cloud-Connected with Sync 模式
    针对需要跨设备同步的本地 Agent。Agent 在本地嵌入式库里高频读写,后台通过同步机制把变更推到云端,兼顾了本地响应速度和云端备份。详见 Turso 嵌入式同步机制说明
  4. Hub-and-Spoke 协调模式
    当 Agent 数量变多、既要物理隔离又要互相协作时,架构就演进到了 Hub-and-Spoke。每个 Agent 在自己的 Spoke 库里玩自己的私有状态,同时连着一个共享的 Hub 协调库,只在干完阶段性大活时往 Hub 库里写一条状态通知。

现实世界的常驻答案:Hub-and-Spoke 混合分层架构

真落到严谨的生产环境里,大家最后选的常驻答案几乎都是 Hub-and-Spoke 混合分层。不过这里有个绝大多数人都会踩的坑:数据库的隔离边界,千万不要直接绑定在 Agent 名称上,而是要绑定在 Task 或 Session 上。如果一个 Agent 要连续处理上万个任务,你把数据库绑在 Agent 名字上,这个独立库跑久了照样会堆满历史垃圾,你又得回过头去搞复杂的库内清理。最爽的切法是一次 Task 一个库,任务结束直接删库或归档,让数据库变成纯粹的临时工作区。

一个靠谱的 Hub-and-Spoke 落地架构,通常划分为四层:

Hub-and-Spoke 分层架构:常驻答案。顶部绿色为共享业务真相库(Postgres/中心库),托管用户、权限、订单、全局事实;左下蓝色为 Per-Task 临时工作区(Turso per-agent DB),托管上下文、Scratchpad、试错,跑完归档或销毁;右下黄色为追加审计日志(Event Log),记录工具调用、决策、恢复点;底部灰色为对象存储(S3/R2),存放大文件、构建产物、测试日志。

分工明确之后,共享事实留中心,临时状态放私有,系统就清爽了。

被白皮书跳过的一步与生产环境里的致命坑

状态的物理归属:决定要不要用 Database-per-Agent。左栏绿色为本质上私有的状态(对话上下文、执行进度、Agent 偏好),归 Agent/Task 所有,跑完即焚;右栏红色为共享事实的私有视图(订单、用户档案、权限),归用户/系统所有,留在中心库;中间黄色窄栏为灰色地带,需根据归属权判断。

搭建好 Hub-and-Spoke 拓扑之后,许多团队在实际运行中依然会遇到数据混淆与撕裂。根源在于,Turso 的白皮书成功证明了在成本上给每个 Agent 开库是可行的,但它恰恰跳过了最关键的一步:白皮书从共享库难用直接跳到了给每个 Agent 一个库,却没有说清楚到底哪些状态该隔离,哪些状态绝对不能隔离。

要不要用 Database-per-Agent,跟 Agent 数量多不多、跑得久不久关系不大,中心问题只有一个:这部分数据的物理归属权到底在谁手里?动笔设计之前,得先把 Agent 跑起来产生的数据硬拆成两类:

第一类是本质上私有的状态。这类数据完全属于 Agent 或这次任务本身,Agent 死了,数据就应该跟着灰飞烟灭。比如 Code Agent 在修 Bug 时试过的临时代码片段、思考到一半的 Scratchpad、探索文件树时的中间路径,或者客服 Agent 这次会话里积累的上下文。这些东西只对这次任务有价值,别的 Agent 既不需要读,读了也是干扰。对这类数据,一库一人、跑完删库是绝配,Turso 的优势能发挥出来。

第二类是共享事实的私有视图。这类数据本质上属于用户、租户或者整个系统,Agent 只是刚好拿到了当前的操作权。最典型的例子是订单和用户资料。销售 Agent 创建订单,履约 Agent 查物流,客服 Agent 处理退款,它们操作的都是同一份订单真相。如果你硬套一 Agent 一库,把订单数据拷进每个 Agent 的独立库里,相当于在物理层搞出了三个各自演化的副本。接下来你就得写一套复杂的同步逻辑去保证它们不打架,为了用独立库而人为制造分布式数据一致性难题,纯属没事找事。权限表、全局审批流、财务账单同理,它们归属于系统的全局协调层,必须死死守在共享真相库里。归 Agent 自己所有、销毁了也无所谓的,放私有独立库;归系统或用户所有、Agent 只是临时来操作的,必须留在中心库。Database-per-Agent 只管前者,千万别拿它去装后者。

除了数据物理归属错配的风险,在生产环境落地这套架构时,还有两个白皮书上一笔带过的工程坑需要盘清楚:

第一个坑是 Cross-Agent Analytics 跨库分析。在共享数据库里,想查上周失败了多少个任务,写句 SELECT COUNT(*) FROM tasks WHERE status = 'failed' 秒出结果。但在几万个独立数据库的结构下,你根本没法直接写 SQL 跨库聚合。想看个全局运营大盘,你必须搭一套全量离线 ETL 管线,把几万个文件里的数据抽出来往数据仓库里填。Per-Agent 确实省掉了实时清理脏数据的麻烦,但代价是把复杂度全转嫁给了离线 ETL。

第二个坑是 Schema Propagation 百万级数据库演进。业务一迭代,表里要加个新字段或者改个索引,在单库时代就是一条 DDL 命令的事。但在几十万个独立的 SQLite 库文件上改 Schema,本质上是个极其复杂的分布式迁移治理问题。怎么做灰度发布、怎么做版本校验、断网重试怎么处理,全得你自己建专门的基础设施去抗。

结语:从跟风风潮到按状态归属设计

把数据库从大家共用的基础设施解耦成 Agent 随用随丢的临时资源,确实是 AI 原生架构里非常漂亮的一招。这就跟当年我们从多应用共享一台大物理机进化到每个微服务独占一个 Docker 容器一模一样。

但物理隔离绝对不是不用做架构设计的借口。Database-per-Agent 真正的威力,是给 Agent 的临时 Scratchpad 提供了干净、零残留的物理隔离。下一次给 Agent 系统设计存储层时,先别急着跟风选型。把数据拿出来划一划:共享的业务真相留给中心库,临时的探索过程隔离进 Per-Task 库。把状态的归属权想透了,架构该怎么搭也就一目了然了。

确定了哪些状态该隔离进 Per-Task 库之后,下一个自然的问题就是:这个单文件容器到底能不能跑大模型应用里核心的 RAG 向量检索?在单文件容器内如何高效地做向量检索与记忆召回,我们在本系列第三篇有详细的实战测试。

鸭哥每日手记

日更的深度AI新闻和分析