Intégration LlamaIndex
Laya fournit des composants de décision non autorégressifs sous 35 ms pour les pipelines RAG
LlamaIndex, RouterQueryEngine et la sélection d’outils (latence sur une seule question mesurée à
32.8 ms avec laya-multilingual et 39.5 ms avec laya sur un GPU Tesla T4 ; 193–464 ms sur
CPU) :
LayaSingleSelector: sélecteur à choix unique sous 35 ms remplaçantLLMSingleSelectorpourRouterQueryEngine.LayaMultiSelector: sélecteur multi-choix remplaçantLLMMultiSelectorpour les requêtes composites couvrant plusieurs sources de données.LayaQueryRouter: dispatcheur de requêtes autonome routant les requêtes entrantes directement vers des moteurs de requête ou des appelables cibles.
Prend en charge l’inférence locale en processus (Agent ou Router) et l’inférence HTTP distante
contre ta propre instance laya-serve sans exiger PyTorch sur les clients en périphérie.
Installation
pip install "laya[llamaindex]"
1. Routage à choix unique avec RouterQueryEngine
Dans LlamaIndex, RouterQueryEngine utilise un sélecteur pour décider quel moteur de requête ou outil
sous-jacent doit répondre à une question. Les sélecteurs LLM autorégressifs (LLMSingleSelector)
prennent 1 000–2 000 ms à générer du texte. LayaSingleSelector évalue les outils candidats en
~33 ms sans génération de jetons :
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. Sélection multi-choix pour les requêtes composites
Pour les requêtes qui exigent une synthèse entre plusieurs index (par exemple comparer des spécifications
de documentation avec des enregistrements de base de données transactionnelle), LayaMultiSelector
évalue la pertinence des candidats et renvoie plusieurs outils sélectionnés :
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. Dispatch direct de requêtes avec LayaQueryRouter
Pour un routage direct sans la surcharge de RouterQueryEngine, LayaQueryRouter route les requêtes
directement vers des moteurs enregistrés dans un dictionnaire :
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)
Le query() synchrone et l’aquery() asynchrone sont tous deux pris en charge.
4. Gating par seuil de confiance
Comme l’intégration LangChain de Laya, LayaSingleSelector et LayaQueryRouter lisent
l’answer_confidence calibrée (max(p)) :
- Fallback automatique : spécifie
fallback_index(oufallback_key) pour détourner sans heurt les requêtes incertaines vers un moteur par défaut sûr. - Garde stricte : mets
raise_on_low_confidence=TruesurLayaSingleSelectorpour leverLayaLowConfidenceErrorquand l’entrée est ambiguë, ce qui permet l’escalade par l’appelant.
5. Déploiements HTTP distants
Pour le RAG serverless, les environnements en périphérie, ou les environnements sans GPU local :
from laya.integrations.llamaindex import LayaSingleSelector
selector = LayaSingleSelector(
base_url="http://laya-serve.internal:8080",
confidence_threshold=0.85,
fallback_index=0,
)
Le client distant utilise urllib de la bibliothèque standard de Python sans aucune dépendance lourde,
ce qui empêche la transmission cross-origin d’identifiants et correspond à la spécification
/v1/systemone.
6. Contrôles de décision par appel
LayaSingleSelector, LayaMultiSelector et LayaQueryRouter prennent les mêmes arguments par appel que
l’API du cœur : les deux budgets de jetons (max_len, head_max_len), les contrôles de langue et d’abstention (lang, min_confidence), et les cinq arguments de hook de
prédiction (hooks, on_predict_start, on_predict_end, hooks_raise, hooks_timeout). Ils sont par
sélecteur, donc une étape de routage large peut avoir de la place pendant que le reste du pipeline garde
les défauts du checkpoint.
Les options d’une question choice partagent le budget d’options du checkpoint – head_max_len, 192
jetons sur laya – et chaque candidat contribue son nom et sa description, donc au-delà d’environ 20
outils les descriptions commencent à atteindre le modèle comme le même texte.
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
Mesuré sur laya (Apple silicon, une passe avant par requête, évalué sur l’outil choisi) avec un
effectif de 59 outils construit à partir des libellés d’intention MASSIVE anglais et un énoncé par
libellé, donc la vérité terrain est exacte. Chaque cellule est combien des 59 requêtes ont atteint leur
propre outil ; les deux répétitions ont donné le même compte.
| Effectif de 59 outils | Budget par défaut | max_len=1024, head_max_len=384 |
…, head_max_len=512 |
|---|---|---|---|
| Requêtes sur leur propre outil | 2/59 | 8/59 | 15/59 |
| Médiane ms par requête | 160 | 172 | 184 |
L’exactitude absolue n’est pas ce qui est affirmé ici : le checkpoint n’est pas un classifieur MASSIVE, et 59 libellés similaires forment une forme de stress. Ce qui est affirmé, c’est la direction et le prix – un effectif que le budget par défaut effondre presque à néant est lisible, et à cette taille la fenêtre coûte peu de temps. Avec moins d’environ 20 options, les libellés tiennent déjà et élargir peut déplacer les réponses dans le mauvais sens, c’est pourquoi les deux arguments sont opt-in par sélecteur. Voir l’intégration LangChain pour cette falaise mesurée.
Les hooks ne tournent que sur le chemin local. Un sélecteur avec un base_url et hooks=[...] lève
ValueError plutôt que de signaler un succès dont le cache n’a jamais tourné – un hook est un appelable
Python qui s’exécute à l’intérieur de predict, et aucun format de transmission ne le porte. Installe les
hooks dans le processus qui exécute l’inférence. Les deux budgets voyagent bien vers un nœud distant, dans
le corps de la requête, jusqu’à son plafond LAYA_MAX_TOKEN_BUDGET ; une valeur plus grande revient en
422.
Langue et abstention
lang fixe la langue dans laquelle la requête est routée et reçoit sa réponse – il sélectionne la calibration par langue du checkpoint qui répond plutôt que de s’appuyer sur la détection intégrée – et min_confidence est la porte d’abstention du cœur : une décision en dessous revient comme une abstention plutôt qu’une sélection forcée. Les deux sont lus indifféremment par Agent.predict et Router.predict et acceptés par laya-serve dans le corps de la requête, donc un sélecteur les transmet sur le chemin local comme sur le chemin distant. Celui qui n’est pas défini est omis, et non envoyé comme None, afin qu’il ne puisse pas éclipser la valeur par défaut du déploiement lui-même ; min_confidence=0.0 et lang="" sont de vraies valeurs et sont transmis tels quels.
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
)