🤖

AIに「意味」の住所を教える。Obsidian MCP サーバをセマンティック検索に対応させた冬休みの記録

に公開

冬休みの自由研究は、予想外の深淵へと僕を誘い込んだ。

前回、Obsidian(第二の脳)とCursorをMCPで繋ぐ「手足」を作った。

https://zenn.dev/sal9000/articles/b5d6584ea482c6

けれど、使い込むうちに一つの壁にぶつかった。「キーワード一致」という、あまりに古風で融通の利かない検索の壁だ。

「AIの倫理」について書いたメモを、AIが「人工知能の道徳」という言葉で探し出せない。この分断を埋めるために、僕は「セマンティック検索」の実装、つまり、僕の思考を 1,536 次元の数学的空間へと放り込む作業に着手した。

理論:言葉を「座標」へと変換する数理的アプローチ

セマンティック検索の本質は、非構造的な「言葉」の多次元空間上の「ベクトル」への写像を作ることにある。

例えば、「王様」という概念を AI に入力したとする。このとき生成されるのは、1,536 個の実数成分を持つベクトル \mathbf{v} \in \mathbb{R}^{1536} だ。そこには「性別」「権力」「抽象度」といった、人間には到底カウントしきれないほど多角的な「意味の次元」が数値化されて封じ込められている。

ここで数学的な美しさが現れる。1,536 次元の超空間において、意味の似た概念(例:王様と女王)は互いに近い座標に配置され、無関係な概念(例:王様とリンゴ)は遥か彼方へと引き離される。

僕たちが検索クエリ \mathbf{q} を投げたとき、システムはあらかじめベクトル化された各メモ \mathbf{d}_i との間で「コサイン類似度」を算出する。

\text{similarity}(\mathbf{q}, \mathbf{d}_i) = \cos(\theta) = \frac{\mathbf{q} \cdot \mathbf{d}_i}{\|\mathbf{q}\| \|\mathbf{d}_i\|} = \frac{\sum_{j=1}^{n} q_j d_{ij}}{\sqrt{\sum_{j=1}^{n} q_j^2} \sqrt{\sum_{j=1}^{n} d_{ij}^2}}

数式で見ると複雑に感じるかもしれないが、やっていることはシンプルだ。二つのベクトルのなす角 \theta を測り、その方向がどれだけ一致しているかを判定しているに過ぎない。たとえ一文字も一致していなくても、意味の方向性が同じであれば、AI は暗闇の中から僕の過去の思考を正確に手繰り寄せてくれる。これが、キーワード一致を超えた「文脈の理解」の正体だ。

次元が多すぎると「呪われる」のではないか?

ここで一つ、数学的な懸念が生じる。「次元の呪い」だ。通常、次元が増えるほど空間は指数関数的に広がり、データは極めてスパース(スカスカ)になる。

ユークリッド距離 d(\mathbf{x}, \mathbf{y}) = \sqrt{\sum (x_i - y_i)^2} を指標に使う場合、高次元空間ではあらゆる点同士の距離がほぼ等しくなり、意味のある区別ができなくなるという致命的な問題が起きる。

しかし、現代の Embedding モデルはこの呪いを鮮やかに回避している。

第一に、絶対的な距離ではなく「角度(コサイン類似度)」に注目している。全てのベクトルを単位球面上に射影して考えることで、位置関係よりも「情報の向き」という濃淡を抽出することが可能になる。

第二に、「多様体仮説(Manifold Hypothesis)」の恩恵を受けている。1,536 次元という広大な空間であっても、意味のある言葉のデータは、実はその中の極めて低次元な構造(多様体)の上にのみ存在している。LLM は学習を通じてこの「意味のある通り道」を正確にマッピングしているため、スカスカな空間に迷い込むことなく、実用的な検索精度を維持できているのだ。

コサイン類似度でも逃れられない直交の呪い

しかし、ここでさらなる問いが生まれる。コサイン類似度を使えば万事解決なのか?

数学的な性質として、次元 n が増大するほど、ランダムに選ばれた二つのベクトルはほぼ確実に「直交」するという現象がある。次元が 1,000 を超えると、適当に生成したベクトルのなす角は 90度(内積0)付近に極端に集中し、分布の裾野が消えてしまうのだ。

つまり、何の工夫もなければ、あらゆるメモ同士が「全く無関係」と判定され、意味の微細な差がノイズに埋もれてしまうはずだ。この「直交の呪い」を、現代の Embedding モデルはどう回避しているのか。

