RAG 很好,直到它不够用。
Mintlify 的 AI 助手只能检索匹配查询的文本片段。如果答案分布在多个页面,或者用户需要不在 top-K 结果里的精确语法,助手就卡住了。他们想让助手像探索代码库一样探索文档。
每个文档页面是一文件,每个 section 是一目录,Agent 只需要 grep、cat、ls、find 就够了。问题是怎么让这个虚拟文件系统既快又便宜。
朴素解法的问题
最直接的方式是给 Agent 一个真实的文件系统——在隔离的沙盒里 clone 文档仓库。但对 Mintlify 来说,这个方案有两个致命问题:
延迟太高。 p90 会话创建时间(含 GitHub clone 等)约 46 秒,用户盯着加载动画等不起。
成本太贵。 每月 85 万次对话,按最低配置(1 vCPU、2 GiB RAM、5 分钟会话生命周期)算,每年基础设施费用超过 7 万美元。实际会话时间更长,成本翻倍。
核心洞察:Agent 不需要真实文件系统,它只需要文件系统的幻觉
文档已经被索引、分块、存在 Chroma 数据库里了——这本来是用来做搜索的。Mintlify 在这个基础上建了 ChromaFs:一个虚拟文件系统,拦截 UNIX 命令并翻译成对同一数据库的查询。
结果:
- 会话创建:46 秒 → 100 毫秒
- 边际计算成本:零(复用了已有基础设施)
ChromaFs 架构
ChromaFs 基于 just-bash(Vercel Labs 出品的 bash TypeScript 实现),just-bash 负责解析、管道和 flag 逻辑,ChromaFs 只做底层文件系统调用的翻译。
核心设计原则:完全无状态、只读。所有写操作都抛出 EROFS(Read-Only File System)错误。
目录树引导
ChromaFs 需要在 Agent 运行任何命令前就知道有哪些文件存在。把整个目录树存为 Chroma 里一个 gzipped JSON 文档,初始化时一次性取出解压到内存,后面的 ls、cd、find 都直接查本地缓存。
页面重组
文档在 Chroma 里被分成多个 chunk 做嵌入。当 Agent 执行 cat 命令时,ChromaFs 取出所有匹配 page slug 的 chunk,按 chunk_index 排序后拼接成完整页面。结果会被缓存,同一会话内重复读取不再查数据库。
grep 加速
grep -r 如果逐文件扫描网络请求太慢。ChromaFs 的做法是:
- 粗筛:把 grep 条件翻译成 Chroma 查询,找出可能包含匹配的文件
- 预取:把匹配文件的 chunk 批量预热到 Redis 缓存
- 精筛:把搜索范围缩小到已命中的文件,用内存正则引擎输出最终结果
大范围递归查询在毫秒级完成。
内置 RBAC
每个文件节点存 isPublic 和 groups 字段,初始化时根据当前用户权限裁剪目录树,后续所有查询自动带上权限过滤。在真实沙盒里,这需要管理 Linux 用户组、chmod 权限或维护多套容器镜像;在 ChromaFs 里只是几行过滤代码。
关键总结
ChromaFs 的本质是把两个已有组件(Chroma 数据库 + just-bash)用一个新的语义层串联起来:文档本来就在 Chroma 里,用文件系统协议暴露给 Agent,而不是传统的 RAG 查询 API。
这让三个东西同时成立:零冷启动延迟、零边际基础设施成本、细粒度访问控制。
ChromaFs 的核心贡献不是用了什么新技术,而是把"文档在哪里"和"Agent 怎么访问"这两件事解耦了。大多数 RAG 系统的瓶颈不在检索本身,而在这个抽象层——Agent 拿到的是查询接口,不是它熟悉的工作方式。虚拟文件系统让 Agent 用它本来就懂的方式操作文档,顺便把延迟和成本问题一并解决了。