PromptRouter, QuestionType
On this page
core.prompt_router.PromptRouter, core.prompt_router.QuestionType
Overview
PromptRouter detects the language (Arabic/English) and rhetorical type of a question, then builds a prompt from a matching template — including optional few-shot examples. It exists so RAGSystem can automatically tailor its instructions to the user (e.g. "explain the steps" for a how-to question vs. "compare the elements" for a comparative one) without the caller having to classify questions manually.
QuestionType
class QuestionType(Enum):
FACTUAL = "factual"
ANALYTICAL = "analytical"
COMPARATIVE = "comparative"
PROCEDURAL = "procedural"
DEFINITIONAL = "definitional"
EVALUATIVE = "evaluative"
CAUSAL = "causal"
GENERAL = "general"
Eight classifications. GENERAL is the fallback when no keyword pattern matches.
Constructor
Exact signature
class PromptRouter:
def __init__(self, include_few_shot: bool = True): ...
Parameters
detect_language
def detect_language(self, text: str) -> str
Algorithm
- Empty/falsy
text→ return"ar"(Arabic is the default for empty input). - Count characters matching the Unicode ranges
\u0600–\u06FF,\u0750–\u077F,\uFB50–\uFDFF,\uFE70–\uFEFF(covers Arabic, Arabic Supplement, Arabic Presentation Forms-A and -B). - Compute
ratio = arabic_chars / max(len(text.replace(" ", "")), 1). - Return
"ar"ifratio > 0.25, else"en".
Returns
"ar" or "en".
Complexity
O(n) in text length (single regex scan).
Examples
router = PromptRouter()
router.detect_language("ما هو الذكاء الاصطناعي؟") # "ar"
router.detect_language("What is AI?") # "en"
router.detect_language("") # "ar" (empty-string default)
router.detect_language("AI مصطلح") # depends on the >25% ratio threshold
detect_question_type
def detect_question_type(self, query: str, language: Optional[str] = None) -> QuestionType
Parameters
Algorithm
Selects the pattern list (_PATTERNS_AR or _PATTERNS_EN) for the resolved language, then tests each (QuestionType, compiled_regex) pair in a fixed priority order and returns the first match:
Arabic priority order: COMPARATIVE → PROCEDURAL → DEFINITIONAL → ANALYTICAL → CAUSAL → EVALUATIVE → FACTUAL
English priority order: identical ordering.
If nothing matches, returns QuestionType.GENERAL.
[!NOTE] Pattern order matters Because the check is first-match-wins in a fixed order, a query matching multiple patterns (e.g. "Why is X better than Y?" — both
ANALYTICAL-ish andCOMPARATIVE-ish) resolves to whichever pattern is checked first —COMPARATIVEin this case, since it's listed beforeANALYTICAL.
Keyword patterns (as implemented)
(Arabic patterns mirror the same semantic categories using Arabic keywords — see source for exact regex.)
Returns
QuestionType.
Examples
router.detect_question_type("How do I reset my password?") # PROCEDURAL
router.detect_question_type("What is the difference between AI and ML?") # COMPARATIVE
router.detect_question_type("Who is the CEO?") # FACTUAL
router.detect_question_type("") # GENERAL
router.detect_question_type("كيف أنشئ حساباً؟") # PROCEDURAL
build
def build(self, query: str, context: str, language: Optional[str] = None,
question_type: Optional[QuestionType] = None) -> str
Parameters
Returns
str — a complete, ready-to-send LLM prompt.
Algorithm
- Resolve
langandq_type(auto-detect any that weren't passed explicitly). - If
include_few_shot, look up a matching example string from_FEW_SHOT_AR/_FEW_SHOT_EN(keyed byq_type;GENERALmaps to an empty string in both tables). - Dispatch to
_build_arabicor_build_englishwith(query, context, q_type, few_shot). - Log a DEBUG line with
lang,q_type.value, and prompt length.
Internal builders — instruction mapping
Both _build_arabic and _build_english select a per-QuestionType instruction sentence (e.g. FACTUAL → "Answer factually and concisely using only the provided information", COMPARATIVE → "Compare the elements, highlighting similarities and differences") and assemble a fixed template:
{persona sentence}
Instruction: {instruction}
Rules:
• Base your answer solely on the provided information.
• If information is insufficient, say: "Insufficient information to answer."
• Answer in {language}.
{few_shot examples, if any}
Available Information:
{context}
Question: {query}
Answer:
(Arabic version uses the equivalent Arabic wording and RTL-appropriate phrasing.)
Side effects
None beyond a DEBUG log line — build() is a pure string-construction function.
Complexity
O(n) in the combined length of context + few-shot text (string concatenation/formatting).
Examples
Basic — full auto-detection:
router = PromptRouter()
prompt = router.build(
query="What is the return policy?",
context="Items may be returned within 30 days of purchase.",
)
Forcing language and type:
prompt = router.build(
query="مقارنة بين الخطط",
context="...",
language="ar",
question_type=QuestionType.COMPARATIVE,
)
Disabling few-shot examples:
router = PromptRouter(include_few_shot=False)
prompt = router.build(query="How do I cancel my subscription?", context=context)
Inspecting classification before building:
lang = router.detect_language(query)
qtype = router.detect_question_type(query, lang)
print(f"{lang} / {qtype.value}")
prompt = router.build(query, context, language=lang, question_type=qtype)
Production-ready usage — inside a custom RAG loop:
router = PromptRouter(include_few_shot=True)
context = context_manager.build(query, retrieved_chunks)
prompt = router.build(query=query, context=context)
answer = llm.generate(prompt)
Thread safety
Stateless aside from the immutable include_few_shot flag set at construction — safe to share a single PromptRouter instance across threads.
Best practices
- Let
build()auto-detect language/type unless you have a specific reason to override — the priority-ordered pattern matching is already tuned per language. - If you need a question type your query doesn't trigger via keywords, pass
question_typeexplicitly rather than trying to game the regex patterns.
Common mistakes
- Assuming pattern matching is exhaustive/ML-based — it's simple regex keyword matching, so paraphrased questions without trigger words fall through to
GENERAL. - Expecting
QuestionTypevalues to compare equal to their string values directly (QuestionType.FACTUAL == "factual"isFalse; use.value).
Related APIs
RAGSystem._resolve_prompt— the primary caller ofPromptRouter.build().