文件系统与数据库的五十年恩怨:Agent时代存储终局揭秘
最近半年,Agent基础设施圈出现了一个耐人寻味的动向:好几位资深数据库人,几乎在同一时间做起了专门给AI Agent使用的文件系统。
Timescale推出了TigerFS,把PostgreSQL挂载成一棵目录树,每个文件对应一行记录,目录化作表,写入带事务,变更可版本化。Turso的AgentFS将Agent的文件、键值状态和工具调用审计痕迹装入一个由SQLite支撑的文件系统中,支持快照、隔离、搬移、分支。AGFS则把数据库、消息队列、对象存储等资源暴露为文件接口,并明言向Plan 9致敬。
我本人一年前也折腾过基于PostgreSQL的PGFS方案,最近又收到好几个Harness团队的询问,明显感觉到这个赛道正急剧升温。
乍一看,一堆做数据库的人齐刷刷转向文件系统,仿佛是文件系统赢了。可是剖开这些项目,心脏全是数据库。TigerFS是PostgreSQL投射出一张文件系统的脸,AgentFS是SQLite/Turso装扮成POSIX风格的工作区,AGFS底层同样由一组存储引擎和服务接口在托底。所谓的“Agent爱文件系统”,落实到实现上,全都变成了“数据库学会说文件系统的方言”。
这并非新鲜事,而是一场打了五十多年的战争的再次延续。文件系统和数据库这对老冤家,同根同源,分道扬镳,互相蔑视,又反复试探——历史上几次高调的联姻均以失败告终,私底下的技术互偷却持续了半个世纪。
要判断Agent时代这一轮会怎样收场,必须先翻清楚前几轮的旧账。这篇文章打算做两件事:把五十年的恩怨理成一条主线;然后在这条线的延长线上,对Agent时代的存储格局做出几个敢被打脸的判断。
一、共同的起点:文件系统是数据库的母体
辈分得先理清:文件在前,数据库在后,而且数据库是从文件系统的肚子里生出来的。
上世纪五十年代,数据处理无非就是文件处理。磁带上一卷卷顺序记录,1959至1960年间定型的COBOL,其核心抽象就是记录(record)和文件(file),当时所谓的“数据库”,往往指的就是一堆归档好的文件。六十年代初,Charles Bachman在通用电气开发出IDS,首次将“程序穿行于记录之间”这件事做成了通用系统;1968年,IBM为阿波罗计划交付了IMS的前身ICS/DL/I,翌年更名为IMS/360,用来管理阿波罗飞船和土星五号第二级火箭数百万零件的物料清单——层次模型,数据结构是一棵树。
有意思的是,几乎同一时期,Multics的文件系统设计也给出了分层目录结构。同样是一棵树。Multics论文里的文件结构,本质上就是一棵带有链接等访问机制的基本树形层级。
这不是巧合。六十年代的存储世界里,文件系统和数据库仿佛亲兄弟:都是层级命名空间,都依赖“从根往下走”来定位数据。真正的分岔发生在1970年——Codd发表关系模型论文,矛头直指这种“穿行”:程序员不该像领航员一样在指针和层级里导航,你只需声明要什么,系统负责如何获取。Bachman在1973年的图灵奖演讲标题就叫《作为领航员的程序员》(The Programmer as Navigator),而关系革命要斩杀的对象,恰恰就是这个“领航员”。

数据库这边的革命成功了。层次模型、网状模型被关系模型逐渐边缘化,SQL后来成为事实上的主流语言。但同一场革命,从未波及隔壁的文件系统——路径就是导航,cd就是穿行,ls就是环顾四周。
反过来看,文件系统何尝不是一种数据库。只不过,它是一个没有关系代数、没有查询优化器、没有schema、没有事务语义的导航式数据库。事实上,文件系统是最后一个活着的导航式数据库。
较真的读者可能举出DNS、LDAP、注册表作反例——这些当然成立,但它们主要为机器和管理员服务;天天被普通人和程序员cd来ls去的,只剩文件系统这个最大的遗民。
数据库世界经历了革命,文件系统保留了旧制度。旧制度活得下来的原因很朴素:对文件这种对象,导航够用了——人类自己取名字、自己翻目录,天经地义;至于文件内容是什么结构,那是应用程序自己的事。
而“内容结构谁负责”,恰恰成为接下来五十年战争的导火索。
二、分道扬镳:语义所有权的争夺战
七十年代之后,两边彻底分家,各自竖起旗帜,旗帜上写着同一个问题的两种不同答案:数据的语义该归谁管?

