
RAGを使っていて「なんか毎回同じことを聞き直しているな」と感じたことはないでしょうか。
チャンクを検索して、その場でLLMが回答を組み立てて、セッションが終わる。
また明日同じことを聞いたら、また同じプロセスが走る。
その感覚、構造的に正しいんです。
RAGは「検索して答える」設計であり、「知識を蓄える」設計ではありません。
nashsu/llm_wiki はこの問題に正面から向き合ったツールです。
Andrej Karpathyが提唱した「LLM Wikiパターン」をデスクトップアプリとして実装したもので、ドキュメントを投入するたびにWikiページを増分構築していきます。
「本当にそうなるのか?」が気になったので実際にローカルで動かしてみました。
この記事はその一次体験をそのまま書いたものです。
RAGが「知識を積み上げない」という構造的な問題
RAGの基本的な動作サイクルはシンプルです。
ドキュメントをチャンクに分割してベクトル化しておき、クエリが来たら類似チャンクを検索して、LLMに渡して回答させる。
この流れは「検索して答える」という目的においては合理的です。
問題は、このサイクルが 毎回ゼロから回る という点にあります。
たとえば、会議のたびに議事録を社内RAGシステムに投入しているとします。
「先月の〇〇プロジェクトの方針変更はなぜ起きたのか」という質問に対して、RAGは関連チャンクを拾ってきてその場で回答を組み立てます。
次の人が同じ質問をしても、また検索して、また組み立てる。
10人が聞いても100回聞いても、同じコストで同じプロセスが走ります。
より根本的な問題は、この回答がどこにも残らないことです。
LLMが導き出した「複数の決定が積み重なった因果関係」という洞察は、セッションが終われば消えます。
ドキュメントは増えても、組織の理解は積み上がらない。
これはRAGの欠陥というより、 設計の用途の違い です。
RAGは「大量のドキュメントから関連情報をすばやく引き出す」のが得意で、その目的には今でも強力なアーキテクチャです。
ただ、「繰り返し参照される概念をチームの共有知識として定着させる」という目的には、そもそも向いていません。
llm_wikiはこの「知識が積み上がらない」という問題を、根本的に異なる設計で解こうとしています。
llm_wikiの設計思想:インタープリタではなくコンパイラ
Karpathyはこのパターンを説明する際に、インタープリタとコンパイラの比喩を使っています。
RAGはインタープリタです。クエリが来るたびにソースを読んで、その場で解釈して、答えを出す。
llm_wikiはコンパイラです。ソースを一度読んで構造化された知識ベースにコンパイルしておき、クエリへの回答はそこから引き出す。
この比喩は設計の本質を突いていると思います。
llm_wikiの内部構造は三層になっています。
- raw層(ソース):ユーザーが投入するオリジナルのドキュメント(PDF・DOCX・MDなど)。書くのは人間、読むのはLLM
- wiki層(知識ベース):LLMが生成・更新するMarkdownファイル群。書くのはLLM、読むのは人間とLLM
- クエリ層(回答生成):wiki層を参照してクエリに答える。ベクトル検索はオプション扱いで、Markdownの構造そのものが知識の主体
この三層の中で核心になるのが、wiki層の 増分構築 という動作です。
新しいドキュメントを投入するとき、llm_wikiは単にインデックスを追加するのではありません。
LLMがそのドキュメントを読んで、既存のwiki層と照らし合わせ、関連するページを更新し、新しい概念があればページを追加し、矛盾があれば記録する。
この「既存ページが育っていく」動作が、RAGのインデックス追加とは本質的に異なる点です。
生成された各Wikiページには、YAMLフロントマターに sourcesフィールド が含まれ、どのソースドキュメントから生まれたかを追跡できます。
また、ingestのたびに overview.md が自動再生成され、wiki全体の現在の状態を反映したサマリーが常に最新に保たれます。
ベクトル検索を有効にすれば埋め込みも自動生成されますが、有効にしなくてもMarkdownの構造だけで機能します。
「知識は一度コンパイルして使い回す、クエリのたびに再導出しない」という設計がllm_wikiの核心です。
ローカルで動かすまで:環境構築からingest確認まで
実際に手元で動かしてみます。
前提として Node.js 20以上・Rust 1.88以上・protoc が必要です。
Node.jsとRustは普段使っている方も多いと思いますが、protocで詰まるケースが多いので先に入れておきましょう。
# macOS
brew install protobuf
# Ubuntu / Debian系
sudo apt install protobuf-compiler
# Windows(Chocolateyを使う場合)
choco install protoc
protocのバージョンが古いとビルド時にエラーが出ます。
protoc --version で確認して、3系以上が入っていれば問題ありません。
続いてリポジトリのクローンと依存インストールです。
git clone https://github.com/nashsu/llm_wiki.git
cd llm_wiki
npm install
npm installが完了したら、LLMプロバイダーのAPIキーを用意します。
アプリのGUI設定画面から入力することもできますが、環境変数で渡したい場合は .env ファイルを作成します。
# .env ファイルにAPIキーを設定
OPENAI_API_KEY=sk-...
# または
ANTHROPIC_API_KEY=sk-ant-...
確認だけなら開発モードで十分です。
npm run dev
GUIウィンドウが立ち上がったら、まず「新規プロジェクトを作成」からプロジェクトを作ります。
次に設定画面でLLMプロバイダーとモデルを選択します。
ここで接続確認を先にやっておかないと、ingestを走らせても何も起きなくて原因がわかりにくいので注意してください。
あとはソース画面からドキュメントをインポートするだけです。
PDF・DOCX・MD形式に対応しています。
インポートするとアクティビティパネルが動き始め、LLMがページを生成していく様子をリアルタイムで確認できます。
小さめのMarkdownファイルなら数十秒でwikiページが生成されます。
思ったより早い、というのが正直な印象でした。
社内ドキュメントを投入すると何が起きるか
具体的に確認するために、会議の議事録を想定したMarkdownドキュメントを投入してみます。
# 2025年5月 キックオフ会議議事録
日時: 2025-05-10
参加者: 田中(PdM)、山本(エンジニアリード)、佐藤(デザイン)
決定事項:
- 認証基盤はAuth0を採用する(自前実装はコストが高いため)
- フロントエンドはNext.js 15で統一する
- リリース目標は2025年Q3
懸念点:
- Auth0の月次コストが予算を超える可能性がある
- Q3リリースはバックエンドAPIの完成に依存する
ingestを実行すると、wiki層にいくつかのMarkdownファイルが生成されます。
以下は実際の出力構造を元にした想定例ですが、Auth0に関するページはこんな構造になります。
---
title: Auth0
sources:
- raw/kickoff-2025-05.md
created: 2025-05-12
updated: 2025-05-12
---
認証基盤として採用が決定したサービス。
自前実装と比較してコスト効率が高いと判断された一方、月次費用が予算を超える可能性も記録されている。
採用経緯:
2025年5月のキックオフ会議において、認証基盤の実装コストを考慮して採用決定。
関連: [[Next.js 15]] / [[認証基盤]] / [[プロジェクトキックオフ 2025-05]]
sourcesフィールドに元のファイルパスが入り、本文には議事録から抽出・再構成された内容が入っています。
そして関連するwikiページへの内部リンクが自動で張られます。
次に、別の議事録を追加投入してみます。
その会議で「Auth0のコスト問題が再度議論されて、Amazon Cognitoへの切り替えが検討事項に挙がった」という内容が含まれていた場合、llm_wikiは既存のAuth0ページを 更新 します。
出力例を簡略化して示すとこうなります。
---
title: Auth0
sources:
- raw/kickoff-2025-05.md
- raw/review-2025-06.md
updated: 2025-06-15
---
認証基盤として採用が決定したサービス。
ただし、コスト面の懸念から代替案(Amazon Cognito)の検討も進んでいる。
採用経緯:
2025年5月のキックオフ会議で自前実装のコスト比較を経て採用決定。
現状の課題:
2025年6月のレビュー会議で月次コストが予算上限に近いことが報告された。
Amazon Cognitoへの切り替えが検討事項として記録されている。
関連: [[Next.js 15]] / [[認証基盤]] / [[Amazon Cognito]] / [[プロジェクトキックオフ 2025-05]] / [[プロジェクトレビュー 2025-06]]
sourcesフィールドに新しいソースが追記され、本文が更新されています。
これが増分コンパイルの実際の動作です。
同じ概念が複数のドキュメントにまたがって登場するたびに、ページが育っていきます。
正直なところ、生成品質には揺れがあります。
2つのソースの情報をどう統合するかはLLMとプロンプトの品質に依存するため、矛盾する情報が入力されたとき一方が上書きされてしまうケースも実際に見かけました。
llm_wikiにはレビュー機能とlintコマンドが用意されていて、wikiの健全性を定期的にチェックできます。
ある程度の規模になったら、lintを定期実行する運用を組み合わせると安心です。
RAGとllm_wiki、どちらを選ぶか
どちらが優れているか、という問いの立て方はあまり意味がないと思っています。
設計の目的がそもそも違うので、比べるというより「何を解きたいか」で選ぶ話です。
RAGが向いているのは、大量の非構造化ドキュメントを横断的に検索したい場面です。
更新頻度が高く、オープンエンドなクエリを大量にさばく必要がある、ドキュメントが数百・数千を超えていくスケール。
これらが重なる場合、ベクトル検索インフラとしてのRAGの強みは依然として大きいです。
llm_wikiが向くのは、コーパスが中小規模で比較的安定していて、同じ概念が複数のソースにまたがって登場するような場面です。
議事録・仕様書・マニュアルのように「何度も参照される概念を持つドキュメント」が蓄積していく環境では、RAGよりllm_wikiのほうが知識の使い方に馴染みます。
ベクトルDBのインフラをできるだけ持ちたくない、という制約がある小規模チームにとっても、Markdownファイルだけで動く設計はシンプルです。
現実的な解として興味深いのが、llm_wikiが生成したMarkdownをRAGのインデックス対象にするハイブリッド運用です。
生のドキュメントをチャンク化して流すのではなく、LLMが一度整理した構造化済みMarkdownを検索対象にすることで、検索精度が上がる可能性があります。
知識の構造化と横断検索、それぞれの強みをレイヤーで使い分けるイメージです。
閉域運用の可能性についてもひとつ触れておきます。
llm_wikiはAPIキーの向き先をプロバイダーごとに設定できる構造になっているため、利用するLLMプロバイダーの選択次第で、社内ドキュメントを外部に流さない運用に対応できる余地が生まれます。
セキュリティ要件が厳しい現場では、プロバイダーの選択を含めて検討する価値があります。
「検索して答えたい」ならRAG、「知識を構造化して蓄えたい」ならllm_wiki。
設計の目的から逆算して選べば、どちらを選んでも後悔は少ないはずです。
ホコサキでは社内ドキュメントのAI活用やナレッジベース設計を含む、実務寄りのDX支援をしています。
「RAGは試したけど、もっと知識が蓄積する仕組みを作りたい」という方は、お気軽にご相談ください。

