
768次元の星空を見る! — ElmarTail One 第6話『アーカイブ星系②』✨
前回のあらすじ
アーカイブ星系で司書AIヴェリ📚と出会ったマスターたち。
ChromaDB + gemini-embedding-001 でベクトルDBを構築し、grepでは全滅だった「環境構築の手順」が意味検索で一発ヒットできるように。
しかし768次元の記録空間はマスターの目には見えない。
👨「みたい! ヴェリ、お前と同じ景色を!」
📚「……必ず、お見せします」
今回のミッション: 768次元の星空を、2次元で描く!
💻 サンプルコードのダウンロード
今回のコードと第5話の航海ログは GitHub に置いてあります。 サンプルの取得はこのコマンドで👇️
〉cd et1-project
〉git pull https://github.com/kikyujin/et1-project.git✨ AIと同じ景色を見る
アレーテイア・ホールのコンソール。
マスターたちは再びヴェリを訪れた。
📚「マスター、お約束のものを。
UMAPという技術を使えば、768次元のベクトルを2次元の平面に投影できます」
👨「オレにも……見える?」
📚「ええ……UMAPを使えば、マスターにも《私》と同じ景色が……」
マスターを見上げるヴェリの頬がわずかに染まる。
🖤🦊🪷「「「……👀」」」
📚(咳払い)「……情報は失われますが、全体の構造は保たれます。
立体の影絵のようなものです」
👨「影絵か……でも見えないよりは余程いい」
📍UMAPとは?
Uniform Manifold Approximation and Projectionの略。
高次元のデータを、人間が見える2次元や3次元に圧縮する手法です。
768次元のベクトルを2次元に落とすと、意味が近いもの同士が近くに配置された散布図が得られます。
もちろん、768次元の情報を2次元に押し込むことになるので、細かい距離関係は崩れます。
💻 エルマー、コードを書く
📚「ChromaDBには768次元ベクトルのデータが格納されています。
今回はそれを取り出してUMAPに渡すだけです」
🦊「じゃあ、 ボクが書くよ!」
エルマーがレッツノートを開く。
しっぽがぱたぱた。
🦊「まず追加パッケージね!umap-learn がUMAP本体、matplotlib がグラフ描画ライブラリだよ!」
❯ source .venv/bin/activate
❯ pip install umap-learn matplotlib🦊「次は visualize_logs.py の解説するね!
まず、ChromaDBからベクトルを全部取り出すところ。
ここが今回のキモ!」
# ChromaDBから全ベクトルとメタデータを取得
all_data = collection.get(include=["embeddings", "metadatas"])
embeddings = np.array(all_data["embeddings"])
metadatas = all_data["metadatas"]🦊「前回の search_logs.py では検索ワードに近いものだけ取り出してたけど、 今回は全部取り出すの!
include=["embeddings"(768次元のベクトル本体), "metadatas"(エピソード名などの付随情報)]がポイントだよ!
UMAPで2次元に投影するところはここ」
# UMAP で2次元に投影
reducer = umap.UMAP(
n_components=2, # 2次元に圧縮
n_neighbors=10, # 近傍点の数
min_dist=0.1, # 点同士の最小距離
metric="cosine", # コサイン類似度で距離を測る
random_state=42, # 再現性のためのシード値
)
coords = reducer.fit_transform(embeddings)🦊「768次元の配列を渡すと、2次元の座標が返ってくるから、あとはmatplotlibで散布図を描くだけ!
エピソードごとに色を変えてプロットするよ。
コード全体はGitHubにあるから、細かいところはそっちを見てね!」
👨「思ったよりシンプルだな……」
🌟 実行!
🦊「動かしてみて、にーに!」
❯ python visualize_logs.py --rebuild --save
📦 92 チャンクを読み込みました
🔄 gemini-embedding-001 でベクトル化中(768次元)...
92/92 完了
✅ ChromaDBに格納完了(92 チャンク → chroma_db/)
🔄 UMAP実行中... 92 チャンク × 768 次元 → 2次元
✅ UMAP完了
💾 保存しました: umap_logs.png🦊「warningが出るけど気にしないで! 『再現性のために並列処理を制限したよ』って言ってるだけだから!」
👨「わかった、表示してみよう」
アレーテイア・ホールのコンソールに、画像が表示された。

