主题
概念
路由器(Router)是这样一类模块:它接收用户查询和一组“候选项”(由元数据描述),返回一个或多个被选中的候选项。
它们可以独立使用(作为“选择器模块”),也可以作为查询引擎或检索器使用(即建立在其他查询引擎/检索器之上)。
它们是简单却强大的模块,用 LLM 来做决策。可用于以下场景(不止这些):
- 在差异很大的数据源中挑出合适的那个
- 决定该做摘要(例如用 summary index 查询引擎)还是语义检索(例如用 vector index 查询引擎)
- 决定要不要“同时试”多个候选再合并结果(利用多路路由能力)。
核心的路由器模块有以下几种形态:
- LLM 选择器:把候选项作为文本整体塞进提示词,用 LLM 的文本补全端点来做决策
- Pydantic 选择器:把候选项作为 Pydantic schema 传给函数调用端点,并返回 Pydantic 对象
使用方式
下面是一个把路由器模块作为查询引擎一部分使用的简单例子。
from llama_index.core.query_engine import RouterQueryEngine
from llama_index.core.selectors import PydanticSingleSelector
from llama_index.core.tools import QueryEngineTool
list_tool = QueryEngineTool.from_defaults(
query_engine=list_query_engine,
description="Useful for summarization questions related to the data source",
)
vector_tool = QueryEngineTool.from_defaults(
query_engine=vector_query_engine,
description="Useful for retrieving specific context related to the data source",
)
query_engine = RouterQueryEngine(
selector=PydanticSingleSelector.from_defaults(),
query_engine_tools=[
list_tool,
vector_tool,
],
)
query_engine.query("<query>")1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
使用方式
定义一个路由器,核心就在于定义“选择器”。
你可以很自然地把我们的路由器当作查询引擎或检索器使用。这时路由器负责把用户查询“选择”并转交给某个(或某几个)查询引擎/检索器。
我们还要介绍 ToolRetrieverRouterQueryEngine,它做的是检索增强的路由——适用于候选项本身非常多、需要被索引起来的场景。注意:这是一个 beta 特性。
同样值得介绍的是把路由器作为独立模块使用。
定义一个选择器
下面是基于 LLM 与 Pydantic 的单选/多选选择器各一例:
from llama_index.core.selectors import LLMSingleSelector, LLMMultiSelector
from llama_index.core.selectors import (
PydanticMultiSelector,
PydanticSingleSelector,
)
# pydantic selectors feed in pydantic objects to a function calling API
# single selector (pydantic)
selector = PydanticSingleSelector.from_defaults()
# multi selector (pydantic)
selector = PydanticMultiSelector.from_defaults()
# LLM selectors use text completion endpoints
# single selector (LLM)
selector = LLMSingleSelector.from_defaults()
# multi selector (LLM)
selector = LLMMultiSelector.from_defaults()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
作为查询引擎使用
RouterQueryEngine 是把其他查询引擎作为工具组合在其之上构成的。
from llama_index.core.query_engine import RouterQueryEngine
from llama_index.core.selectors import PydanticSingleSelector
from llama_index.core.selectors.pydantic_selectors import Pydantic
from llama_index.core.tools import QueryEngineTool
from llama_index.core import VectorStoreIndex, SummaryIndex
# define query engines
...
# initialize tools
list_tool = QueryEngineTool.from_defaults(
query_engine=list_query_engine,
description="Useful for summarization questions related to the data source",
)
vector_tool = QueryEngineTool.from_defaults(
query_engine=vector_query_engine,
description="Useful for retrieving specific context related to the data source",
)
# initialize router query engine (single selection, pydantic)
query_engine = RouterQueryEngine(
selector=PydanticSingleSelector.from_defaults(),
query_engine_tools=[
list_tool,
vector_tool,
],
)
query_engine.query("<query>")1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
作为检索器使用
类似地,RouterRetriever 是把其他检索器作为工具组合而成的。例子如下:
from llama_index.core.retrievers import RouterRetriever
from llama_index.core.selectors import PydanticSingleSelector
from llama_index.core.tools import RetrieverTool
# define indices
...
# define retrievers
vector_retriever = vector_index.as_retriever()
keyword_retriever = keyword_index.as_retriever()
# initialize tools
vector_tool = RetrieverTool.from_defaults(
retriever=vector_retriever,
description="Useful for retrieving specific context from Paul Graham essay on What I Worked On.",
)
keyword_tool = RetrieverTool.from_defaults(
retriever=keyword_retriever,
description="Useful for retrieving specific context from Paul Graham essay on What I Worked On (using entities mentioned in query)",
)
# define retriever
retriever = RouterRetriever(
selector=PydanticSingleSelector.from_defaults(llm=llm),
retriever_tools=[
list_tool,
vector_tool,
],
)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
把选择器作为独立模块使用
你可以把选择器当作独立模块使用。候选项既可以定义成一列 ToolMetadata,也可以简单写成一组字符串。
from llama_index.core.tools import ToolMetadata
from llama_index.core.selectors import LLMSingleSelector
# choices as a list of tool metadata
choices = [
ToolMetadata(description="description for choice 1", name="choice_1"),
ToolMetadata(description="description for choice 2", name="choice_2"),
]
# choices as a list of strings
choices = [
"choice 1 - description for choice 1",
"choice 2: description for choice 2",
]
selector = LLMSingleSelector.from_defaults()
selector_result = selector.select(
choices, query="What's revenue growth for IBM in 2007?"
)
print(selector_result.selections)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
更多示例: