Documentation

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çant LLMSingleSelector pour RouterQueryEngine.
  • LayaMultiSelector : sélecteur multi-choix remplaçant LLMMultiSelector pour 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 (ou fallback_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=True sur LayaSingleSelector pour lever LayaLowConfidenceError quand 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
)