Logical Routing


What is Logical Routing?
Previously, we saw what “Routing” in RAG means. So, we’re going to start from the definition in here.
Definition:
Logical routing is a query handling approach that uses explicit rules, patterns, and conditional logic to determine where to direct incoming queries in an information system. Unlike semantic approaches that analyze meaning, logical routing relies on precise, predefined criteria to make routing decisions.
Core Parts:
Logical routing mainly consists of these 4 parts:
Rule Engine:
The central component that evaluates conditions and executes routing decisions based on predefined logic.
Pattern Matchers:
Tools that identify specific patterns in queries (keywords, phrases, question types).
Decision Trees:
Structured flow-charts that guide the routing process through a series of yes/no questions
Routing Destinations:
The various endpoints where queries can be directed (knowledge bases, specialized handlers, etc.)
How does it work?
Look at the following diagram:
Let’s take an example and see what exactly happens here:
Query: “How do I implement authentication in a React app with Node.js backend?”
Pre-processing:
Generally, the query is converted to lowercase.
Then the query is tokenized: ["how", "do", "i", "implement", "authentication", "in", "a", "react", "app", "with", "node.js", "backend"]
Logical Routing:
Rule Matching:
System checks predefined rules in order of specificity
Matches rule: "IF query contains React AND Node.js AND authentication → route to full-stack authentication guides"
Pattern Matching:
Languages/Frameworks identified: "React", "Node.js"
Concepts identified: "authentication"
Operation type: "implementation" (how-to)
Decision Trees:
Look at this:
Route Decisions:
- Based on the rule match, the system selects "javascript_fullstack_auth" as the routing destination.
Response Phase:
The query is directed specifically to the "JavaScript Full-Stack Authentication Documentation" section, which contains:
React frontend authentication patterns
Node.js backend authentication implementations
JWT/session management guides
Security best practices
The system retrieves information specifically from this targeted section rather than searching the entire database, resulting in:
More relevant results
Faster response times
Content specifically about implementing authentication in React+Node.js applications.
Is it always good?
Will answer it in the next article. Now, let’s do some code🤓
Let’s Code:
In this part, we will code Logical Routing. We will use a dummy Qdrant DB and simulate what happens when we use this kind of “Routing”
Feed the context (Give Knowledge):
# These should be valid files in your system def _init_knowledge_base(self): """Initialize the knowlegde base""" # Let's work with a dummy knowledge base. In real case, there might be some website data, database data and so on self.kb_files = { "javascript": "javascript_docs.pdf", "python": "python_docs.pdf", "ruby": "ruby_docs.pdf", "react": "react_docs.pdf", "nodejs": "nodejs_docs.pdf", "django": "django_docs.pdf", "api": "api_docs.pdf", "database": "database_docs.pdf", "authentication": "auth_docs.pdf", "general": "general_web_docs.pdf" } # This should be a proper knowledge base when implemented with real information self.knowledge_bases = {}
Define the patterns (Define Rules):
def _init_patterns(self): # In ideal cases, these patters should de generated using LLMs in massive amount and # stored in the vector store beforehand. """Initialize pattern matching rules""" # Language patterns self.language_patterns = { "javascript": ["javascript", "js", "ecmascript", ".js"], "python": ["python", "py", ".py", "pip"], "ruby": ["ruby", "rails", "erb", "gem", ".rb"] } # Framework patterns self.framework_patterns = { "react": ["react", "jsx", "component", "hook", "props", "state"], "nodejs": ["node", "nodejs", "npm", "express", "package.json"], "django": ["django", "drf", "django-rest-framework"] } # Concept patterns self.concept_patterns = { "api": ["api", "rest", "endpoint", "http", "request", "response"], "database": ["database", "db", "sql", "query", "mongodb", "schema", "model"], "authentication": ["auth", "login", "jwt", "token", "session", "password"] } # Operation patterns self.operation_patterns = { "how_to": ["how to", "how do i", "steps to", "guide for", "tutorial", "implement"], "definition": ["what is", "define", "explain", "meaning of", "understand", "concept of"], "comparison": ["vs", "versus", "compare", "difference between", "better than", "pros and cons"], "troubleshooting": ["fix", "error", "bug", "issue", "problem", "not working", "debug"] }
Match the Patterns (Pattern Matching):
# Match the patterns with pre-defined rules. def _match_patterns(self, query, pattern_dict): """Match query against a pattern dictionary and return the matched results""" query_lower = query.lower() matches = [] matched_patterns = {} for category, patterns in pattern_dict.items(): for pattern in patterns: if pattern in query_lower: if category not in matches: matches.append(category) matched_patterns[category] = [pattern] else: matched_patterns[category].append(pattern) return matches, matched_patterns
Analyze Query (between rules matching and routing):
```python def analyze_query(self, query): """Analyze the query and get the results"""
languages, lang_patterns = self._match_patterns(query, self.language_patterns) frameworks, framework_patterns = self._match_patterns(query, self.framework_patterns) concepts, concept_patterns = self._match_patterns(query, self.concept_patterns) operations, op_patterns = self._match_patterns(query, self.operation_patterns)
analysis = { "languages": languages, "frameworks": frameworks, "concepts": concepts, "operations": operations, "matched_patterns": { "languages": lang_patterns, "frameworks": framework_patterns, "concepts": concept_patterns, "operations": op_patterns }, "original_query": query }
return analysis
5. **Route the query:**
```python
# Routing started
def route_query(self, query):
"""Apply logical routing rules to determine the best knowledge base available"""
analysis = self.analyze_query(query=query)
route_info = {
"query": query,
"analysis": analysis,
"route_decision": None,
"decision_path": [],
"knowledge_base": None
}
if analysis["languages"]:
primary_language = analysis["languages"][0]
route_info["decision_path"].append(f"Language detected: {primary_language}")
if analysis["frameworks"]:
framework = analysis["frameworks"][0]
compatible = False
if primary_language == "javascript" and framework in ["react", "nodejs"]:
compatible = True
elif primary_language == "python" and framework == "django":
compatible = True
if compatible:
route_info["decision_path"].append(f"Compatible framework found: {framework}")
route_info["route_decision"] = framework
route_info["knowledge_base"] = self._get_kb(framework)
return route_info
route_info["route_decision"] = primary_language
route_info["knowledge_base"] = self._get_kb(primary_language)
return route_info
elif analysis["frameworks"]:
framework = analysis["frameworks"][0]
route_info["decision_path"].append(f"Framework detected: {framework}")
route_info["route_decision"] = framework
route_info["knowledge_base"] = self._get_kb(framework)
return route_info
elif analysis["concepts"]:
concept = analysis["concepts"][0]
route_info["decision_path"].append(f"Concept detected: {concept}")
route_info["route_decision"] = concept
route_info["knowledge_base"] = self._get_kb(concept)
return route_info
route_info["decision_path"].append("No specific domain detected, using general knowledge base")
route_info["route_decision"] = "general"
route_info["knowledge_base"] = self._get_kb("general")
return route_info
# Routing done. Now Search the final decision on the vector store
def search(self, query, k=5):
"""Route the query and perform search"""
route_info = self.route_query(query)
kb = route_info["knowledge_base"]
if not kb:
print("No valid knowledge base found for routing decision")
return []
results = kb.search(query, k=k)
return {
"routing": route_info,
"results": results
}
Dummy Checker Function:
# Dummy Checking Function. In real time, real queries will be sent to the server an the backend # will validate and route it. def demonstration_logical_routing(): """Show examples of the logical routing system with real queries""" router = LogicalRouter() example_queries = [ "How do I create an array in JavaScript?", "What's the best way to connect Python to a SQL database?", "How to fix React component rendering error", "What is authentication in web applications?", "Explain the difference between Node.js and Django", "How to implement REST APIs?", "What is a closure in JavaScript?", "Django vs Flask - which should I use?" ] print("\n" + "="*80) print(" "*30 + "LOGICAL ROUTING DEMO") print("="*80 + '\n') for index, query in enumerate(example_queries, 1): print(f"Query no. {index}: {query}") print('\n') route_info = router.route_query(query) print("\nQUERY ANALYSIS:") for category, items in route_info["analysis"].items(): if category not in ["mathched_patters", "original_query"]: print(f"-> {category.capitalize()}: {', '.join(items)}") print("\n ➡️ Routing Decision Paths: ") for step in route_info["decision_path"]: print(f" -> {step}") print(f"\n 🤚 Final Decision Here: {route_info["route_decision"]}") if route_info["knowledge_base"]: kb_name = route_info["route_decision"] print(f" Routed to Knowledge base: {kb_name}") else: print(" No valid knowledge base found") print("-"*80)
Demo Response:
Initializing the logical router with base path
Logical router base path initilalized successfully
================================================================================
LOGICAL ROUTING DEMO
================================================================================
Query no. 1: How do I create an array in JavaScript?
Initializing knowldege base: javascript
Creating new collection: 'javascript_docs'
Error creating new collection: {e}
QUERY ANALYSIS:
-> Languages: javascript
-> Frameworks:
-> Concepts:
-> Operations: how_to
-> Matched_patterns: languages, frameworks, concepts, operations
➡️ Routing Decision Paths:
-> Language detected: javascript
🤚 Final Decision Here: javascript
Routed to Knowledge base: javascript
--------------------------------------------------------------------------------
Query no. 2: What's the best way to connect Python to a SQL database?
Initializing knowldege base: python
Creating new collection: 'python_docs'
Error creating new collection: {e}
QUERY ANALYSIS:
-> Languages: python
-> Frameworks:
-> Concepts: database
-> Operations:
-> Matched_patterns: languages, frameworks, concepts, operations
➡️ Routing Decision Paths:
-> Language detected: python
🤚 Final Decision Here: python
Routed to Knowledge base: python
--------------------------------------------------------------------------------
Query no. 3: How to fix React component rendering error
Initializing knowldege base: react
Creating new collection: 'react_docs'
Error creating new collection: {e}
QUERY ANALYSIS:
-> Languages:
-> Frameworks: react
-> Concepts:
-> Operations: how_to, troubleshooting
-> Matched_patterns: languages, frameworks, concepts, operations
➡️ Routing Decision Paths:
-> Framework detected: react
🤚 Final Decision Here: react
Routed to Knowledge base: react
--------------------------------------------------------------------------------
Query no. 4: What is authentication in web applications?
Initializing knowldege base: authentication
Creating new collection: 'auth_docs'
Error creating new collection: {e}
QUERY ANALYSIS:
-> Languages:
-> Frameworks:
-> Concepts: authentication
-> Operations: definition
-> Matched_patterns: languages, frameworks, concepts, operations
➡️ Routing Decision Paths:
-> Concept detected: authentication
🤚 Final Decision Here: authentication
Routed to Knowledge base: authentication
--------------------------------------------------------------------------------
Query no. 5: Explain the difference between Node.js and Django
Initializing knowldege base: nodejs
Creating new collection: 'nodejs_docs'
Error creating new collection: {e}
QUERY ANALYSIS:
-> Languages: javascript
-> Frameworks: nodejs, django
-> Concepts:
-> Operations: definition, comparison
-> Matched_patterns: languages, frameworks, concepts, operations
➡️ Routing Decision Paths:
-> Language detected: javascript
-> Compatible framework found: nodejs
🤚 Final Decision Here: nodejs
Routed to Knowledge base: nodejs
--------------------------------------------------------------------------------
Query no. 6: How to implement REST APIs?
Initializing knowldege base: api
Creating new collection: 'api_docs'
Error creating new collection: {e}
QUERY ANALYSIS:
-> Languages:
-> Frameworks:
-> Concepts: api
-> Operations: how_to
-> Matched_patterns: languages, frameworks, concepts, operations
➡️ Routing Decision Paths:
-> Concept detected: api
🤚 Final Decision Here: api
Routed to Knowledge base: api
--------------------------------------------------------------------------------
Query no. 7: What is a closure in JavaScript?
QUERY ANALYSIS:
-> Languages: javascript
-> Frameworks:
-> Concepts:
-> Operations: definition
-> Matched_patterns: languages, frameworks, concepts, operations
➡️ Routing Decision Paths:
-> Language detected: javascript
🤚 Final Decision Here: javascript
Routed to Knowledge base: javascript
--------------------------------------------------------------------------------
Query no. 8: Django vs Flask - which should I use?
Initializing knowldege base: django
Creating new collection: 'django_docs'
Error creating new collection: {e}
QUERY ANALYSIS:
-> Languages:
-> Frameworks: django
-> Concepts:
-> Operations: comparison
-> Matched_patterns: languages, frameworks, concepts, operations
➡️ Routing Decision Paths:
-> Framework detected: django
🤚 Final Decision Here: django
Routed to Knowledge base: django
--------------------------------------------------------------------------------
Full Code:
Get the full code here (Github Gist)
There is an implementation of Vector Store; you can ignore it. I am using Docker for running Qdrant Store locally.
Additional Resource:
Conclusion:
Next, we will see the Semantic Routing and see some comparisons.
Subscribe to my newsletter
Read articles from Pritom Biswas directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