その答えは、モデルが 「意味のある関係性に対して、意図的に分布を偏らせている」 点にある。

Embedding モデルは、単なる数値変換器ではない。人類が書き残してきた膨大な文章データ(コーパス)を用いた「対照学習(Contrastive Learning)」を経て構築されている。

具体的にイメージしてみよう。
学習前のモデルにとって、「王様」と「女王」という二つのベクトルは、広大な 1,536 次元の野原にランダムに放たれた、互いに無関係な点に過ぎない。

  • 王様: [0.12, -0.05, 0.88, ...]
  • 女王: [-0.44, 0.21, -0.03, ...]

この二つの内積(なす角)を計算すれば、当然 0 に近く、数学的な「直交」の状態にある。

しかし、対照学習はこの座標を強引に書き換える。大量の文章を読み、「王様」と「女王」が常に同じような文脈で現れることを知った AI は、二つのベクトルを あえて極めて狭い特定の方向に「押し込める」 ように学習する。

  • 王様: [0.77, 0.11, 0.05, ...]
  • 女王: [0.75, 0.12, 0.04, ...]

結果として、先頭の成分(この例では 0.7x 付近)が共通の「高貴な統治者」という強い意味の方向性を持ち、なす角 \theta は限りなく 0 に近づく。つまり、コサイン類似度(\cos \theta)の値が極限まで 1 に近づくというわけだ。

言い換えれば、1,536 次元の空間のほとんどは「使われていない死んだ空間」であり、意味を持つデータは特定の「意味の山脈」の中に密集している。この 「学習された不均一性」 こそが、数学的な直交の呪いを抑え込み、僕たちが期待する「似ているものは近くに」という直感を高次元世界で実現させている正体なのだ。

この「意味の近い状態に特定の方向へ情報を畳み込む」という行為は、統計学における主成分分析(PCA)のプロセスに似ている。PCAがデータのばらつきから本質的な軸を抽出するように、Embedding モデルはコーパスという膨大な経験から「意味の本質的な軸」を抽出し、そこに情報を凝縮させているのだ。

ただ、Embedding が PCA よりも遥かに強力なのは、それが単なる線形な圧縮ではなく、意味のつながりに基づいて空間そのものを複雑に折り畳んでいる点にある。遠く離れた場所にある「王様」と「女王」という概念が、多次元空間の中でピタリと重なるように空間を歪める。この 「意味による空間の折り畳み」 こそが、セマンティック検索を魔法たらしめている正体と言えるだろう。

LangChain と FAISS で編む索引

実装には LangChain を使い、以下の 3 ステップで僕の Vault を再定義した。

  1. チャンク分割: 数千文字のメモを、意味の断絶が起きないように 1,000 文字程度の「チャンク」に切り分ける。
  2. ベクトル化(Embedding): OpenAI の API を叩き、僕の言葉を 1,536 次元の座標へと変換する。
  3. FAISS インデックス作成: 手に入れた「住所」をローカルのベクトルデータベース(FAISS)に整理して保存する。

ここまで述べてきた数学的な理論は、確かに一定の難解性を含んでいる。しかし、実際に手を動かす段階になると、驚くほどその詳細を意識しなくて済むことに気づかされる。LangChain というフレームワークが、これらの複雑な数理的アプローチを「API呼び出し」や「メソッド一つ」のレベルまで高度に抽象化してくれているからだ。

僕たちは数式を解く代わりに、情報の設計に集中できるようになっている。

セマンティックサーチの挙動

実装を終えて、実際に検索を試してみたとき、セマンティックサーチの威力に驚かされた。

「教育とAIの未来」について尋ねると、AI はメモの中にその文言がなくても、過去の友人との会話のGemini議事録や、深夜に書き殴った考察を拾い上げてきた。

MCP サーバを作ることは、単なる情報源への接続インターフェースのコーディングではない。
AI に何を見せ、どう探させ、どう考えさせるかという「知のインターフェース」を設計することと言える。

今の僕の実装はまだ、文字列の一致を卒業して「意味の近さ」を理解し始めたばかりの、不格好な手足でしかない。けれど、自分の文脈を理解した AI と対話する心地よさは、一度知ってしまうともう元には戻れない。

冬休みの自由研究は、まだ終わらない。次はこの 1,536 次元の地図の上を、AI にもっと自律的に歩かせてみようと思う。

参考:実装サンプル

https://github.com/shuhei0866/mcp-server-obsidian-slipbox/commit/1932d5eb378f0e3429c6b8403821b5fc90846901

Discussion