Routers
Concept
Section titled “Concept”Routers are modules that take in a user query and a set of “choices” (defined by metadata), and returns one or more selected choices.
They can be used on their own (as “selector modules”), or used as a query engine or retriever (e.g. on top of other query engines/retrievers).
They are simple but powerful modules that use LLMs for decision making capabilities. They can be used for the following use cases and more:
- Selecting the right data source among a diverse range of data sources
- Deciding whether to do summarization (e.g. using summary index query engine) or semantic search (e.g. using vector index query engine)
- Deciding whether to “try” out a bunch of choices at once and combine the results (using multi-routing capabilities).
The core router modules exist in the following forms:
- LLM selectors put the choices as a text dump into a prompt and use LLM text completion endpoint to make decisions
- Pydantic selectors pass choices as Pydantic schemas into a function calling endpoint, and return Pydantic objects
Usage Pattern
Section titled “Usage Pattern”A simple example of using our router module as part of a query engine is given below.
from llama_index.core.query_engine import RouterQueryEnginefrom llama_index.core.selectors import PydanticSingleSelectorfrom 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>")
Usage Pattern
Section titled “Usage Pattern”Defining a “selector” is at the core of defining a router.
You can easily use our routers as a query engine or a retriever. In these cases, the router will be responsible for “selecting” query engine(s) or retriever(s) to route the user query to.
We also highlight our ToolRetrieverRouterQueryEngine
for retrieval-augmented routing - this is the case
where the set of choices themselves may be very big and may need to be indexed. NOTE: this is a beta feature.
We also highlight using our router as a standalone module.
Defining a selector
Section titled “Defining a selector”Some examples are given below with LLM and Pydantic based single/multi selectors:
from llama_index.core.selectors import LLMSingleSelector, LLMMultiSelectorfrom 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()
Using as a Query Engine
Section titled “Using as a Query Engine”A RouterQueryEngine
is composed on top of other query engines as tools.
from llama_index.core.query_engine import RouterQueryEnginefrom llama_index.core.selectors import PydanticSingleSelectorfrom llama_index.core.selectors.pydantic_selectors import Pydanticfrom llama_index.core.tools import QueryEngineToolfrom llama_index.core import VectorStoreIndex, SummaryIndex
# define query engines...
# initialize toolslist_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>")
Using as a Retriever
Section titled “Using as a Retriever”Similarly, a RouterRetriever
is composed on top of other retrievers as tools. An example is given below:
from llama_index.core.retrievers import RouterRetrieverfrom llama_index.core.selectors import PydanticSingleSelectorfrom llama_index.core.tools import RetrieverTool
# define indices...
# define retrieversvector_retriever = vector_index.as_retriever()keyword_retriever = keyword_index.as_retriever()
# initialize toolsvector_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 retrieverretriever = RouterRetriever( selector=PydanticSingleSelector.from_defaults(llm=llm), retriever_tools=[ list_tool, vector_tool, ],)
Using selector as a standalone module
Section titled “Using selector as a standalone module”You can use the selectors as standalone modules. Define choices as either a list of ToolMetadata
or as a list of strings.
from llama_index.core.tools import ToolMetadatafrom llama_index.core.selectors import LLMSingleSelector
# choices as a list of tool metadatachoices = [ ToolMetadata(description="description for choice 1", name="choice_1"), ToolMetadata(description="description for choice 2", name="choice_2"),]
# choices as a list of stringschoices = [ "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)
More examples: