世界を動かす技術を、日本語で。

AIドキュメンテーションアシスタントのためにRAGを仮想ファイルシステムに置き換えました

概要

  • RAGの限界と、複数ページにまたがる情報検索の課題
  • 仮想ファイルシステム「ChromaFs」による高速・低コストな解決策
  • just-bashとChromaDBを活用したUNIXコマンドの仮想化
  • 柔軟なアクセス制御(RBAC)とキャッシュによる効率化
  • 実運用での大規模なコスト削減と即時性の実現

RAGの課題と仮想ファイルシステムへの転換

  • RAG はクエリに一致するテキスト断片しか取得できず、 複数ページにまたがる回答正確な構文検索 に弱点
  • ユーザーがコードベースを探索するように、 エージェントがドキュメントを横断的に探索 する必要性
  • grep, cat, ls, find などのUNIXコマンドを使い、ファイルシステム的にドキュメントを扱う発想
  • 各ドキュメントページを「ファイル」、各セクションを「ディレクトリ」として仮想化
  • 実際のファイルシステムを使う従来方式では、 サンドボックス起動の遅延(約46秒)高額なインフラコスト が発生

ChromaFs:仮想ファイルシステムの設計

  • ChromaDB に既にインデックス・分割保存されたドキュメントを活用し、 ChromaFs を構築
  • UNIXコマンドを仮想ファイルシステムにリダイレクトし、 DBクエリとして変換実行
  • セッション生成時間が約100ミリ秒 に短縮、 マージナルコストはゼロ
  • 既存インフラを再利用するため、 追加コストや新規インフラ不要

just-bashとChromaFsの連携

  • just-bash(Vercel Labs製) はTypeScript実装のbashで、 IFileSystemインターフェース を提供
  • ChromaFsはこのインターフェースを実装し、 ls, cat, grep, find, cd 等をChromaDBクエリに変換
  • パイプやフラグ処理はjust-bash側で担当 し、ファイル操作部分のみChromaFsが担当

ディレクトリツリーの構築とキャッシュ

  • 全ファイルツリーをgzipped JSON(path_tree)としてChromaコレクションに格納
  • 初期化時にサーバーがこのツリーを展開し、 Set<string>とMap<string, string[]> でインメモリ管理
  • ls, cd, findはローカルメモリで即時解決、ネットワークコール不要
  • 同一サイトのセッションでは キャッシュ利用で更に高速化

アクセス制御(RBAC)の実装

  • isPublic, groups フィールドでファイルごとにアクセス制御を設定
  • ユーザーのセッショントークン に基づき、ファイルツリー構築時に 閲覧可能ファイルのみ抽出
  • Linuxユーザーグループやchmod管理不要、 数行のフィルタリング処理で完結

ページの再構成とキャッシュ

  • catコマンド実行時、対象ページの全チャンクを chunk_index順に結合 して完全なページを再現
  • キャッシュにより繰り返しアクセス時のDB負荷を削減
  • 巨大なOpenAPI仕様書などはlazy pointer登録、実際にアクセスされるまで取得しない設計
  • 書き込み操作は常にEROFS(Read-Only File System)エラー、システムの完全なステートレス化

grep高速化とネットワーク効率

  • grep -r 等の再帰検索は、ChromaDBでまず粗いフィルタをかけ、 該当チャンクをRedisキャッシュへ一括取得
  • マッチファイルのみjust-bash側で詳細フィルタ、 大規模検索もミリ秒単位で完了

実運用と成果

  • ChromaFsは1日3万件超の会話・数十万ユーザーのドキュメントアシスタントを支える基盤
  • サンドボックス不要・即時起動・ゼロコスト・柔軟なRBAC を実現
  • Mintlifyドキュメントサイトやmintlify.com/docsで体験可能

Hackerたちの意見

ファイルシステムベースの検索で人々が再発見している本当のことは、埋め込みベースの検索ではないセマンティック検索の一種があるってことだと思う。図書館の司書がドメインに基づいてファイルを棚に整理するような感じだね。私たちは、何十年も前から知っていた検索の形を再発見しているんだ。そして、それらはエージェントにとっても解釈しやすいことがわかった。

知識労働をしている何百万もの人々は司書じゃないし、みんな適当にやってるってことがわかった。

誰かがどこかでRAGはベクター検索に基づいているに違いないと単純に思い込んで、みんなそれに従ったんだ。

これはオントロジカルNLPに戻る話で、知識表現を言語処理のためのプリミティブとして使っていたんだ。そっち方面には本当にたくさんの研究があるよ。

逆インデックスは、ブール演算子をサポートする大きな利点があるね。

LLMがリアルタイムで大規模にこういう分類をできるのはすごいと思う。単なる「検索」以上のツールをLLMに与えると、実際にズルしてる感じになるね。