文件系统的答案:归应用。存储平台对内容保持无知,我只管字节流和命名空间,打开、读、写、关,其余一概不问。无知换来的是普适——任何程序、任何格式、任何用途,一视同仁。Unix把这一哲学推到极致:“一切皆文件”,连设备和管道也尽量纳入文件接口。
数据库的答案:归平台。你先把结构声明给我,也就是schema;我凭借这份结构向你保证一系列昂贵的性质:完整性、并发正确性、崩溃恢复、查询优化。ACID这个词直到1983年才被造出来,但那套保证七十年代末就已经在System R和Oracle里成型了。
两边不仅是理念不合,更是真枪实弹地互相看不上。数据库阵营的态度,Stonebraker在1981年的CACM上写得毫不客气:操作系统提供的缓冲、调度、文件系统、进程间通信、一致性控制,对数据库来说常常不合用,甚至方向相反。
所以那个年代的严肃数据库经常绕开文件系统直接读写裸设备,自建缓冲池、自建WAL、自建恢复。在数据库人眼中,文件系统不是完全可信的持久性边界:fsync的合同要穿过操作系统页缓存、文件系统、块层、控制器和磁盘缓存,任何一层的重排、缓存、错误处理或硬件语义偏差,都可能让数据库的恢复模型变得复杂。O_DIRECT这类东西,本质上都是数据库试图缩短这条信任链,文件系统被迫给数据库开的后门。
文件系统阵营看数据库,同样一肚子鄙夷:一个自带祭司阶层的半封闭世界——需要DBA、需要schema、需要专用协议,而世界上大部分数据根本不需要这套繁文缛节。
平心而论,双方都对,因为守的地盘不同。共享的、争用的、错不起的数据,值得付schema和事务的税;随手一存的字节,付这个税就显得有些荒谬了。
问题在于,总有野心家不信邪,想把两边统一起来。
三、历史镜鉴:三次联姻为何均告失败
从九十年代到2006年,大一统的梦做了一轮又一轮。按方向可以分成三路,三路的结局出奇一致。
第一路:文件系统吞掉一切。代表作Plan 9。它把“一切皆文件”贯彻到极致:网络是文件,窗口是文件,进程是文件,别的机器的资源挂过来也是文件。技术上美得像诗,商业上却没有成为主流。但它的基因并未消失,而是一次次回响在per-process namespace、union/overlay mount、资源文件化接口等设计里。今天容器技术的mount namespace与overlayfs,和Plan 9至少共享同一种审美:给每个执行上下文一棵可定制的树。AGFS明说向Plan 9致敬,是三十年后的回声。

Plan 9的教训值得铭记:接口的普适不等于语义的普适。你可以把万物都叫作“文件”,但事务在哪、查询在哪、权限委派在哪、审计在哪?把非文件硬说成文件,open/read/write之外的语义依然缺席。
第二路:文件系统长出数据库器官。BeFS给文件属性建索引、支持实时查询,作者Dominic Giampaolo后来去了苹果,把这套思路带进了Spotlight;ReiserFS更加直白,Hans Reiser的野心就是让文件系统拥有接近数据库的小对象效率。结局呢?BeOS死了,Reiser4没能进入Linux内核主线。真正活下来的是Spotlight——请注意它活下来的身份:一个旁挂的搜索服务,而非POSIX文件系统的本体语义。查询作为外挂能活,作为文件系统的核心合同很难活。
第三路:数据库吞掉文件。这一路阵仗最大,尸体也最多。Oracle在8i时代推出iFS(Internet File System),把文件存在关系数据库中,让数据库看起来像共享网络盘。Oracle当年的文档明确说,iFS可以让用户像访问文件服务器一样,通过Windows Explorer、浏览器、FTP、邮件客户端等访问数据库管理的文件。

