MCPとRAGとLLMで苦労してた話

AI界隈で有名な方が最近MCP触ってないんだけど?みたいな話を見かけたことで、下書きになってた記事の存在を思い出したので掘り起こしてみる。

MCPは良くも悪くも定着しただけに思えるし、まだRAGのためプロトコルという程度の使われ方しかしていないので、そりゃ使わなければ使わんだろうなぁ、という感想。コマンド実行toolだけでよくね?って。

以下は掘り起こしたもの。AIにまつわるもの全般が使いこなせていない苦悩を吐き出しているだけ。お役立ち情報は無いです。


AIに脳みそをやられています。

昨今は何でもMCPだ、AIエージェントの連携だと騒がれていますが、正直なところ、全然実用的なものが出てきている印象がありません。何か月経っているんでしょうか。私の観測範囲が狭すぎるだけだとは思いますが。

最近はRAGという名の検索システムを作ろうとして心が折れたり、LLMがMCPツールを使いこなせなかったり、期待する結果にならず原因を分析したり…そんなことばかりやっています。


MCP自体は大したことはない

みんなMCPについて何度も入門していると思いますが、Webアプリ開発時代を生き抜いた人なら、これは「サーバサイドとクライアントサイドのSDKが付いたREST API」と解釈して問題ないと思っています。

MCP自体は色々な仕様が盛り込まれていますが、実際に使うのはほとんどが tools です。tools は、クライアントがサーバ側の function calling を行うための情報を返したり、実際に function calling を行うための窓口にすぎません。

  • (1) ツールの一覧を取得し、LLMに渡す
  • (2) LLMにどのツールを使うか決定させ、引数を作らせる
  • (3) そのツールを呼ぶ

HTTPでWebアプリを作っていたなら、次のようなフローを作ったことがあるはずです。

  • ユーザ一覧(/users)を呼び、画面に表示する
  • あるユーザのリンクをクリックする
  • そのユーザの詳細(GET /users/{id})を呼ぶ、あるいは自身の情報を更新する(PUT /user)

やっている内容はこれだけです。 ユーザが操作するか、LLMが判断するか、SSEでストリーミングされるかどうか、その程度の違いしかありません。MCPの tools は、せいぜいこの程度のことしかやっていません。

MCPは仕様上いろいろと風呂敷を広げていますが、直近20年近くのWebにおける人間の営みは、REST APIのような単純な仕組みでなんとかなってきました。 人間がやっていた操作を機械にやらせるプロトコルとしても、単純なリクエスト・レスポンスで十分なのです。むしろ単純なほうがスケールするので都合がよい。

MCPクライアントとサーバのSDKを整備した点は、評価されるべきだとは思います。それがなければ「REST APIでよくない?」派が跋扈していたでしょう。実際、「MCPにWebSocketを」という議論もありますしね。

ただ、仮にMCPがWebSocketをサポートしたとしても、クライアント側がWebSocketをうまく使えないケースのほうが多いでしょう。結果として高度な機能は結局使われない、という未来が見えています。

よくMCPはUSBハブのようなものだと例えられますが、私はこれがどうしても腑に落ちません。

サーバ側からクライアントのリソースを取得する仕組みもMCPにはありますが、クライアントはサーバが求めるものを本当に返せるのでしょうか。 たとえば「航空券予約のために個人情報とカード情報が必要です、ください」とサーバが要求してきたとき、クライアントは何をすれば「はい、どうぞ」と返せるのでしょうか。

もちろん、生データを渡すわけではなく、PayPalやStripeのような第三者サービスで抽象化したり、承認フローを挟んだりすることは考えられます。しかし問題はそこではありません。 サーバが求めている「コンテキスト」を、クライアントが正しく理解し、適切に渡せるのでしょうか。結局はクライアント次第です。 プリンターのUSBポートに無線マウスを挿したら便利になりますか?という話です。

こうした疑問が私ですら浮かぶのに、どう対処するのか、あるいは実際にどう活用しているのか、そうした話がほとんど見当たりません。 みんなMCPに入門するだけで、その先の情報が出てこないのです。

これまでだって、クライアントはサーバ側の作法に倣って連携してきたはずです。だからこそ、クライアントはサーバのコンテキストを理解できているのが普通でした。 MCPがそれを解決しているとは、正直まったく思えません。

「繋ぐだけ」の共通プロトコルとしては、HTTPのようにMCPが機能するので、今はそれで十分なのかもしれません。 自然言語こそがハブだ、という主張なら、まあ分からなくもないですが。


MCPで何をするかが重要

MCP自体はそれほど重要ではなく、エージェントのために「何をしてあげられるか」が重要です。

一般的にはRAGを提供する使い方が多いでしょう。

それ以外では、単にコマンド実行を指示すれば足りるケースも多いです。 毎回発生する初期化時間を減らしたい、といった理由があるならMCP化する価値はあるかもしれません。serenaのように、grepやsedの代替として、より高度で効率的な処理をさせるMCPサーバもあります。

過去に、code coverageの結果を返す部分をMCPサーバで実装したことがあります。しかし結局、カバレッジファイルの作成はコマンドで実行させ、そのファイルをwatchする構成になりました。 ファイルに対応するカバレッジ情報をLLM向けに単純なテキストで返す、というものです。

その後CLI版を作ったところ、処理速度は十分すぎました。 「これ、MCPである必要ある?」という気持ちになり、最終的には「爆速なCLIツールのほうが、人間も使えて便利では?」という結論に傾きました。

MCPを使ってくれないLLMたち