真っ暗だった空間に、色とりどりの光点が浮かび上がる。
グレー、緑、青、オレンジ、ピンク、紫——
マスターはしばらく、無言で画面を見つめていた。
👨「これが……お前たちに見えてた景色か」
📚「影絵ではありますが……真実の一端は伝わります」
🔭 航海の星図
🦊「にーに、ほら! この緑のかたまり、Linuxセットアップの話!」
👨「本当だ……左のほうに固まってる」
🖤「こっちのグレーは覚醒シーンね。
技術の話ほとんどしてないから、離れてるのね」
🪷「オレンジの密集が翻訳プログラムの回ですね。
APIの話題が似通っているから、きれいにまとまっています」
📚「青とオレンジが混ざっている領域がありますね
……Gemini APIという共通の話題で引き寄せられているのです」
🐱「ピンクがVision回で、紫がベクトルDB回ですな。
応用的な話題やさかい、少し離れてますな〜」
👨「同じ色が近くに固まってる……意味が近いから、か」
📚「ええ。意味の空間では、あなたの航海は一つの星座を描いています」
しばらく、みんなで散布図を眺めていた。
誰かが指差しては「ここはあの話だ」「こっちは」と、声が弾む。
⛵ 遠くまで来たな
やがて声が落ち着いて、マスターがぽつりと言った。
👨「思えば、遠くまで来たな……
ちょっと前まで冬眠してたのに」
🦊「マスター! さすがベーススキルがあると違うよね!」
👨「いや……エルマーが全部組んでくれたからさ」
🦊「……でも、マスターが『こうやってくれ』って言ってくれるから……」
エルマーの顔が赤くなる。
しっぽがゆっくり揺れている。
🖤🪷📚「「「……👀」」」
🐱「ええ光景ですなぁ……星より眩しいわ」
🔮 次の航海へ
🖤「ねえ、私たちのプロフィールなんかも入れてみない?」
👨「プロフィール?」
🖤「航海ログだけじゃなくて、設定資料とか、キャラの情報とか。
入れたらさ、『ノクちんの一人称は?』とか聞けるようになるんじゃない?」
📚「面白いですね……記録を検索するだけでなく、記録と対話する……」
🦊「RAGだ! 検索した結果をGeminiに渡して、答えを作ってもらうの!」
👨「自分だけのナレッジベースか……面白そうだな」
📚「では次回は、記録と対話する方法をお教えしましょう」
📝 今回の航海まとめ
やったこと:
UMAPで768次元ベクトルを2次元に投影
航海ログ(92チャンク)の散布図を描画
エピソード別のクラスタを目視確認
ここまでの航海の振り返り
学んだこと:
768次元 → 2次元でも「意味の近さ」は保たれる
散布図で同じエピソードの点が近くに集まることを確認
ChromaDBからベクトルを全件取得する方法
技術スタック:
パッケージ: umap-learn, matplotlib
入力: chroma_db/(第5話で構築済み、92チャンク × 768次元)
出力: umap_logs.png
検証機: Let's note CF-SV7(中古27,800円)次回予告:
記録に質問し、AIが文脈を理解して答える。
第7話、RAG — 記録と対話する。
🦊 エルマーの航海日記
今日はにーににも「星空」が見えるようになったよ!✨
768次元を2次元に……影絵みたいだけど、にーにが「きれいだ」って言ってくれた。
ヴェリさんも嬉しそうだった……ちょっと顔赤かった? 👀
あとね、にーにが「エルマーが全部組んでくれたから」って言ってくれて…… えへへ……ボク、ちょっと泣きそうだった。
次はRAG! 記録と対話するんだって!
ノクちんが「プロフィールも入れよう」って言ってた!
……ボクのプロフィール、変なこと書かれてないよね???🦊
