ドキュメント

LlamaIndex 連携

LlamaIndex 連携

Laya は LlamaIndex の RAG パイプライン、RouterQueryEngine、ツール選択に、35ms 未満の非自己回帰型の意思決定コンポーネントを提供します(単一質問のレイテンシは Tesla T4 GPU で laya-multilingual が 32.8 ms、laya が 39.5 ms。CPU では 193〜464 ms)。

  • LayaSingleSelector:RouterQueryEngine 用に LLMSingleSelector を置き換える、35ms 未満の単一選択セレクタ。
  • LayaMultiSelector:複数のデータソースにまたがる複合クエリ用に LLMMultiSelector を置き換える複数選択セレクタ。
  • LayaQueryRouter:受信リクエストを対象のクエリエンジンや callable へ直接ルーティングする、単体のクエリディスパッチャ。

ローカルのインプロセス推論(Agent または Router)と、自前の laya-serve インスタンスに対するリモート HTTP 推論の両方をサポートし、エッジクライアントに PyTorch を必要としません。


インストール

pip install "laya[llamaindex]"

1. RouterQueryEngine による単一選択ルーティング

LlamaIndex では RouterQueryEngine がセレクタを使って、どの下位のクエリエンジンやツールが質問に答えるべきかを決めます。自己回帰型の LLM セレクタ(LLMSingleSelector)はテキスト生成に 1,000〜2,000 ms かかります。LayaSingleSelector はトークン生成なしで候補ツールを 約 33 ms で評価します。

from llama_index.core.query_engine import RouterQueryEngine
from llama_index.core.tools import QueryEngineTool, ToolMetadata
from laya.integrations.llamaindex import LayaSingleSelector

# Define query engine tools
docs_tool = QueryEngineTool(
    query_engine=vector_index.as_query_engine(),
    metadata=ToolMetadata(
        name="vector_documentation",
        description="Semantic search over technical user documentation and API guides.",
    ),
)
sql_tool = QueryEngineTool(
    query_engine=sql_index.as_query_engine(),
    metadata=ToolMetadata(
        name="sql_database",
        description="Structured SQL database containing customer accounts, billing, and orders.",
    ),
)

# Initialize Laya sub-35ms selector with confidence fallback
selector = LayaSingleSelector(
    confidence_threshold=0.80,   # If confidence < 0.80, fall back to index 0
    fallback_index=0,
)

router_engine = RouterQueryEngine(
    selector=selector,
    query_engine_tools=[docs_tool, sql_tool],
)

response = router_engine.query("What is the shipping address for order #4912?")
print(response)

2. 複合クエリ向けの複数選択

複数のインデックスにまたがる統合を必要とするクエリ(たとえばドキュメントの仕様とトランザクションのデータベース記録を比較するもの)では、LayaMultiSelector が候補の関連性を評価し、複数の選択されたツールを返します。

from laya.integrations.llamaindex import LayaMultiSelector

multi_selector = LayaMultiSelector(
    probability_threshold=0.25,  # Select all tools with probability >= 0.25
    max_outputs=2,
)

tools = [docs_tool.metadata, sql_tool.metadata, summary_tool.metadata]
result = multi_selector.select(
    tools,
    "How does the database security policy compare with our published compliance guide?"
)

for sel in result.selections:
    print(f"Tool: {tools[sel.index].name} | {sel.reason}")

3. LayaQueryRouter による直接クエリディスパッチ

RouterQueryEngine のオーバーヘッドなしで直接ルーティングしたい場合、LayaQueryRouter はクエリを辞書登録されたエンジンへ直接ルーティングします。

from laya.integrations.llamaindex import LayaQueryRouter

router = LayaQueryRouter(
    query_engines={
        "vector": vector_query_engine,
        "sql": sql_query_engine,
        "summary": summary_query_engine,
    },
    descriptions={
        "vector": "Semantic search over product documentation and guides",
        "sql": "Structured SQL queries for user accounts and transactions",
        "summary": "Quarterly reports and high-level business summaries",
    },
    confidence_threshold=0.75,
    fallback_key="vector",
)