MCPを使う文脈を、こちらが明示的に教えてあげる必要があります。 「C#のコードを実装する場合」「Azureのサービスを使ったアーキテクチャを検討する場合は Microsoft Learn MCP を使いなさい」といった具合です。

また、MCPサーバ側の各 tools には description を与えられますが、これを最初にまとめて受け取るため、コンテキストトークンを逼迫する、という有名な問題があります。

これへの基本戦略は、「使うMCPをAIエージェントごとに分ける」ことです。

AIエージェントって?

役割を持たせてその範囲の仕事を任せると、扱えるコンテキストトークンを抑えつつ目的を達成できます。

コードの修正を行う際、LLMはまずthinkingしどこにどういうコードがあるかをディレクトリ構造やAGENTS.mdの内容から理解したり、どこに目的のコードがあるかgrepコマンドなりsearchツールなりで検索し、特定のファイルのn行を読み取り、それに対してどう修正するかthinkingし、コードを置換し、テストを実行しテストの実行結果からパスしたと判断するまで作業します。

この過程が全部コンテキストトークンに乗っかってきます。よくセッションをこまめに切り替えなさいと言われるのはこのあたりが大きいです。

でもコードを修正してほしい側としてはコードが適切に置き換わっていればなんでもよいわけです。

それをエージェントという形で役割を独立させて作業を任せるわけです。上司と部下のような関係ですね。

要は「お飯事させる」わけですから設定が重要です。しかしLLMだとどの文言が効いたかなんてわからないので、地道な努力と継続が必要となります…

Claude Skillsはどうなの?

Claude Skillsのように、必要になったら skill 情報を読み取り、API設計やコーディング規約やテスト戦略といった操作を改善する方法もあります。

これはMCPのように動的に情報を取得するものではなく、静的な情報を必要に応じて与える仕組みです。 要するに、AGENTS.mdを役割ごとに分けて用意する、という発想です。

こうしておけば、実装フェーズなのに設計に関する情報でコンテキストトークンを圧迫する、といったことは防げます。

あと、よくあるタスクをmarkdownに書き連ねてこういうときにこれを読んでね、ぐらいでも十分だったりします。ツールの指定をできたり違いはありますけど。

良い仕組みには見えますが、結局はコンテキストトークンをやりくりするための回避策にすぎません。本当に優秀なLLMがすべて学習していれば、そもそもこんな工夫は不要なのになぁ。

RAGは大したことない。だが、RAGシステムは非常に難しい

MCPの活用例としてよく挙がるのは、RAGとの組み合わせでしょう。

LLM単体の知識では足りないため、固有の知識を外部から引っ張ってきてLLMに与え、その知識に基づいて回答させる。それがRAGです。 各社が提供しており、実際に便利です。

トップダウンで「社内ナレッジをLLMで活用しろ」と言われたら、社内ナレッジをMCP経由で渡す戦略は妥当でしょう。

そのためにはRAGシステム、つまり社内ナレッジに特化した検索エンジンが必要になります。 pgvectorやAzure AI Searchを触った程度の知識でも分かりますが、これがとにかく難しい。

LLMには扱えるコンテキストトークンに制限があるため、その範囲内で必要十分な情報を渡す必要があります。 そのため、ドキュメントをチャンクに分割し、要求に合うチャンクを検索して渡す、という構成になります。

しかし、言うは易し行うは難し、です。

狙ったチャンクがなかなか引っかからない。 自然文で聞く人もいれば、キーワードで聞く人もいます。それをどうクエリにするのか。

LLMにクエリを作らせる方法もありますが、重要な情報が抜けることもあります。 ユーザの入力をそのまま受け取り、RAG側で処理する方法もありますが、応答性は確実に落ちます。

チャンク化も地獄です。 Markdownは見出しがないものもありますし、PDFはさらに厄介です。OCR、図表、変換コスト… なんか、ETLで見たやつだ、となります。

検索手法も悩ましい。全文検索、ベクトル検索、リランキング。 Embeddingの更新が入れば、過去データは全洗い替えです。考えたくありません。

そして、苦労して返したチャンクを見て、LLMは 知った気 になります。 対策はいくらでもありますが、決定打はありません。

元ドキュメントは100%正しい必要があります。 議事録の思いつきを事実として扱われたら困ります。 メタデータや分類で多少は抑えられますが、トークン消費との戦いです。

一番良いのは、ナレッジストアを分けることです。 議事録用、仕様書用、と分ければ、LLMが選んでくれるかもしれません。

「かもしれません」。ここが厄介です。 モデルを変えたら使ってくれない、アップデートで挙動が変わる。十分あり得ます。

正直、最近の進歩速度を見ると、そこまで楽観はしていません。 みんなLLMを良くするより、使わせてマネタイズする方向に見えます。


RAGの評価

RAGが大変なのは分かりました。では、その施策が効いたのかをどう評価するか。これは早期に検討すべきです。RAGASが有名でしょう。ただ、この辺で色々あり、心が折れました。データ作るの好きじゃないので辛かったし、LLMのモデルでflakyな結果になった時が辛かった。でも一番は手伝ってくれる人がいなかったことでしょうか。

理想はユーザフィードバックですが、不完全すぎるとそもそも使ってもらえません。質が悪いだのMCPを使わなくてもあまり変わらない気がするだの、役に立たない感想を色々言われます。

ちなみに当たり前としてリクエストとレスポンス内容はトレースできるよう記録しておくとよいです。まぁそれをどこにストアするのかとかプライバシーの話はありますが、良し悪しを評価できないほうが辛いので。

良し悪しを評価するには理想的にはドメインエキスパートが必要になります。しかし、その人たちは忙しい。……となると、自分がドメインエキスパートになるしかないのです。