微软前后也扑腾过几次:九十年代Cairo计划里的OFS,Exchange 2000那套Web Storage System,最后是集大成的WinFS——2003年PDC上高调登场,要替整个Windows换上关系型的底座;2004年被移出Longhorn/Vista首发范围;2006年不再作为独立产品交付,残余技术流进SQL Server、ADO.NET等方向。

WinFS值得仔细复盘。微软没有公布过一份完整的工程死因清单,我将它的工程死因归纳为三条。
第一,性能税。为了让1%的操作能被查询,强制99%不需要查询的操作陪着一块交税。
第二,兼容性。数以百万计的应用假设的是文件语义,不是表。
第三,也是最深的一条:文件和记录的改写模型截然不同。文件倾向于就地的字节改写,记录则偏向事务性的逻辑更新。把一种改写模型强加给另一种负载,两边一起受罪。
三次联姻,结论一致:接口可以互相模仿,语义模型无法合并。
这是五十年战争里第一条经得起复验的规律。
四、台面下的融合:接口各自独立,引擎早已互通
台面上的婚一场没结成。台面下,两边偷技术偷得飞快,而且是双向的。
文件系统偷数据库的:ext3这类journaling文件系统,和数据库的WAL共享同一个想法——先把意图或变更写进可恢复日志,再让系统状态在崩溃后可重放、可修复;ZFS的写时复制加快照,让文件系统拥有了类似MVCC的多版本视图。
数据库偷文件系统的:日志结构文件系统(LFS)的思想孕育了LSM-Tree,如今撑起了半个NoSQL世界;append-only成了大半个存储圈的默认审美。
但这几十年里最大的一桩事,当时几乎没人用“联姻”的框架去讲它:SQLite。
SQLite官方的自我定位是我见过的最精准的产品定义:“SQLite不和客户端/服务器数据库竞争,SQLite和fopen()竞争。”翻译一下:它抢的不是Oracle的活,是文件系统的活——应用本地存储这份工。抢法是把一个完整的事务型数据库伪装成一个普通文件:零配置、零进程、拷走就能用。按SQLite官方说法,它很可能是部署量最大的软件模块之一;官方估算活跃SQLite数据库数量可能超过万亿。

FS和DB领域五十年里唯一修成正果的联姻,不是什么宏大统一语义模型,而是数据库穿上文件的衣服,嫁到了端侧。方向从此定了调——是数据库吃掉了文件的工作,而不是反过来。
同一时期在光谱的另一端,文件系统干了件更决绝的事:主动把语义剥掉以换取规模。S3把POSIX剥得精光——rename没了,就地改写没了,目录是假的,靠前缀模拟;一致性模型也长期不是完整强一致(直到2020年底,S3的GET、PUT、LIST,以及部分元数据操作,才统一补齐强一致)。对象存储与其说是文件系统,不如说是一个巨型分布式KV数据库。这等于文件系统阵营自己承认:POSIX没能原样穿越过大规模分布式。
然后,故事绕成了一条衔尾蛇。
切开今天的数据湖仓:表是对象存储上的Parquet/ORC/Avro文件,文件内部是列式页和统计信息;管这些文件集合的,是Iceberg、Delta、Hudi这类表格式和catalog。Iceberg的metadata、snapshot、manifest list、manifest file维护表状态、数据文件集合和提交协议;catalog则往往落回数据库或数据库化的元数据服务。
Snowflake这类云数仓走专有路线,殊途同归:表被切成内部管理的压缩列式micro-partitions,底层托管在云对象存储上。云数据库那头,Aurora把redo log推到分布式存储层;Neon把PostgreSQL架在存算分离和copy-on-write分支之上。
数据库睡在对象上,对象里装着列式页,管对象集合的是表格式、catalog和事务提交协议。引擎层早就你中有我、我中有你。只有接口层,还维持着1970年代画下的楚河汉界。
这就是五十年战争的第二条规律:融合发生在引擎层,语义保持复数。
谁试图在语义层强行统一,谁死。
五、第四次试探:Agent真的偏爱文件系统吗?
2026年,战火重燃。导火索不是传统操作系统,也不是桌面搜索,而是coding agent。这批agent的行为很快收敛到了文件:项目说明是文件,技能入口是文件,配置是JSON/YAML,补丁是diff,日志、测试结果、临时报告,也都是一堆文件。Agent在仓库里ls、cat、grep、edit,像个不知疲倦的实习生,在目录树里来回翻东西。于是有了一句流传甚广的判断:Agent爱文件系统。

