change default router to pydantic
diff --git a/llama_index/llm_predictor/base.py b/llama_index/llm_predictor/base.py
index 1d164c58a3249..32e02bf27d733 100644
--- a/llama_index/llm_predictor/base.py
+++ b/llama_index/llm_predictor/base.py
@@ -28,6 +28,11 @@ class BaseLLMPredictor(Protocol):
 
     callback_manager: CallbackManager
 
+    @property
+    @abstractmethod
+    def llm(self) -> LLM:
+        """Get LLM."""
+
     @property
     @abstractmethod
     def metadata(self) -> LLMMetadata:
diff --git a/llama_index/llm_predictor/mock.py b/llama_index/llm_predictor/mock.py
index a9e8f458a2612..1bf80fadc46be 100644
--- a/llama_index/llm_predictor/mock.py
+++ b/llama_index/llm_predictor/mock.py
@@ -6,7 +6,7 @@
 from llama_index.callbacks.schema import CBEventType, EventPayload
 from llama_index.constants import DEFAULT_NUM_OUTPUTS
 from llama_index.llm_predictor.base import BaseLLMPredictor
-from llama_index.llms.base import LLMMetadata
+from llama_index.llms.base import LLMMetadata, LLM
 from llama_index.prompts.base import Prompt
 from llama_index.prompts.prompt_type import PromptType
 from llama_index.token_counter.utils import (
@@ -95,6 +95,10 @@ def __init__(self, max_tokens: int = DEFAULT_NUM_OUTPUTS) -> None:
     def metadata(self) -> LLMMetadata:
         return LLMMetadata()
 
+    @property
+    def llm(self) -> LLM:
+        raise NotImplementedError("MockLLMPredictor does not have an LLM model.")
+
     def _log_start(self, prompt: Prompt, prompt_args: dict) -> str:
         """Log start of an LLM event."""
         llm_payload = prompt_args.copy()
diff --git a/llama_index/llm_predictor/vellum/predictor.py b/llama_index/llm_predictor/vellum/predictor.py
index b8d407e13c816..6d38e43d1a5c2 100644
--- a/llama_index/llm_predictor/vellum/predictor.py
+++ b/llama_index/llm_predictor/vellum/predictor.py
@@ -5,7 +5,7 @@
 from llama_index import Prompt
 from llama_index.callbacks import CallbackManager
 from llama_index.callbacks.schema import CBEventType, EventPayload
-from llama_index.llm_predictor.base import BaseLLMPredictor, LLMMetadata
+from llama_index.llm_predictor.base import BaseLLMPredictor, LLMMetadata, LLM
 from llama_index.llm_predictor.vellum.exceptions import VellumGenerateException
 from llama_index.llm_predictor.vellum.prompt_registry import VellumPromptRegistry
 from llama_index.llm_predictor.vellum.types import (
@@ -45,6 +45,11 @@ def metadata(self) -> LLMMetadata:
         # deployment. This is not currently possible, so we use default values.
         return LLMMetadata()
 
+    @property
+    def llm(self) -> LLM:
+        """Get the LLM."""
+        raise NotImplementedError("Vellum does not expose the LLM.")
+
     def predict(self, prompt: Prompt, **prompt_args: Any) -> str:
         """Predict the answer to a query."""
 
diff --git a/llama_index/query_engine/router_query_engine.py b/llama_index/query_engine/router_query_engine.py
index 807d97119bdcf..774033d5d7ab1 100644
--- a/llama_index/query_engine/router_query_engine.py
+++ b/llama_index/query_engine/router_query_engine.py
@@ -12,6 +12,10 @@
 from llama_index.response.schema import RESPONSE_TYPE, Response, StreamingResponse
 from llama_index.response_synthesizers import TreeSummarize
 from llama_index.selectors.llm_selectors import LLMMultiSelector, LLMSingleSelector
+from llama_index.selectors.pydantic_selectors import (
+    PydanticMultiSelector,
+    PydanticSingleSelector,
+)
 from llama_index.selectors.types import BaseSelector
 from llama_index.schema import BaseNode
 from llama_index.tools.query_engine import QueryEngineTool
@@ -100,10 +104,26 @@ def from_defaults(
         summarizer: Optional[TreeSummarize] = None,
         select_multi: bool = False,
     ) -> "RouterQueryEngine":
+        service_context = service_context or ServiceContext.from_defaults()
+
         if selector is None and select_multi:
-            selector = LLMMultiSelector.from_defaults(service_context=service_context)
+            try:
+                selector = PydanticMultiSelector.from_defaults(
+                    llm=service_context.llm_predictor.llm  # type: ignore
+                )
+            except ValueError:
+                selector = LLMMultiSelector.from_defaults(
+                    service_context=service_context
+                )
         elif selector is None and not select_multi:
-            selector = LLMSingleSelector.from_defaults(service_context=service_context)
+            try:
+                selector = PydanticSingleSelector.from_defaults(
+                    llm=service_context.llm_predictor.llm  # type: ignore
+                )
+            except ValueError:
+                selector = LLMSingleSelector.from_defaults(
+                    service_context=service_context
+                )
 
         assert selector is not None
 

# Description

Changes the router query engine to default to pydantic when possible.

## Type of Change

- [x] Bug fix (non-breaking change which fixes an issue)

# How Has This Been Tested?

- [x] tested in a notebook
- [x] I stared at the code and made sure it makes sense

