hubmesh について
hubmeshは、既存のベクトルデータベースに重ねて使うPython製GraphRAG検索プランナーで、マルチホップRAGの構築に適しています。決定的なグラフランキングとコンテキスト予算に応じた整理を行い、クエリ処理中にLLMを呼び出しません。
主な機能
- 01グラフベースのマルチホップ検索計画
- 02コサイン関連度とPPRランキングの統合
- 03コンテキスト予算に応じた結果整理
- 04メモリ、Qdrant、Chromaアダプター
- 05エンティティ解決と経路説明
活用シーン
- 01関連エンティティをまたぐ根拠の検索
- 02既存ベクトルDBへのグラフ検索追加
- 03使用済み文書を除外した反復検索
MCP 対応
オプションのMCPサーバーは、stdioまたはSSE経由でコーパスのインデックス作成、検索、エンティティ解決、グラフ照会、文書取得のツールを公開します。検索ツールはLLMを呼び出さず、マルチホップの計画はエージェントが担います。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
hubmesh
中心性を考慮した GraphRAG 検索プランナー。あらゆるベクトルデータベースに追加できるレイヤーです。
hubmesh は、既存のベクトルデータベース上でマルチホップ RAG の品質を向上させる Python ライブラリです。インフラストラクチャを置き換える必要はありません。ベクトルデータベースと LLM の間にスマートなプランナーを追加します。
解決する課題
素朴なベクトル検索(「クエリを埋め込み、コサイン類似度で上位 k 件を取得する」)では、「Slack を買収した企業の創業者はどこで生まれましたか?」のようなマルチホップ質問に対応できません。正しい回答には、最も類似した単一の項目ではなく、推論パスに沿ったエンティティの取得が必要です。
GraphRAG と HippoRAG は、クエリ時にナレッジグラフ上で小規模な Personalized PageRank を実行すると、マルチホップ検索の精度を大幅に向上できることを示しました。hubmesh はこの手法を次の 2 つの点で拡張します。
- エンティティを基点としたシード設定と、複数要素によるランキング。 KG モードでは、PPR のシードはコーパスのグラフに照らして解決された質問自体のエンティティです(エイリアスインデックスを使用し、質問にエンティティが含まれない場合はコサイン類似度上位の結果に含まれるエンティティにフォールバックします)。kNN モードでは ANN の上位 k 件がシードになります。複数要素スコア(コサイン関連度、統合された PPR 質量、複数アンカーの収束度を min-max 正規化し、3:1:1 で統合)は、シードの選択ではなく、ドキュメントのランキングに適用されます。
- 予算を考慮したコンテキストのパッキング。 関連エンティティをスコアリングしたら、上位 k 件を単純に切り詰めるのではなく、網羅性と冗長性を明示的に制御しながら LLM のコンテキストウィンドウに詰め込みます。
この複数要素スコアリングのパターンは、SDN トポロジー最適化のための NNSI フレームワーク(Naidu et al., CCIS 2934, Springer, 2026)を、検索プランニング向けに応用したものです。
クイックスタート
インメモリ(テスト、小規模コーパス向け)
from hubmesh import Planner
from hubmesh.adapters import InMemoryStore
embed = ... # callable: text -> np.ndarray
docs = [...] # list of Document or strings or dicts
store = InMemoryStore.from_documents(docs, embed=embed)
planner = Planner(store=store, embed=embed)
result = planner.retrieve(query="...", top_k=10, budget_tokens=4000)
Qdrant アダプター(本番環境向け)
from hubmesh import Planner
from hubmesh.adapters import QdrantStore
store = QdrantStore.from_documents(docs) # in-memory
store = QdrantStore.from_documents(docs, path="./qdrant_data") # on-disk
store = QdrantStore.from_documents(docs, url="http://localhost:6333") # remote
planner = Planner(store=store, embed=embed)
result = planner.retrieve(query="...", top_k=10)
Chroma アダプター
from hubmesh.adapters import ChromaStore
store = ChromaStore.from_documents(docs) # ephemeral
store = ChromaStore.from_documents(docs, persist_directory="./chroma_data")
store = ChromaStore.from_documents(docs, host="localhost", port=8000)
マルチホップ/KG モード
from hubmesh.kg import build_entity_kg
import spacy
nlp = spacy.load("en_core_web_sm")
kg = build_entity_kg(docs, nlp=nlp)
planner = Planner(store=store, kg=kg, nlp=nlp, embed=embed) # embed= needed for text queries
result = planner.retrieve(query="Where was the founder of the company that bought Slack born?",
top_k=10, budget_tokens=4000)
# RetrievalResult includes reasoning paths showing why each doc was returned
for path in result.reasoning:
print(f" score={path.score:.3f} {' → '.join(path.node_ids)}")
LLM で抽出した KG(spaCy より高機能)
from hubmesh.kg_llm import build_entity_kg_llm
from hubmesh.entity_linker import EmbeddingLinker, make_st_embedder
def llm(prompt): # provider-agnostic — bring your own
return your_llm_call(prompt)
kg = build_entity_kg_llm(docs, llm=llm, cache_path="kg_cache.json")
# optional: cross-document entity dedup — same Linker protocol as the spaCy path
kg = build_entity_kg_llm(docs, llm=llm, cache_path="kg_cache.json",
linker=EmbeddingLinker(embed=make_st_embedder()),
llm_identity="gpt-5-mini") # namespaces the cache
planner = Planner(store=store, kg=kg, nlp=nlp, embed=embed)
エンティティリンクの改善
from hubmesh.kg import build_entity_kg
from hubmesh.entity_linker import EmbeddingLinker, make_st_embedder
# Cluster surface variations: "United States" / "U.S." / "USA" → one entity
linker = EmbeddingLinker(embed=make_st_embedder(), threshold=0.82)
kg = build_entity_kg(docs, linker=linker)
反復型マルチホップ:エージェントに操作を任せる
r1 = planner.retrieve(query=question, top_k=5)
# your agent reads r1, spots the bridge entity, then aims hop 2 at it:
r2 = planner.retrieve(
query=question, top_k=5,
seed_entities=["Nimbus Analytics"], # merged with the query's own seeds
exclude_docs=[s.doc.id for s in r1.sources], # don't re-retrieve consumed docs
)
シードとなる言及はエイリアスインデックスを通じて解決されるため、自由形式のエンティティ名を使用できます。クエリ処理は決定論的で、LLM を使用しません。プランニングの知能は呼び出し元にあります。
MCP サーバー:hubmesh をあらゆるエージェントに接続
pip install "hubmesh[mcp]"
python -m spacy download en_core_web_sm
{"mcpServers": {"hubmesh": {"command": "hubmesh-mcp"}}}
プランナーを、stdio 経由で決定論的なオペレーターツールとして公開します —
index_corpus、retrieve(上記のとおりシードで誘導可能)、resolve_entities、
entity_neighbors、path_between、get_document、graph_stats、
list_corpora。問題を解くのはエージェントです。質問を分解し、
各ホップを読み取り、次のホップを定めます。サーバーは LLM を一切呼び出さず、
ミリ秒単位で応答します。コーパスは ~/.hubmesh/corpora の
プレーンな JSON/NPZ として永続化されます。
サーバーは起動時に、モデルと永続化されたコーパスをバックグラウンドで ウォームアップします(初回実行時は約 5~10 秒)。そのため、ツール呼び出しは 最初から高速です。Perplexity など、厳しいタイムアウトが設定された コネクタークライアントで特に役立ちます。
ウェブベースのコネクタークライアントでは、ゲートウェイプロセスを 用意せずに SSE をネイティブで提供できます。
export HUBMESH_API_KEY="$(openssl rand -hex 24)" # any strong secret
hubmesh-mcp --transport sse --port 8000 --allow-tunnel
ngrok http 8000 # paste https://<your-url>/sse into the connector
トンネル経由での提供には API キーが必須です(キーがないとサーバーは起動しません)。
また、デフォルトでは読み取り専用です。index_corpus を有効にしたままにするには、
--allow-writes を指定します。クライアントは
Authorization: Bearer <key> を送信する必要があります。コネクタークライアントで
ヘッダーを設定できない場合、トンネルのエッジで呼び出し元を独自に認証する
必要があります(ngrok の OAuth/IP 制限トラフィックポリシー、Cloudflare Access など)。
その後に上流ヘッダーを追加してください。匿名トラフィックにヘッダーを付加すると、
すべての呼び出し元に完全な読み取りアクセスを与えることになります(読み取り専用で
防げるのはコーパスの置き換えであり、開示ではありません。get_document は
全文を返します)。ヘッダーを送信できず、認証機能のあるエッジの背後にも
配置できないクライアントは、プライベートコーパスには対応していません。
トンネル利用時の現場メモ(Perplexity との実運用連携に基づく):ngrok は動作します
(無料プランを含む)。cloudflared のクイックトンネルは SSE 本文をバッファリングし、
ツール呼び出しがハングします。また、ここでは supergateway は不要で、
再接続時にクラッシュします。--allow-tunnel を指定すると、トンネルから転送された
Host ヘッダーを受け入れます。指定しない場合、プロキシ経由のリクエストは
421 Misdirected Request になります。
セットアップ、エラーデコーダー、Perplexity で実施した 9/9 のテスト一式、 および推論モデルの挙動に関する 2 つの知見をまとめた完全なレポートは、 docs/perplexity.md をご覧ください。
長いドキュメントのチャンク分割
from hubmesh import chunk_by_sentences, chunk_documents
chunks = chunk_documents(
[{"id": "doc1", "text": long_text}, ...],
strategy="sentences", target_tokens=200,
)
# Then embed chunks and index normally
インストール
pip install hubmesh # core
pip install "hubmesh[qdrant]" # Qdrant adapter
pip install "hubmesh[chroma]" # Chroma adapter
pip install "hubmesh[kg]" # entity-linked KG (spaCy)
pip install "hubmesh[linker]" # embedding-based entity linker
pip install "hubmesh[all]" # everything
python -m spacy download en_core_web_sm # required for KG mode
設計
KG モード — ベンチマーク済みの本番運用向け経路:
query ─► spaCy NER ─► alias index ─► entity seeds ─► Personalized PageRank over the corpus KG
│ (fallback: entities of the top-3 cosine documents) │
└───────────► cosine similarity against every document ─────────────────────────────┤
▼
3·minmax(cosine) + 1·minmax(pooled PPR) + 1·minmax(per-anchor geomean) [weighted sum]
▼
budget-aware packing ─► context + sources + reasoning paths
kNN モード(KG なし、プロトタイピング向け):第 1 段階で ANN → 上限付きの誘導近接 サブグラフ → ANN シードからの PPR → 同じスコアリングとパッキング。 単一トピックの検索向けにコミュニティアンカリングも用意されていますが、デフォルトでは 無効です。
各レイヤーは個別にテストおよび置き換えが可能です。アダプターは既存の ベクトル DB をラップするため、移行する必要はありません。ただし、KG モードでは すべてのドキュメントをスコアリングします(ベクトルはストアのバージョンごとに 一度だけ収集され、キャッシュされます)。また、ストアの ANN インデックスは シードのフォールバックにのみ使用されます。
ベンチマーク
プールされた混同行段落コーパスにおける、根拠段落の再現率です。各行は個別の実験です。文書表現と埋め込みモデルによって絶対値は大きく変わるため、異なる表現間で行を比較することはありません。プロトコル、アブレーション、制限事項については BENCHMARKS.mdをご覧ください。
HotpotQA dev 全件(質問7,405件、プール段落66,581件)、 hubmesh と単純なコサイン類似度の比較、v0.4 のデフォルト設定:
| 表現 · 埋め込み | 単純 @10 | hubmesh @10 | Δ @10 | Δ @5 | Δ @2 |
|---|---|---|---|---|---|
| 本文のみ · MiniLM-L6 | 69.3% | 75.2% | +5.90 | +4.21 | −0.75 |
| タイトル+本文 · MiniLM-L6 | 70.0% | 77.3% | +7.24 | +5.88 | +0.25 |
| タイトル+本文 · bge-m3 | 83.5% | 84.8% | +1.38 | −1.41 | −9.09 |
両方の方向からご覧ください。小規模な埋め込みではグラフ層によって深い順位の再現率が5~7ポイント向上しますが、高性能な埋め込みでは深い順位での向上は+1.4に縮小し、デフォルト設定では上位順位の性能が低下します(recall@2で−9.1)。収束項は上位順位の適合率と深い順位の再現率をトレードオフします。高性能な埋め込みで上位2件/5件を対象とするワークロードでは、use_convergence=Falseまたは通常のコサイン類似度を使用し、グラフ層を全体に適用する前に、ご自身のワークロードで評価してください。
MuSiQue-Ans dev 全件(質問2,417件、MiniLM、本文のみ)、hubmesh と 単純な手法の比較、対応あり95%信頼区間付きのrecall@10: 全体で +3.67 [+3.00, +4.39](@2で+2.2、@5で+3.3)。ホップ数別では+2.9/+4.1/+5.3 (n = 1,252/760/405)。ホップ数が増えるほど向上幅は大きくなり、MuSiQueではhubmeshはrecall@2でも単純な手法を上回ります。
スコアリングによる効果(HotpotQA N=500、本文のみ、recall@10): 同じ グラフ、シード、フォールバック、パッカーを使った場合、コサイン融合スコアリングは、純粋な構造シグナル(PPRのみ)の0.676に対し0.871を達成します。 +19.5ポイント [+16.3, +22.7](MuSiQue N=300:+16.3)。以前のバージョンではHippoRAG形式のランキングとの比較で+29.8と記載していましたが、その比較ではパイプラインも変更されていたため、スコアリングへの寄与を示す値としては現在引用していません。
収束項(デフォルトで有効): MuSiQue dev全件で収束無効の設定より@10で+0.9ポイント、HotpotQA N=500で+1.1ポイント。単一の解決から得た同じ位置のログプール信号も、集計値では同等です。幾何平均では3ホップと4ホップで約1ポイントを維持します。複数シードのクエリではコストが約1.5~2倍になります(LLMトークンは引き続きゼロで、決定論的です)。
レイテンシ:7KノードのKGで、クエリあたり平均約22 ms/p95で26 ms(PPR行列のキャッシュ後)。収束を有効にした状態で、段落66K件のdev全件規模ではクエリあたり約3秒を測定しましたが、これはクエリごとのベクトル再収集を削除する前の測定です。この規模での再測定はまだ行っていません。
再現方法(各実行では、クエリごとの記録と、コミット、ダーティーフラグ、ソース/ハーネスのコンテンツハッシュを含むマニフェストを格納したJSONが書き出されます):
python benchmarks/run_hotpotqa.py --n 500 --kg --out hotpot.json
python benchmarks/run_musique.py --n 300 --kg --out musique.json
python benchmarks/run_ablation_coherence.py --dataset musique --n 2417
python benchmarks/profile_query.py # latency profile
ステータス
プレアルファ版(v0.4.2)。コアアルゴリズムを実装・検証済みです。インメモリ、Qdrant、Chroma用のアダプター、spaCy NERとLLMベースの抽出(どちらもリンク機能を考慮)に対応したエンティティリンク付きKG、エイリアスインデックスを利用したエンティティ解決、NNSI-KGスコアリング(複数ソースの収束はデフォルトで有効、ハブ割引PPRはオプトイン)、エージェント主導の反復型マルチホップ処理(seed_entities /
exclude_docs)、JSON/NPZコーパス永続化に対応したMCPオペレーターサーバー(hubmesh-mcp、ネイティブSSE)、文書のチャンク分割、推論経路の説明、PPRキャッシュによるレイテンシ最適化を備えています。Pinecone/pgvector/Weaviate用アダプターと、追加のマルチホップベンチマークは
初めての貢献に適したイシューとして管理されています。
謝辞
複数のコンポーネントを用いたスコアリングパターンは、以下で紹介された Network Node Significance Index(NNSI) フレームワークを応用したものです。
D. S. K. Naidu et al., "A Framework for Improving Network Topology Based on Graph Theory in Software-Defined Networking," in Internet Computing, Internet of Things, Artificial Intelligence, and Applications, Communications in Computer and Information Science, vol. 2934, H. R. Arabnia, L. Deligiannidis, K. Ferens, F. Ghareh Mohammadi, F. Shenavarmasouleh, and S. Amirian, Eds. Cham: Springer, 2026, pp. 3–18. doi: 10.1007/978-3-032-22190-2_1
@inproceedings{naidu2026nnsi,
author = {Naidu, Datta Sai Krishna and others},
title = {A Framework for Improving Network Topology Based on Graph Theory
in Software-Defined Networking},
booktitle = {Internet Computing, Internet of Things, Artificial Intelligence,
and Applications},
series = {Communications in Computer and Information Science},
volume = {2934},
editor = {Arabnia, Hamid R. and Deligiannidis, Leonidas and Ferens, Ken and
Ghareh Mohammadi, Farid and Shenavarmasouleh, Farzan and
Amirian, Soheyla},
pages = {3--18},
publisher = {Springer},
address = {Cham},
year = {2026},
doi = {10.1007/978-3-032-22190-2_1},
isbn = {978-3-032-22189-6}
}
ここでは、NNSIをSDNのトポロジー最適化から検索計画に転用しています。エンティティがリンクされたKG上での検索への適用は、本研究で新たに取り組むものです。
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。