这话不假,但只说对了一半。往深一层看,文件系统是导航式访问,而大模型干活正是这个节奏:看一眼,走一步,再看一眼,再改主意。当年关系模型要杀掉的——“程序员作为领航员”,五十年后在agent身上还魂了。
历史不重演,但押韵得可怕。AGFS是Plan 9的回声:把万物都暴露成文件。TigerFS有BeFS的影子:文件系统不再只是字节流,还要长出查询、版本和索引。数据库投射出文件接口,则像是WinFS的遗愿——只不过这次它学乖了:不给整个操作系统换底座,不逼所有桌面应用陪它交税,只把一个好用的入口,单独献给agent这个新用户。
前三次失败,是因为有人想把两套语义强行合并。这次数据库聪明多了:不合并,只投影;不吞世界,只递给agent一个入口。
但“好用的入口”不是“终局的存储语义”。而且这里有个采样偏差得先戳破:从coding agent归纳出“Agent爱文件系统”,是程序员的乡党偏见。coding agent这个场景太特殊——它认识世界靠文件,改变世界也靠文件:读代码是读文件,改代码是写文件,提交是一组diff,回滚还是文件版本。文件系统对它既是地图又是操作台,既是上下文又是执行面。Coding agent爱文件,是因为代码世界本来就是file-native。可老乡都这样,不代表天下人都这样。
Coding agent的成功会放大一种误判:把代码仓库的本体论,当成了所有组织工作的本体论。软件经济里真正值钱的部分,并不都长成代码库。工单、发票、订单、库存、病历、理赔、支付、审批流——这些东西不是文件形状,是记录、事件、状态机和事务。
离开代码世界,事情立马变样。客服agent可以读工单摘要、聊天记录、用户邮件和知识库文档;但它关闭工单的时候,不是去编辑一个ticket.md。财务agent可以读发票PDF、报销说明和合同条款;但它批准付款的时候,不是去改一个invoice.json。医疗agent可以读病历文本、检查报告和医生记录;但它修改病历、开具医嘱、触发理赔的时候,不可能靠patch一个Markdown文件来完成。
这才是Agent时代真正的分界:不在“读”,而在“写”。
认识世界,可以靠文件;改变世界,必须靠COMMIT。它让一件事从“模型生成的候选方案”,变成“组织承认的事实”。订单状态改了,库存扣了,钱付了,权限授予了,病历更新了——这些都不是文本变化,是现实承诺,不能靠概率模型的自觉,也不能靠一堆文件的自律。
聪明的读者这时会拍桌子:又不是只有数据库有COMMIT,git也有COMMIT,这不就是文件世界的事务吗?原子提交、冲突检测、版本历史、回滚,一样不缺,而且管的正是文件。这恰恰是绝好的试金石——TigerFS、AgentFS的官方文档,都专门拿git worktree当对手,说自己比它强在哪。强在哪?git的事务性是单写者、粗粒度、无并发约束、无引用完整性的:它能保证“这一次提交是原子的”,但保证不了“库存不许扣成负数”,保证不了“两个agent不许同时卖掉最后一张票”,更拦不住第三个agent在worktree外头乱改。

