LlamaIndex-Integration
Laya bietet nicht-autoregressive Entscheidungskomponenten unter 35 ms für LlamaIndex-RAG-Pipelines, RouterQueryEngine und Werkzeugauswahl (Latenz pro Frage gemessen bei 32.8 ms mit laya-multilingual und 39.5 ms mit laya auf einer Tesla T4 GPU; 193–464 ms auf der CPU):
LayaSingleSelector: Single-Choice-Selector unter 35 ms, derLLMSingleSelectorfürRouterQueryEngineersetzt.LayaMultiSelector: Multi-Choice-Selector, derLLMMultiSelectorfür zusammengesetzte Abfragen über mehrere Datenquellen hinweg ersetzt.LayaQueryRouter: Eigenständiger Query-Dispatcher, der eingehende Anfragen direkt an Ziel-Query-Engines oder Callables routet.
Unterstützt sowohl lokale In-Process-Inferenz (Agent oder Router) als auch Remote-HTTP-Inferenz gegen deine eigene laya-serve-Instanz, ohne PyTorch auf Edge-Clients zu erfordern.
Installation
pip install "laya[llamaindex]"
1. Single-Choice-Routing mit RouterQueryEngine
In LlamaIndex verwendet RouterQueryEngine einen Selector, um zu entscheiden, welche zugrunde liegende Query-Engine oder welches Werkzeug eine Frage beantworten soll. Autoregressive LLM-Selectors (LLMSingleSelector) brauchen 1,000–2,000 ms, um Text zu generieren. LayaSingleSelector bewertet Kandidatenwerkzeuge in ~33 ms ohne Token-Generierung:
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. Multi-Choice-Auswahl für zusammengesetzte Abfragen
Für Abfragen, die eine Synthese über mehrere Indizes erfordern (z. B. den Vergleich von Dokumentations-Spezifikationen mit transaktionalen Datenbankeinträgen), bewertet LayaMultiSelector die Relevanz der Kandidaten und gibt mehrere ausgewählte Werkzeuge zurück:
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. Direkter Query-Dispatch mit LayaQueryRouter
Für direktes Routing ohne den Overhead von RouterQueryEngine routet LayaQueryRouter Abfragen direkt an im Dictionary registrierte Engines:
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)
Sowohl das synchrone query() als auch das asynchrone aquery() werden unterstützt.
4. Gating auf den Konfidenzschwellenwert
Wie Layas LangChain-Integration lesen LayaSingleSelector und LayaQueryRouter die kalibrierte answer_confidence (max(p)):
- Automatischer Fallback: Gib
fallback_index(oderfallback_key) an, um unsichere Abfragen nahtlos an eine sichere Standard-Engine umzuleiten. - Strikte Absicherung: Setze
raise_on_low_confidence=TrueaufLayaSingleSelector, umLayaLowConfidenceErrorauszulösen, wenn die Eingabe mehrdeutig ist, und so die Eskalation durch den Aufrufer zu ermöglichen.
5. Remote-HTTP-Deployments
Für serverloses RAG, Edge-Umgebungen oder Umgebungen ohne lokale GPUs:
from laya.integrations.llamaindex import LayaSingleSelector
selector = LayaSingleSelector(
base_url="http://laya-serve.internal:8080",
confidence_threshold=0.85,
fallback_index=0,
)
Der Remote-Client verwendet Pythons Standardbibliothek urllib ohne schwere Abhängigkeiten, was die Weiterleitung von Cross-Origin-Anmeldedaten verhindert und der Spezifikation von /v1/systemone entspricht.
6. Entscheidungskontrollen pro Aufruf
LayaSingleSelector, LayaMultiSelector und LayaQueryRouter nehmen dieselben Argumente pro Aufruf wie die Kern-API: die beiden Token-Budgets (max_len, head_max_len), die Sprach- und Enthaltungskontrollen (lang, min_confidence), und die fünf Prediction-Hook-Argumente (hooks, on_predict_start, on_predict_end, hooks_raise, hooks_timeout). Sie gelten pro Selector, sodass einem breiten Routing-Schritt Raum gegeben werden kann, während der Rest der Pipeline die Standardwerte des Checkpoints behält.
Die Optionen einer choice-Frage teilen sich das Option-Budget des Checkpoints – head_max_len, 192 Token auf laya – und jeder Kandidat trägt seinen Namen und seine Beschreibung bei, sodass ab etwa 20 Werkzeugen die Beschreibungen das Modell als derselbe Text erreichen.
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
Gemessen auf laya (Apple Silicon, ein Vorwärtspass pro Abfrage, bewertet auf dem gewählten Werkzeug) mit einer 59-Werkzeug-Aufstellung, die aus den englischen Intent-Labels von MASSIVE und einer Äußerung pro Label gebaut wurde, sodass die Ground Truth exakt ist. Jede Zelle gibt an, wie viele der 59 Abfragen ihr eigenes Werkzeug erreichten; beide Wiederholungen ergaben dieselbe Zählung.
| 59-Werkzeug-Aufstellung | Standard-Budget | max_len=1024, head_max_len=384 |
…, head_max_len=512 |
|---|---|---|---|
| Abfragen auf ihrem eigenen Werkzeug | 2/59 | 8/59 | 15/59 |
| Median ms pro Abfrage | 160 | 172 | 184 |
Die absolute Genauigkeit ist hier nicht die Aussage: Der Checkpoint ist kein MASSIVE-Klassifikator, und 59 ähnliche Labels sind eine Stressform. Die Aussage ist die Richtung und der Preis – eine Aufstellung, die das Standard-Budget auf nahezu null kollabieren lässt, ist lesbar, und bei dieser Größe kostet das Fenster wenig Zeit. Mit weniger als etwa 20 Optionen passen die Labels bereits und das Erweitern kann Antworten in die falsche Richtung bewegen, weshalb beide Argumente pro Selector opt-in sind. Siehe die LangChain-Integration für diese gemessene Klippe.
Hooks laufen nur auf dem lokalen Pfad. Ein Selector mit einem base_url und hooks=[...] löst ValueError aus, statt einen Erfolg zu melden, dessen Cache nie lief – ein Hook ist ein Python-Callable, der innerhalb von predict läuft, und kein Wire-Format trägt ihn. Installiere Hooks in dem Prozess, der die Inferenz ausführt. Die beiden Budgets reisen aber zu einem Remote-Knoten, im Request-Body, bis zu dessen LAYA_MAX_TOKEN_BUDGET-Obergrenze; ein größerer Wert kommt als 422 zurück.
Sprache und Enthaltung
lang pinnt die Sprache, in der die Anfrage geroutet und beantwortet wird – es wählt die sprachspezifische Kalibrierung des antwortenden Checkpoints, statt sich auf die eingebaute Erkennung zu verlassen – und min_confidence ist das Enthaltungs-Gate des Kerns: Eine Entscheidung darunter kommt als Enthaltung zurück statt als erzwungene Auswahl. Beide werden von Agent.predict und Router.predict gleichermaßen gelesen und von laya-serve im Request-Body akzeptiert, sodass ein Selector sie auf dem lokalen und dem Remote-Pfad weiterreicht. Ein nicht gesetztes wird weggelassen, nicht als None gesendet, sodass es den eigenen Standard des Deployments nicht überschatten kann; min_confidence=0.0 und lang="" sind echte Werte und werden so weitergegeben, wie sie sind.
selector = LayaSingleSelector(
instructions="Which tool or query engine is best suited to answer this query?",
lang="de", # answer German queries in German
min_confidence=0.3, # abstain when no tool clears a 0.3 confidence
)