# Route and execute in one call:
response = router.query("How many active subscriptions were renewed in Q3?")
print(response)

同期の query() と非同期の aquery() の両方をサポートします。


4. 信頼度しきい値によるゲート

Laya の LangChain 連携と同様、LayaSingleSelector と LayaQueryRouter はキャリブレーション済みの answer_confidence(max(p))を読みます。

  • 自動フォールバック: fallback_index(または fallback_key)を指定すると、不確かなクエリを安全な既定エンジンへシームレスに迂回させます。
  • 厳格なガード: LayaSingleSelector で raise_on_low_confidence=True を設定すると、入力が曖昧なときに LayaLowConfidenceError を投げ、呼び出し元がエスカレーションできます。

5. リモート HTTP デプロイ

サーバーレス RAG、エッジ環境、ローカル GPU のない環境向け:

from laya.integrations.llamaindex import LayaSingleSelector

selector = LayaSingleSelector(
    base_url="http://laya-serve.internal:8080",
    confidence_threshold=0.85,
    fallback_index=0,
)

リモートクライアントは Python 標準ライブラリの urllib を重い依存関係なしで使い、クロスオリジンの資格情報転送を防ぎ、/v1/systemone の仕様に一致します。


6. 呼び出しごとの意思決定制御

LayaSingleSelector、LayaMultiSelector、LayaQueryRouter は、コア API と同じ呼び出しごとの引数を取ります。2 つのトークン予算(max_len、head_max_len)と 5 つの予測フック引数(hooks、on_predict_start、on_predict_end、hooks_raise、hooks_timeout)です。これらはセレクタごとなので、広いルーティングステップに余地を与えつつ、パイプラインの残りはチェックポイントの既定を保てます。

choice の質問の選択肢はチェックポイントの選択肢予算 —— head_max_len、laya では 192 トークン —— を共有し、各候補が名前と説明を寄与するので、およそ 20 ツールを超えると説明が同じテキストとしてモデルに届き始めます。

selector = LayaSingleSelector(
    instructions="Which tool or query engine is best suited to answer this query?",
    max_len=1024,          # total window
    head_max_len=512,      # tokens shared by the option prompt
)
result = selector.select(tools, query)     # tools: 59 descriptions

laya(Apple silicon、クエリあたり 1 回のフォワードパス、選ばれたツールで採点)で、MASSIVE の en 意図ラベルとラベルごとの 1 発話から作った 59 ツールの名簿で実測しました。正解は正確です。各セルは 59 クエリのうち自分のツールに到達した数で、どちらの繰り返しも同じ数でした。

59 ツールの名簿 既定予算 max_len=1024, head_max_len=384 …, head_max_len=512
自分のツールに到達したクエリ 2/59 8/59 15/59
クエリあたりの中央値 ms 160 172 184

ここでの主張は絶対精度ではありません。このチェックポイントは MASSIVE の分類器ではなく、59 個の似たラベルはストレス形状です。主張は方向と代償です。既定予算ではほぼ何も読めなくなる名簿が読めるようになり、この規模では窓がかかる時間はわずかです。およそ 20 未満の選択肢ではラベルはすでに収まっており、広げると答えが悪い方向へ動きえます。だから両方の引数はセレクタごとのオプトインなのです。その実測された崖は LangChain 連携を参照してください。

フックはローカル経路でのみ走ります。 base_url と hooks=[...] を持つセレクタは、キャッシュが決して走らなかった成功を報告するのではなく ValueError を投げます。フックは predict の内部で走る Python の callable で、それを運ぶワイヤ形式はありません。フックは推論を実行するプロセスにインストールしてください。2 つの予算はリモートノードへリクエストボディで伝わり、その LAYA_MAX_TOKEN_BUDGET の上限まで適用されます。より大きい値は 422 で返ります。