所以Agent一旦真正动手改现实,问题就不再是它能不能读懂文件,而是它能不能安全地提交事实。这,才是文件系统和数据库在Agent时代的真正分野。
六、工作区交由文件,账本必须恪守数据库
文件系统擅长当工作区。它便宜、直观、可读、可改、可diff、可fork、可丢弃。Agent在里面试错很舒服,人类也容易检查。代码、草稿、临时结果、工具输出、patch、测试日志、生成物,都适合放在文件形状的空间里。
但数据库擅长当账本。账本的任务不是让你随便写,而是在关键时刻拦住你。不许重复付款,不许库存扣成负数,不许两个agent同时卖掉最后一张票,不许绕过权限改病历,不许半截事务提交成事实,不许崩溃后丢掉已经承诺的结果。
文件系统的美德,是它不管你。数据库的美德,是它不惯着你。
对人类来说,这种不管叫自由;对agent来说,很容易变成事故现场。agent会批量行动、并发行动、在上下文不完整时行动,还会把错误放大。模型越能干,越不能把权威状态交给它自由发挥。你需要一个更硬、更笨、更不讲情面的系统,替它守边界。
所以Agent时代的存储,不会被一种抽象统一。更合理的格局很简单:工作区可以是文件,账本必须是数据库。
工作区是agent的手稿。手稿可以乱写,可以重来,可以fork,可以回滚,可以留痕。账本是组织的事实。账本不能乱写,不能靠猜,不能靠补救性总结。账本需要事务、约束、权限、审计、恢复和并发控制。
而真正的终局很可能再进一步:工作区会是伪装成文件系统的数据库。这也正好解释了开头那个谜——为什么TigerFS、AgentFS、AGFS看着像文件系统,底层却全是数据库。因为一旦agent工作区不再是一次性临时目录,而要支持快照、隔离、fork、历史、审计、回滚,它就开始长出数据库器官。你以为在做文件系统,需求表一拉出来,全是数据库的祖传手艺。
这一轮真正发生的,不是文件系统复辟,是数据库换皮。表面一棵树,agent可以读、写、改、回滚;里面是日志、事务、索引、版本、权限、审计和恢复。外形给模型探索,内核给系统兜底。
这跟SQLite当年的剧本一脉相承。SQLite的伟大,不是发明了新文件系统,而是把数据库伪装成一个普通文件,吃掉了应用本地存储。Agent时代把剧本又推进一步:数据库不只伪装成一个文件,而是伪装成一棵可探索、可fork、可审计、可回滚的文件树,来吃掉agent工作区。
文件系统赢了接口与入口,数据库赢了终局。
结语
文件系统和数据库打了五十多年,表面是存储之争,底层一直是语义所有权之争。文件系统的答案:语义归应用,平台只管名字和字节。数据库的答案:语义归平台,你声明结构,我提供保证。
Agent时代把这桩旧案翻出来重审,新变量是模型。模型说:未声明的语义,我也能读。
这句话确实改变了很多。过去机器读不懂的Markdown、日志、邮件、合同、报错信息,这些散乱的非结构化原始文件,现在模型能直接读了;过去必须提前建模的一部分上下文,现在可以先扔进文件,让模型临场解释。所以文件系统赢回了一局,尤其在coding agent这里,赢得非常漂亮。
但数据库的那份判决,模型翻不了。
因为模型能读,不等于模型能承诺;模型能生成修改,不等于修改可以绕过事务;模型能解释状态,不等于状态可以没有约束;模型能写文件,不等于文件系统可以承担组织的事实。
Agent真正进入生产环境以后,问题马上从“它能不能看懂”变成“它能不能安全地改”。而安全地改,靠的不是自然语言理解,靠的是老东西:事务、约束、日志、权限、审计、恢复、并发控制。
旧,但硬。
所以Agent的终局不是文件系统。文件系统是agent的工作区、草稿纸、沙盘和上下文平面;数据库会继续承担权威状态、提交路径和事实账本。一个负责让模型试,一个负责让世界别被试坏。但最终,文件系统的接口会保留,底层引擎会收敛到数据库。
几个数据库人不约而同做文件系统,看上去像文件系统复辟,实际上完全不是。不是因为他们背叛了数据库,而是因为他们看懂了同一个方向:Agent需要文件系统的入口,但需要数据库的心脏。外面是一棵可以被模型翻看的树,里面跳动的,还是日志、事务、索引、约束和恢复。
工作区可以是文件,账本必须是数据库。