Интеграция с LlamaIndex
Laya предоставляет неавторегрессионные компоненты принятия решений с задержкой менее 35 мс для RAG-конвейеров LlamaIndex, RouterQueryEngine и выбора инструментов (задержка на один вопрос — 32.8 мс с laya-multilingual и 39.5 мс с laya на GPU Tesla T4; 193–464 мс на CPU):
LayaSingleSelector: селектор одного варианта с задержкой менее 35 мс, заменяющийLLMSingleSelectorдляRouterQueryEngine.LayaMultiSelector: селектор нескольких вариантов, заменяющийLLMMultiSelectorдля составных запросов, охватывающих несколько источников данных.LayaQueryRouter: автономный диспетчер запросов, направляющий входящие запросы напрямую в целевые движки запросов или callables.
Поддерживает как локальный инференс в процессе (Agent или Router), так и удалённый инференс по HTTP к вашему собственному экземпляру laya-serve, без необходимости в PyTorch на периферийных клиентах.
Установка
pip install "laya[llamaindex]"
1. Маршрутизация одного варианта с RouterQueryEngine
В LlamaIndex RouterQueryEngine использует селектор, чтобы решить, какой нижележащий движок запросов или инструмент должен ответить на вопрос. Авторегрессионные LLM-селекторы (LLMSingleSelector) тратят 1,000–2,000 мс на генерацию текста. LayaSingleSelector оценивает инструменты-кандидаты за ~33 мс, без генерации токенов:
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. Выбор нескольких вариантов для составных запросов
Для запросов, требующих синтеза данных из нескольких индексов (например, сравнения спецификаций документации с записями транзакционной базы данных), LayaMultiSelector оценивает релевантность кандидатов и возвращает несколько выбранных инструментов:
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. Прямая отправка запросов с LayaQueryRouter
Для прямой маршрутизации без накладных расходов RouterQueryEngine LayaQueryRouter направляет запросы напрямую в движки, зарегистрированные в словаре:
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)
Поддерживаются как синхронный query(), так и асинхронный aquery().
4. Gating по порогу уверенности
Как и интеграция Laya с LangChain, LayaSingleSelector и LayaQueryRouter читают откалиброванную answer_confidence (max(p)):
- Автоматический резервный вариант: укажите
fallback_index(илиfallback_key), чтобы плавно перенаправлять неуверенные запросы на безопасный движок по умолчанию. - Строгая защита: задайте
raise_on_low_confidence=TrueвLayaSingleSelector, чтобы вызыватьLayaLowConfidenceError, когда входные данные неоднозначны, — это позволяет вызывающей стороне выполнить эскалацию.
5. Удалённые развёртывания по HTTP
Для бессерверного RAG, периферийных сред или сред без локальных GPU:
from laya.integrations.llamaindex import LayaSingleSelector
selector = LayaSingleSelector(
base_url="http://laya-serve.internal:8080",
confidence_threshold=0.85,
fallback_index=0,
)
Удалённый клиент использует стандартную библиотеку Python urllib без тяжёлых зависимостей, что предотвращает пересылку учётных данных между источниками и соответствует спецификации /v1/systemone.
6. Управление решением на каждый вызов
LayaSingleSelector, LayaMultiSelector и LayaQueryRouter принимают те же аргументы на каждый вызов, что и
базовый API: два бюджета токенов (max_len, head_max_len), управление языком и воздержанием (lang, min_confidence), и пять аргументов хуков
предсказаний (hooks, on_predict_start, on_predict_end, hooks_raise, hooks_timeout). Они задаются
для каждого селектора отдельно, поэтому широкому шагу маршрутизации можно дать запас, пока остальной
конвейер сохраняет значения по умолчанию чекпойнта.
Варианты choice-вопроса делят бюджет вариантов чекпойнта — head_max_len, 192
токена в laya — и каждый кандидат вносит своё имя и описание, поэтому примерно после 20 инструментов
описания начинают доходить до модели как один и тот же текст.
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
Измерено на laya (Apple silicon, один прямой проход на запрос, оценка по выбранному инструменту)
с набором из 59 инструментов, построенным из английских меток интентов MASSIVE и одной реплики на
метку, поэтому эталонная истина точна. Каждая ячейка показывает, сколько из 59 запросов
попали в свой собственный инструмент; оба повтора дали одинаковый результат.
| Набор из 59 инструментов | Бюджет по умолчанию | max_len=1024, head_max_len=384 |
…, head_max_len=512 |
|---|---|---|---|
| Запросы на своём собственном инструменте | 2/59 | 8/59 | 15/59 |
| Медиана мс на запрос | 160 | 172 | 184 |
Абсолютная точность здесь не является утверждением: чекпойнт — не классификатор MASSIVE, а 59 похожих меток — это стрессовая форма. Утверждение — это направление и цена: набор, который бюджет по умолчанию сводит почти к нулю, становится читаемым, и при таком размере окно стоит мало времени. При менее чем примерно 20 вариантах метки уже помещаются, и расширение окна может сдвинуть ответы в неверную сторону, поэтому оба аргумента включаются по выбору для каждого селектора. См. интеграцию с LangChain, чтобы увидеть этот измеренный обрыв.
Хуки выполняются только на локальном пути. Селектор с base_url и hooks=[...] вызывает
ValueError, а не сообщает об успехе, кэш которого так и не выполнился, — хук это Python callable,
который выполняется внутри predict, и никакой формат передачи его не переносит. Устанавливайте хуки
в процессе, который выполняет инференс. Два бюджета действительно доходят до удалённого узла, в теле
запроса, до его потолка LAYA_MAX_TOKEN_BUDGET; большее значение возвращается как 422.
Язык и воздержание
lang фиксирует язык, на котором запрос маршрутизируется и получает ответ – он выбирает языковую калибровку отвечающего чекпойнта вместо того, чтобы полагаться на встроенное определение – а min_confidence — это гейт воздержания ядра: решение ниже него возвращается как воздержание, а не как принудительный выбор. Оба одинаково читаются Agent.predict и Router.predict и принимаются laya-serve в теле запроса, поэтому селектор передаёт их и на локальном, и на удалённом пути. Не заданное значение опускается, а не отправляется как None, так что оно не может заслонить собственное значение по умолчанию развёртывания; min_confidence=0.0 и lang="" — это реальные значения, и они передаются как есть.
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
)