AI 文档助手总答不准?Mintlify 用虚拟文件系统把响应从 46 秒压到 100 毫秒
AI 文档助手最常见的问题,不是模型太弱,而是“拿上下文”的方式太笨
如果你做过文档问答、API 助手,应该很熟悉一种尴尬:用户问的是一个很具体的问题,比如某个参数能不能和另一个字段一起用、某个 SDK 片段在什么前提下成立、某个 OpenAPI schema 里到底少了哪一级嵌套,但助手给出来的却总像“差一点”。
问题往往不在模型,而在经典 RAG 流程太粗。
你把文档切 chunk、做 embedding、Top-K 检索,再把几段文本塞给模型。它能回答大方向,却经常处理不好三类高频需求:
- 需要跨页面拼上下文
- 需要精确读取原始代码块、参数名和 schema
- 需要像人一样继续“翻目录、看文件、搜关键词”
Mintlify 这篇官方工程文让我觉得最值得写的,不是它又做了一个 AI 助手,而是它承认了一个现实:很多文档问答场景,本质上已经不是“召回几段文本”,而是“让 Agent 像读代码一样读文档”。
先说结论:Mintlify 不是继续补 RAG,而是给助手加了一层只读文件系统
Mintlify 的文档助手已经不是简单聊天框。官方文档里给出的能力包括:
- 基于当前页面上下文回答问题
- 自动引用相关文档来源
- 结合 API schema 生成代码示例
- 支持用
.mintlify/Assistant.md对助手行为做项目级定制
但他们在真实流量里发现,只靠传统检索还是会卡住。于是团队没有继续往提示词里硬塞 chunk,也没有把所有问题都丢进沙箱容器,而是把整套文档索引抽象成一个虚拟文件系统 ChromaFs。
换句话说,助手不再只是“拿到几段候选文本后回答”,而是多了几种更接近开发者习惯的读文档方式:
ls:看目录结构cd:进入某个文档路径cat:读取完整页面或片段grep:按关键词做精确搜索find:按路径定位目标文件
这一步非常关键。因为一旦接口变成“文件系统”,模型就能按任务需要逐步探索,而不是被一次性的 Top-K 检索绑死。
为什么他们要放弃“容器里跑 bash”这条路?
Mintlify 其实试过更重的方案。
他们一开始做了一个沙箱容器,让 Agent 在里面直接运行 bash,用 ls、cat、grep 去访问文档。这个思路听起来很合理,因为 Agent 天然会用这些命令。
但上线后问题很快暴露:
- 每次对话都起一个容器,启动和挂载成本太高
- 文档助手本质是只读场景,却承担了完整执行环境的额外开销
- 流量上来以后,成本和延迟都不划算
官方给出的数字很直接:按当时的规模估算,月会话量大约 85 万,继续跑容器的话,年成本会超过 7 万美元;而 p90 延迟最高能到 46 秒。对于“问文档”这种本该秒回的场景,这基本不可接受。
所以他们最后做了一个更适合只读任务的折中:保留“像文件系统一样探索”的交互方式,但把底层实现换成轻量级虚拟层。
ChromaFs 真正聪明的地方,不是像文件系统,而是只实现文档助手真正需要的那一半
如果你看这套设计,会发现它不是在浏览器里模拟一个完整 Linux,而是只保留最值钱的读取能力。
1. 用路径树解决“先知道去哪找”的问题
纯 RAG 最大的问题之一,是你不知道模型有没有看到正确的文档区域。
Mintlify 先把所有文档路径整理成树结构,再把压缩后的路径树放进 Chroma 的 metadata 里。这样助手一开始就能拿到整个站点的大致目录,知道应该先去 /sdk、/api 还是 /guides。
这个设计很像你第一次进陌生代码库时,先 ls 一遍目录,而不是直接全文检索所有文件。
对文档助手来说,这很重要,因为很多问题其实依赖“文档位置感”。比如:
- 这个能力是产品说明,还是 API 参考
- 这个字段定义是在 REST 章节,还是 SDK 示例
- 这是一篇概念页,还是某个 endpoint 的细节页
如果没有这层路径树,模型只能靠关键词瞎猜。
2. 用 cat 还原完整页面,而不是永远困在 chunk 里
RAG 常见的第二个坑,是拿到的是切碎后的文本,不是用户真正想看的“页面”。
Mintlify 的做法是把文档 chunk 继续保留在索引里,但在需要读取时,通过 slug 和 chunk_index 把同一页面重新拼起来。这样模型调用 cat 时,看到的是更接近原文结构的内容,而不是几段脱离上下文的碎片。
他们还做了一个很实用的补丁:对体积很大的 OpenAPI schema,不直接把全文塞进数据库,而是放到对象存储里,只在索引里保留“懒加载指针”。只有真正读这个文件时,才去取内容。
这意味着两件事:
- 大文件不会把常规检索拖慢
- Agent 又保留了“需要时再精读”的能力
如果你现在做的是 API 助手,这个思路尤其值得抄。因为 schema 和示例往往最有价值,但也是最容易把上下文窗口和索引成本一起拉爆的部分。
3. 用两段式 grep,把“找关键词”做成低成本高精度操作
很多文档问题并不适合向量检索。比如用户直接问:
- 某个 header 名字在哪些页面出现过
- 某个错误码在文档里有没有明确解释
- 某个配置项是不是只在 Python SDK 里出现
这类问题,本质上更像 grep,而不是语义相似度。
Mintlify 的做法是先用向量库做一轮粗筛,拿到可能相关的 chunk,再做内存里的正则匹配精筛。为了降低延迟,他们还把 Redis 预取接进来,减少二次读取的等待时间。
这就是很典型的工程化思路:语义检索负责缩小范围,精确匹配负责给最终答案。
别把所有搜索问题都塞进 embedding。很多时候,关键词就是关键词。
4. 把权限和只读限制做进文件系统层,而不是事后补救
这套方案还有一个容易被忽略的优点:权限控制更自然。
Mintlify 直接根据会话 token 和用户组,把能看到的路径树裁出来。也就是说,Agent 从一开始就只会“看到该看到的文件”。再加上整个系统明确是只读的,很多安全边界都比容器方案更容易收紧。
这点很适合企业文档、内部知识库、客户分层文档这些场景。
很多团队做 AI 助手,喜欢先把资料都喂进去,再想办法在回答时限制输出。这个顺序其实是反的。更稳的做法是像文件系统权限一样,先限制可见范围,再允许模型在范围内探索。
如果你也想做一个文档助手,这 5 条比“继续调 Prompt”更重要
看完 Mintlify 这套实现,我觉得最值得直接拿走的是下面 5 条。
1. 先判断你的助手到底是“问答器”还是“阅读器”
如果用户问的都是概念型问题,普通 RAG 可能已经够用。
但如果用户经常会问参数、示例、版本差异、文件位置、SDK 行为,那你的助手更像“阅读器”。这时候让模型拥有 ls / cat / grep 这类阅读动作,价值会明显高于再堆几层检索重排。
2. 不要为只读场景支付完整执行环境的税
容器、沙箱、shell 很灵活,但如果你的任务只是读文档、读 schema、做搜索,很多执行能力其实根本用不上。
只保留读操作,通常能同时换来:
- 更低延迟
- 更低成本
- 更简单的权限控制
- 更容易规模化
3. 保留 chunk 索引,但别让用户永远只看到 chunk
chunk 适合召回,不适合最终阅读。
一个更稳的模式是:
- 用 chunk 找候选
- 用页面级拼接恢复完整上下文
- 再让模型回答
这样既保留了检索效率,也不会丢掉页面结构。
4. 目录结构本身就是上下文
很多团队只给模型正文,不给模型“文档长什么样”。但路径树、栏目结构、文件名,其实本身就是强信号。
对技术文档来说,/getting-started/ 和 /api-reference/ 的语义完全不同。把这个层次信息也喂给模型,常常比多给一段正文更有用。
5. 把精确搜索和语义搜索分开做
别试图让一个检索器包打天下。
- 语义问题,用 embedding
- 精确字段、错误码、参数名,用
grep - 大文件,做 lazy load
- 权限问题,前置到路径层
当这些能力拆开以后,助手的行为会更像一个真正能工作的 Agent,而不是一个“只能在候选段落里猜答案”的聊天机器人。
对普通开发者最现实的启发:AI 助手的下一步,可能不是更大的模型,而是更像操作系统
Mintlify 这篇文章最打动我的点,是它没有把问题理解成“模型不够聪明”,而是把问题还原成“接口不对”。
当你让模型只能看 Top-K chunk,它就只能做“段落猜题”。
当你给它一个只读文件系统,它才开始像真正的工程师那样工作:
- 先看目录
- 再找位置
- 再读原文
- 不确定时继续搜
- 最后再组织答案
这也是为什么我越来越觉得,很多 AI 工具真正该优化的,不是提示词花样,而是模型和信息之间的交互层。
对文档助手、知识库助手、内部 Copilot、API 支持机器人来说,这条思路都值得现在就重视。因为用户真正需要的,从来不是“再一段更像人的话”,而是更接近正确原文、更接近真实结构、更接近可验证来源的答案。
Mintlify 只是把这件事先做出来了。
如果你正准备重做自己的文档问答,先别急着继续堆 RAG。也许更值钱的一步,是先问自己一句:
你的助手,究竟是在“检索几段文本”,还是应该被允许“读完整个文档系统”?
参考资料
- Mintlify 官方工程博客:How we built a virtual filesystem for our AI documentation assistant
- Mintlify 官方文档:Assistant
如果文章对你有帮助,欢迎点击上方按钮打赏作者,更多功能请访问博客站
支付宝打赏
微信打赏