Documentación

Integración con LlamaIndex

Laya ofrece componentes de decisión no autorregresivos por debajo de 35 ms para canalizaciones RAG de LlamaIndex, RouterQueryEngine y la selección de herramientas (latencia de una sola pregunta medida en 32.8 ms con laya-multilingual y 39.5 ms con laya en una GPU Tesla T4; 193–464 ms en CPU):

  • LayaSingleSelector: Selector de opción única por debajo de 35 ms que reemplaza a LLMSingleSelector para RouterQueryEngine.
  • LayaMultiSelector: Selector de opción múltiple que reemplaza a LLMMultiSelector para consultas compuestas que abarcan varias fuentes de datos.
  • LayaQueryRouter: Despachador de consultas independiente que enruta las solicitudes entrantes directamente a los motores de consulta o callables de destino.

Admite tanto la inferencia local en proceso (Agent o Router) como la inferencia remota por HTTP contra tu propia instancia de laya-serve, sin necesidad de PyTorch en los clientes de borde.


Instalación

pip install "laya[llamaindex]"

1. Enrutamiento de opción única con RouterQueryEngine

En LlamaIndex, RouterQueryEngine usa un selector para decidir qué motor de consulta o herramienta subyacente debe responder una pregunta. Los selectores LLM autorregresivos (LLMSingleSelector) tardan 1,000–2,000 ms en generar texto. LayaSingleSelector evalúa las herramientas candidatas en ~33 ms, sin generación de tokens:

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. Selección de opción múltiple para consultas compuestas

Para consultas que requieren sintetizar información de varios índices (por ejemplo, comparar especificaciones de la documentación con registros de una base de datos transaccional), LayaMultiSelector evalúa la relevancia de los candidatos y devuelve varias herramientas seleccionadas:

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. Despacho directo de consultas con LayaQueryRouter

Para el enrutamiento directo sin la sobrecarga de RouterQueryEngine, LayaQueryRouter enruta las consultas directamente a motores registrados en un diccionario:

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)

Se admiten tanto query() sincrónico como aquery() asincrónico.


4. Gating por umbral de confianza

Al igual que la integración de Laya con LangChain, LayaSingleSelector y LayaQueryRouter leen answer_confidence calibrada (max(p)):

  • Fallback automático: Especifica fallback_index (o fallback_key) para desviar sin problemas las consultas dudosas a un motor predeterminado seguro.
  • Vigilancia estricta: Define raise_on_low_confidence=True en LayaSingleSelector para lanzar LayaLowConfidenceError cuando la entrada es ambigua, lo que permite el escalado por parte de quien llama.

5. Despliegues remotos por HTTP

Para RAG sin servidor, entornos de borde o entornos sin GPU locales:

from laya.integrations.llamaindex import LayaSingleSelector

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

El cliente remoto usa la biblioteca estándar de Python urllib, sin dependencias pesadas, lo que evita el reenvío de credenciales entre orígenes y se ajusta a la especificación de /v1/systemone.


6. Controles de decisión por llamada

LayaSingleSelector, LayaMultiSelector y LayaQueryRouter aceptan los mismos argumentos por llamada que la API del núcleo: los dos presupuestos de tokens (max_len, head_max_len), los controles de idioma y abstención (lang, min_confidence), y los cinco argumentos de hooks de predicción (hooks, on_predict_start, on_predict_end, hooks_raise, hooks_timeout). Son por selector, así que a un paso de enrutamiento amplio se le puede dar más espacio mientras el resto de la canalización conserva los valores predeterminados del checkpoint.

Las opciones de una pregunta choice comparten el presupuesto de opciones del checkpoint — head_max_len, 192 tokens en laya — y cada candidato aporta su nombre y su descripción, así que a partir de unas 20 herramientas las descripciones empiezan a llegar al modelo como el mismo texto.

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

Medido en laya (silicio de Apple, una pasada hacia adelante por consulta, puntuado sobre la herramienta elegida) con una plantilla de 59 herramientas construida a partir de las etiquetas de intención en inglés de MASSIVE y un enunciado por etiqueta, de modo que la verdad de referencia es exacta. Cada celda indica cuántas de las 59 consultas llegaron a su propia herramienta; ambas repeticiones dieron el mismo recuento.

Plantilla de 59 herramientas Presupuesto predeterminado max_len=1024, head_max_len=384 …, head_max_len=512
Consultas asignadas a su propia herramienta 2/59 8/59 15/59
ms de mediana por consulta 160 172 184

La precisión absoluta no es lo que se afirma aquí: el checkpoint no es un clasificador de MASSIVE, y 59 etiquetas similares son una forma de estrés. Lo que se afirma es la dirección y el precio — una plantilla que el presupuesto predeterminado reduce a casi nada se puede leer, y a este tamaño la ventana cuesta poco tiempo. Con menos de unas 20 opciones las etiquetas ya caben y ampliar la ventana puede mover las respuestas en la dirección equivocada, por eso ambos argumentos se habilitan por selector. Consulta la integración con LangChain para ver ese acantilado medido.

Los hooks solo se ejecutan en la ruta local. Un selector con un base_url y hooks=[...] lanza ValueError en lugar de informar un éxito cuya caché nunca se ejecutó — un hook es un callable de Python que se ejecuta dentro de predict, y ningún formato de transmisión lo incluye. Instala los hooks en el proceso que ejecuta la inferencia. Los dos presupuestos sí viajan a un nodo remoto, en el cuerpo de la solicitud, hasta su límite de LAYA_MAX_TOKEN_BUDGET; un valor mayor se devuelve como un 422.

Idioma y abstención

lang fija el idioma en el que se enruta y se responde la consulta – selecciona la calibración por idioma del checkpoint que responde en lugar de depender de la detección integrada – y min_confidence es la puerta de abstención del núcleo: una decisión por debajo de ella vuelve como una abstención en lugar de una selección forzada. Ambos los leen por igual Agent.predict y Router.predict y los acepta laya-serve en el cuerpo de la solicitud, así que un selector los reenvía tanto en la ruta local como en la remota. El que no esté definido se omite, no se envía como None, así que no puede eclipsar el valor predeterminado del propio despliegue; min_confidence=0.0 y lang="" son valores reales y se reenvían tal cual.

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
)