代码幻觉不是模型问题,是数据问题。
API每天发布breaking changes、废弃端点、重命名参数。模型的训练数据可能落后几个月甚至几年。所以agent写出的代码看起来完美、编译通过,运行时却失败了——因为那个库半年前就已经移走了。
标准解法是RAG:把文档chunk、embedding、检索top-K匹配片段。但这只解决了80%的问题。当答案跨越三页、或者agent需要精确函数签名(chunking过程保不住的那种)时,RAG就不够用了。检索给你碎片,但agent需要全貌。
他们想要不一样的方案:让agent直接读文档。不是检索碎片,而是真正浏览文档。像grep代码库或cat README一样。
Unix在50年前就解决了这个问题
设备、进程、socket——全部是文件。一种接口:open、read、write、close。不需要为每个资源学新API,学了文件,这个知识就到处适用。
Agents在Unix上预训练过。数十亿token的文件系统交互已经 baked进权重。tree、grep、find——这些不是agents学会使用的工具,是agents已经认识的工具。每个编码模型都见过数百万个cat README.md和grep -r "auth" .的例子。
对比MCP:每个工具需要JSON schema、自然语言描述、精细的参数构造。每个都在吃context window空间,引入滥用风险。文件系统不需要这些。
有句话说得很好:一个有文件系统工具和代码解释器的agent,至少和一个有100+ MCP工具的agent一样通用,甚至更通用。
所以他们问:如果互联网上每个文档站都是一个可以cd进去的目录呢?
试试:
npx nia-docs https://docs.trya.ai
为你的agent设置:
npx nia-docs setup https://docs.trya.ai | claude
支持Claude Code、Cursor、Copilot、Copilot、Codex、Gemini CLI、OpenCode。任何能读指令文件的agent都行。
工作原理
一个命令,给你一个bash shell,任何文档都挂载为文件系统。tree它,grep它,cat单个页面,pipe进你的agent。
第一步:索引。 后端爬取站点,尊重llms.txt,检测OpenAPI spec,处理重定向。每个页面变成一个文件,/api/charges/create变成/api/charges/create.md。
关键是路径规范化。文档站URL结构差异巨大,有的在/docs/下,有的在/api/reference/下,有的用根路径。系统自动检测所有索引URL的共同前缀并剥离,这样文件系统不会在到达实际内容前就嵌套三层。
第二步:缓存。 5天TTL足够保持新鲜,又不至于每次都重新爬取。
第三步:给agent用。 npx nia-docs setup追加几行到agent的指令文件:
## Stripe Docs
Before working on a Stripe feature, check the docs via `npx nia-docs https://docs.stripe.com`.
agent在需要时运行命令,获取当前真实文档,然后基于这些写代码。不是基于训练数据里的什么东西。
-c标志执行单个命令并退出。agent从不进入交互session。运行grep、获取结果、读相关文件、继续。标准工具调用循环。文件系统只是接口。
从文档开始,但不止于文档
从文档开始是因为这里幻觉伤害最大、数据问题最可处理。文档站是公开的、结构化的、相对小的(大多数低于1000页),变化频繁到训练数据总是过时,但又缓慢到5天缓存TTL足够保持新鲜。
但这个想法比文档更大。API reference是一个目录。Changelog是一个文件。OpenAPI spec已经是可cat的JSON。整个互联网应该和代码库一样可导航。
早期数据显示agents收敛到一致的工作流:tree定向、grep -rl找相关文件、cat读它们。完全和人类开发者一样。文件系统抽象不是agents需要学的东西,是给它们选择后它们默认采用的东西。
RAG解决的是「context不够大装不下所有文档」的问题。但当上下文窗口已经是100万tokens时,这个问题的性质变了——变成了「如何在正确的窗口位置放正确的信息」。nia-docs的思路更直接:让agent需要时实时读,而不是预先检索。