PageIndex [1]と似たような取り組みで、基本的に目次のようなツリーを作るんだ。そしたら、LLMがそのツリーをたどって、プロンプトの文脈に関連するチャンクを見つける。1: https://github.com/VectifyAI/PageIndex

俺の直感だけど、AIアシスタントってLLMによって自動的に完成される物語の中のキャラクターだから、人間の言語とのインタラクションとして解釈できるメカニズムが、脳の働きについての推測や抽象概念に近いメカニズムよりも意外なアドバンテージを持ってる気がするんだよね。

次はタグベースのファイルシステムについて話そう。

同意。400以上のPythonファイルがあるコードベースで作業してるけど、その違いは明らかだよ。埋め込みベースのRAGだと、単語が一致する無関係なコードスニペットを引っ張ってきちゃってた。エージェントにディレクトリツリーをブラウズさせて、必要なファイルをその都度読ませるようにしたら、モジュール構造を約30秒で理解して、正しいファイルをパスで要求し始めた。ディレクトリ階層はすでに人間がキュレーションしたナレッジグラフみたいなもんだから、ベクトル数学に夢中になってそれを忘れちゃってたんだよね。

これは間違いなく正しい方法だね。実際のサンドボックスには良いユースケースがある(エージェントが任意のコードを実行するなら、エアギャップ環境でやるべきだよ)。でも、UnixのIOプリミティブを使うためにVMを立ち上げるのはやりすぎだと思う。エージェントがUnixライクなツールコールを出して、プロダクションスタックがIOを処理するのに使う方がずっと理にかなってる。

100%同意。ただ、リソースのトレードオフがなければ、FUSEマウントが一番良いと思う。

これはMintlifyのようなスタートアップには素晴らしいアプローチだと思う。ただ、RAGが最も価値を加える「混沌とした」組織で、どれだけ実用的かには懐疑的だね。個人的な経験から言うと、組織の構造や情報が階層的でも分割可能でもない場所でRAGをうまく機能させるのは非常に難しいタスクなんだ。

ユースケースはここでしっかり定義されているから、早まらないようにしよう。テキスト検索は、例えば本の中の内在的なセマンティックコンテンツに比べると、コードのように比較的単純な問題だと思う。ここでの教訓は、RAGは万能薬ではないってことだね。Claudeコードチームも同じ結論に達したよ。

現代のOCRツールはかなり優秀だよね。検索データベースに追加する知識がOCRできるなら、ここで取ったアプローチは一般化できると思う。

スパゲッティドキュメントの組織の上に仮想ファイルシステムを重ねるのは、まるでドラッグクイーンのようなインデクサーだよ。アクセス制御がないと、コンプライアンスの大惨事になるしね。

使ってる技術スタックには詳しくないけど、外から見ると、なんかフェイクシェルを使う理由があるんじゃないかと思ってた。誰かその理由を教えてくれない?

100%同意。もっと時間とリソースがあれば、FUSEマウントがベストだと思う。ChromaをFUSEアダプタの背後に置くのが最初のアイデアだったけど、めっちゃ遅かったんだよね。FUSEマウントがあっても、grepの最適化が必要だと思う。うちの場合は、読み取り専用のドキュメントのために100% POSIX互換が必要なかったから、bashコマンドの一部だけでドキュメントをたどれたのが楽だった。これで、エージェントが使うEC2ノードやサンドボックスの余分なインフラのオーバーヘッドやメンテナンスを避けられるし。

CLIのアプリケーションが復活してるのが本当に楽しい!可能性がいっぱいあるよね。今、FUSEを使って、Macの実際のファイルシステムをミラーリングする仮想ファイルシステムをマウントするという関連の課題に取り組んでる。~/sourceのようなサブツリーを使って、エージェントをそのファイルシステム内に制限して、リポジトリ外での破壊的な変更をブロックできるようにしてる。各リポジトリには長寿命のエージェントがいるんだけど、彼らが他のリポジトリを変更し始めると、メモリが混乱しちゃうんだ。リポジトリごとにシステムユーザーを作りたくなかったから、1つのclaudeシステムユーザーを作って、仮想ファイルシステムで権限を管理してる。例えば、gmailリポジトリのエージェントはgmailリポジトリとgoogle_authリポジトリを変更できるけど、ragリポジトリは変更できない。追記:ここで公開してるよ。まだ開発中だけど。 https://github.com/sunir/bashguard

でもSQLiteはファイルシステムより35%速いって有名だから、なんでそれを使わないの? [0] https://news.ycombinator.com/item?id=14550060

それで、TursoはSQLiteの上に仮想ファイルシステムを構築したんだ。AgentFS https://agentfs.ai/ https://github.com/tursodatabase/agentfs これはすごくいいアイデアに聞こえるけど、NFSを使っていてFUSEじゃないのが残念だね(macFUSEは今FSKitバックエンドを持ってるから、FUSEはMacとLinux両方にとってベストな解決策みたい)。

