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 的做法是:

  1. 粗筛:把 grep 条件翻译成 Chroma 查询,找出可能包含匹配的文件
  2. 预取:把匹配文件的 chunk 批量预热到 Redis 缓存
  3. 精筛:把搜索范围缩小到已命中的文件,用内存正则引擎输出最终结果

大范围递归查询在毫秒级完成。

内置 RBAC

每个文件节点存 isPublic 和 groups 字段,初始化时根据当前用户权限裁剪目录树,后续所有查询自动带上权限过滤。在真实沙盒里,这需要管理 Linux 用户组、chmod 权限或维护多套容器镜像;在 ChromaFs 里只是几行过滤代码。

关键总结

ChromaFs 的本质是把两个已有组件(Chroma 数据库 + just-bash)用一个新的语义层串联起来:文档本来就在 Chroma 里,用文件系统协议暴露给 Agent,而不是传统的 RAG 查询 API。

这让三个东西同时成立:零冷启动延迟零边际基础设施成本细粒度访问控制