LlamaIndex 整合
Laya 為 LlamaIndex 的 RAG 流水線、RouterQueryEngine 和工具選擇提供低於 35ms 的非自迴歸
決策元件(單問題延遲:Tesla T4 GPU 上用 laya-multilingual 測得 32.8 ms,用 laya 測得
39.5 ms;CPU 上為 193–464 ms):
LayaSingleSelector:低於 35ms 的單選選擇器,替代RouterQueryEngine的LLMSingleSelector。LayaMultiSelector:多選選擇器,替代LLMMultiSelector,用於橫跨多個數據源的複合查詢。LayaQueryRouter:獨立的查詢分發器,把進來的請求直接路由到目標查詢引擎或可呼叫物件。
同時支援本地程序內推理(Agent 或 Router)和遠端 HTTP 推理(對接你自己的
laya-serve 例項),邊緣客戶端不需要裝 PyTorch。
安裝
pip install "laya[llamaindex]"
1. 用 RouterQueryEngine 做單選路由
在 LlamaIndex 裡,RouterQueryEngine 用一個選擇器決定該由哪個底層查詢引擎或工具來回答
問題。自迴歸的 LLM 選擇器(LLMSingleSelector)要花 1,000–2,000 ms 生成文本。LayaSingleSelector
用 ~33 ms 評估候選工具,不做 token 生成:
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. 置信度閾值門控
和 Laya 的 LangChain 整合一樣,LayaSingleSelector 和 LayaQueryRouter 讀取校準過的
answer_confidence(max(p)):
- 自動回退: 指定
fallback_index(或fallback_key),把不確定的查詢無縫轉到一個安全的 預設引擎。 - 嚴格防護: 在
LayaSingleSelector上設定raise_on_low_confidence=True,輸入含義不清時 丟擲LayaLowConfidenceError,讓呼叫方升級處理。
5. 遠端 HTTP 部署
適用於 serverless 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 一樣的逐呼叫參數:
兩個 token 預算(max_len、head_max_len)、語言與棄答控制(lang、min_confidence)和五個預測鉤子參數(hooks、on_predict_start、
on_predict_end、hooks_raise、hooks_timeout)。它們是按選擇器設定的,所以可以讓一個寬度大
的路由步驟多留些空間,而流水線的其餘部分仍保持 checkpoint 的預設值。
一個 choice 問題的各個選項共享 checkpoint 的選項預算 —— head_max_len,在 laya 上是 192 個
token —— 而每個候選都會把自己的名字和描述貢獻進去,所以超過大約 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 晶片,每個查詢一次前向傳播,按選中的工具計分),用一份 59 個工具的名單,
它是從 MASSIVE 英文意圖標籤構建的、每個標籤一句話語,所以真值是精確的。每個單元格是 59 個查詢裡
有多少個命中了它自己的工具;兩次重複得到了相同的計數。
| 59 工具名單 | 預設預算 | max_len=1024, head_max_len=384 |
…, head_max_len=512 |
|---|---|---|---|
| 命中自己工具的查詢 | 2/59 | 8/59 | 15/59 |
| 每個查詢的中位 ms | 160 | 172 | 184 |
這裡主張的不是絕對準確率:這個 checkpoint 不是 MASSIVE 分類器,而 59 個相似的標籤是一種壓力形狀。 主張的是方向和代價 —— 一份會被預設預算壓到近乎為零的名單變得可讀了,而在這種規模下,加寬視窗 幾乎不花時間。選項少於約 20 個時,標籤本來就已經裝得下,加寬反而可能把答案帶偏,這就是兩個參數 都按選擇器選擇加入的原因。那條實測的懸崖見 LangChain 整合。
鉤子只在本地路徑上執行。 一個帶 base_url 和 hooks=[...] 的選擇器會丟擲 ValueError,
而不是報告一個其快取從未執行過的成功 —— 鉤子是一個在 predict 內部執行的 Python 可呼叫物件,
沒有任何線上格式能攜帶它。請把鉤子裝在執行推理的那個程序裡。兩個預算確實會隨請求體傳到遠端節點,
上限是該節點的 LAYA_MAX_TOKEN_BUDGET;更大的值會以 422 返回。
語言與棄答
lang 釘住查詢所路由和作答所用的語言 —— 選擇作答 checkpoint 的按語言校準,而不是依賴內建檢測 —— 而 min_confidence 是 core 的棄答門:低於它的決策會作為一次棄答返回,而不是一次強制的選擇。兩者都同樣被 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
)