SQLite + GPT5.4は俺にはすごく合ってる。最大の成功は、.NETソリューションをSQLiteデータベースに変換するRoslynメソッドで、Files、Lines、Symbols、Referencesのテーブルを作るんだ。このアプローチは、フラットなファイルベースのセットアップ(つまり、Visual StudioのCopilotが提供するようなもの)よりもかなりパフォーマンスが良いことが分かったよ。特に、大規模なプロジェクトに対してはね。100メガ以上のソースも全然問題ない。リレーショナルモデルのおかげで、特注のリフレクションツールやもっと多くのトークンを消費しないとできないような、すごくエレガントな[非]クエリが実現できるんだ。

AIにファイルシステムツールを通じてドキュメントをアクセス可能にすることに関して、SDKの著者たちがどんなパターンを使ってAIコーディングエージェントに最新のドキュメントを使わせているのか探してたんだけど、VercelのAI SDKは他では見たことない面白いことをやってるよ(もしかしたら、ちゃんと探してないだけかもだけど)。その「ai」npmパッケージには、サイトのドキュメントの.mdxバージョンが含まれたルートレベルのdocsフォルダがあって、パッケージのバージョンに特化してるんだ。彼らが意図しているAI支援の開発者体験は、人々が彼らのai-sdkスキルを発見してインストールすること(npx skillsツールを通じて、Vercelだけじゃなくてほとんどのプロバイダーからスキルを発見してインストールできる)なんだ。SKILL.mdはエージェントに、自分のモデルにトレーニングされたかもしれない知識を明示的に無視するように指示していて、まずnode_modules/ai/docs/内のドキュメントをgrepで探してからウェブサイトを検索するように言ってる。https://github.com/vercel/ai/blob/main/skills/use-ai-sdk/SKI...

これは最近見た中で一番混乱する主張だな。ファイルに対してgrepや他のツールを使うのは、昔ながらのキーワード検索と同じで、ほとんどのRAGはベクトル検索を使ってるのに。彼らがファイルシステムについて主張していることは、データベースについて何も知らないことを示唆しているだけだと思う。ほとんどのRAGシステムがデータをどうカテゴライズしているのかはよく知らないけど、データベースならコンテンツを好きなようにインデックスできるんだ。ファイルシステムのように階層でやったり、タグを使ったり、夢に描くようなデザインでやったりできる。検索はgrepのようなキーワード検索でも、ragのようなベクトル検索でも、伝統的なテキスト検索が使うランキングアルゴリズム(tf-idfやBM25)でも、組み合わせてもいい。トップXの文書だけを使う必要はなくて、grepのようにマッチングしきい値を超えたすべての結果を評価することもできる。検索は非常に豊かな分野で、たくさんの良い確立された方法があるんだ。grepやファイルシステムに戻るのは、60年代の検索技術に戻るようなもんだね。

君の言ってることは分かるし、君が正しいと思う。ただ、彼らの立場も理解できる。実際、エージェント(特にコーディングCLI)は、ファイルを使うとすごくうまくいくみたいだよ。たとえその周りのツールが理想的でなくてもね。他のカスタムツールを使うと、すぐにIQが50ポイント下がるし、そもそもツールを使う気にもならないことが多い。

うん、データベースに対するエージェント的検索でかなりの成功を収めてるよ。私の考えでは、エージェント的検索の主な特徴は、エージェントが多くのアドホッククエリを実行できることなんだ。ファイルシステムのことじゃない。私が理解していた初期のRAGシステムは、エージェントのためにその検索を実行することが目的だったんだ。それが「非エージェント的」なアプローチなんだよ。でも、埋め込みと全文が両方あるデータベースがあって、それに対してクエリを実行できて、エージェントが好きなクエリを実行できるようにすると、それが私の中では「エージェント的検索」なんだ。

詳細にはあまり入らなかったけど、なんで彼がエージェントにいろんなデータソースから情報を発見させないのかずっと考えてた。そっちの方がずっと成功してるんだよね。

これは単にナイーブなチャンクを回避するための過剰なエンジニアリングに感じる。ChromaDBの上にTSでPOSIXシェルをエミュレートして階層検索をするのは、TTFTを壊すことになるよ。エージェントが実行することに決めたすべてのlsやgrepは、別々の推論サイクルになるんだから。RAGのコンテキストロスと厳しいマルチステップのレイテンシを交換してるだけだね。

チャンクの上にFUSEを使えば、シェルエミュレーションも必要ないよね。

あ、それ面白いね。俺もRAGを作ったばかりで、データベース内のファイルをファイルとして公開するのが次の論理的なステップだと思ったんだ。もしそうなったら、Fuseを使っただろうな。そしたら実際のファイルシステムになるから。