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 で返ります。