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 aLLMSingleSelectorparaRouterQueryEngine.LayaMultiSelector: Selector de opción múltiple que reemplaza aLLMMultiSelectorpara 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(ofallback_key) para desviar sin problemas las consultas dudosas a un motor predeterminado seguro. - Vigilancia estricta: Define
raise_on_low_confidence=TrueenLayaSingleSelectorpara lanzarLayaLowConfidenceErrorcuando 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
)