File size: 9,596 Bytes
ed1b365 | 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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | """Query Complexity Classifier
Determines whether a query needs full debate or can be answered directly.
This prevents over-activation: simple factual questions get direct answers,
while complex/ambiguous questions trigger full multi-agent reasoning.
"""
import re
from enum import Enum
class QueryComplexity(Enum):
"""Query complexity levels"""
SIMPLE = "simple" # Direct factual answer, no debate needed
MEDIUM = "medium" # Limited debate (2-3 agents)
COMPLEX = "complex" # Full debate with all relevant agents
class QueryClassifier:
"""Classify query complexity to determine reasoning depth."""
# Factual keywords (SIMPLE queries)
FACTUAL_PATTERNS = [
r"what is the (speed|velocity|mass|temperature|distance|height|width|size|weight|color|pressure|density|definition|meaning|name)",
r"define ", # "Define entropy"
r"what (year|date|time) ", # "What year did..."
r"how fast (is|can)", # "How fast is..." / "How fast can..."
r"how high is",
r"how long is",
r"what (color|size|shape)",
r"who (is|wrote|created|invented|discovered|founded)", # "Who is Einstein? Who wrote Romeo?"
r"where (is|are)", # "Where is the capital?"
r"what is the (capital|president|king|queen|currency|language|population)", # Geographic facts
r"list of ", # "List of elements"
r"formula for", # "Formula for..."
r"calculate ", # "Calculate..."
]
# Ambiguous keywords (COMPLEX queries)
AMBIGUOUS_PATTERNS = [
r"could .* really", # "Could machines really be conscious?"
r"might .* ever", # "Might we ever understand consciousness?"
r"can .* (truly|really)", # More specific: "Can machines truly be conscious?"
r"what does .* (really )?mean", # Interpretation of meaning
r"why (do|does) (we|they|people)", # Why questions (explanation seeking)
r"is .* the (future|destiny|past|foundation|basis|purpose)", # "Is AI the future?"
r"can .* (be|become|achieve)", # "Can machines achieve consciousness?" (also caught by subjective)
]
# Ethics/Philosophy keywords (COMPLEX queries)
ETHICS_PATTERNS = [
r"should (we |i |ai|society|companies)",
r"is it (right|wrong|ethical|moral)",
r"is it (good|bad|fair)",
r"ought",
r"morally?",
r"ethics?",
r"value of",
r"meaning of",
r"purpose of",
r"how should (we |ai|companies|society)", # "How should we govern"
r"balance .* (freedom|individual|collective|good|rights)", # Balancing values
]
# Multi-domain keywords (COMPLEX queries)
# Note: Pure factual relationships (e.g., "energy and mass") are NOT complex
# Only philosophical/semantic relationships are complex
MULTIDOMAIN_PATTERNS = [
r"relationship .*(consciousness|meaning|identity|knowledge|reality)", # Philosophical relationships
r"interaction .*(human|society|culture|mind|consciousness)",
r"(challenge|question) .* (understanding|reality|belief|knowledge)", # Foundational questions
]
# Subjective/opinion keywords (COMPLEX queries)
SUBJECTIVE_PATTERNS = [
r"is .*consciousness", # Defining consciousness
r"do you (think|believe)", # Asking for opinion
r"perspective",
r"what is (the )?nature of", # "What is the nature of free will?"
r"can .* (be|become) (measured|quantified|understood)", # Epistemology: "Can experience be measured?"
]
def classify(self, query: str) -> QueryComplexity:
"""Classify query complexity.
Args:
query: The user query
Returns:
QueryComplexity level (SIMPLE, MEDIUM, or COMPLEX)
"""
query_lower = query.lower().strip()
# SIMPLE: Pure factual queries
if self._is_factual(query_lower):
# But check if it has complexity markers too
if self._has_ambiguity(query_lower) or self._has_ethics(query_lower):
return QueryComplexity.COMPLEX
return QueryComplexity.SIMPLE
# COMPLEX: Ethics, philosophy, interpretation, multi-domain
if self._has_ethics(query_lower):
return QueryComplexity.COMPLEX
if self._has_ambiguity(query_lower):
return QueryComplexity.COMPLEX
if self._has_multidomain(query_lower):
return QueryComplexity.COMPLEX
if self._has_subjective(query_lower):
return QueryComplexity.COMPLEX
# MEDIUM: Everything else
return QueryComplexity.MEDIUM
def _is_factual(self, query: str) -> bool:
"""Check if query is direct factual question."""
return any(re.search(pattern, query) for pattern in self.FACTUAL_PATTERNS)
def _has_ambiguity(self, query: str) -> bool:
"""Check if query has ambiguity markers."""
return any(re.search(pattern, query) for pattern in self.AMBIGUOUS_PATTERNS)
def _has_ethics(self, query: str) -> bool:
"""Check if query involves ethics/philosophy."""
return any(re.search(pattern, query) for pattern in self.ETHICS_PATTERNS)
def _has_multidomain(self, query: str) -> bool:
"""Check if query spans multiple domains."""
return any(re.search(pattern, query) for pattern in self.MULTIDOMAIN_PATTERNS)
def _has_subjective(self, query: str) -> bool:
"""Check if query invites subjective reasoning."""
return any(re.search(pattern, query) for pattern in self.SUBJECTIVE_PATTERNS)
def select_agents(
self, complexity: QueryComplexity, domain: str
) -> dict[str, float]:
"""Select agents and their weights based on complexity and domain.
Args:
complexity: Query complexity level
domain: Detected query domain
Returns:
Dict mapping agent names to activation weights (0-1)
"""
# All available agents with their domains
all_agents = {
"Newton": ["physics", "mathematics", "systems"],
"Quantum": ["physics", "uncertainty", "systems"],
"Philosophy": ["philosophy", "meaning", "consciousness"],
"DaVinci": ["creativity", "systems", "innovation"],
"Empathy": ["ethics", "consciousness", "meaning"],
"Ethics": ["ethics", "consciousness", "meaning"],
}
domain_agents = all_agents
if complexity == QueryComplexity.SIMPLE:
# Simple queries: just the primary agent for the domain
# Activate only 1 agent at full strength
primary = self._get_primary_agent(domain)
return {primary: 1.0}
elif complexity == QueryComplexity.MEDIUM:
# Medium queries: primary + 1-2 secondary agents
# Soft gating with weighted influence
primary = self._get_primary_agent(domain)
secondaries = self._get_secondary_agents(domain, count=1)
weights = {primary: 1.0}
for secondary in secondaries:
weights[secondary] = 0.6
return weights
else: # COMPLEX
# Complex queries: all relevant agents for domain + cross-domain
# Full soft gating
primary = self._get_primary_agent(domain)
secondaries = self._get_secondary_agents(domain, count=2)
cross_domain = self._get_cross_domain_agents(domain, count=1)
weights = {primary: 1.0}
for secondary in secondaries:
weights[secondary] = 0.7
for cross in cross_domain:
weights[cross] = 0.4
return weights
def _get_primary_agent(self, domain: str) -> str:
"""Get the primary agent for a domain."""
domain_map = {
"physics": "Newton",
"mathematics": "Newton",
"creativity": "DaVinci",
"ethics": "Ethics",
"philosophy": "Philosophy",
"meaning": "Philosophy",
"consciousness": "Empathy",
"uncertainty": "Quantum",
"systems": "Newton",
}
return domain_map.get(domain, "Newton")
def _get_secondary_agents(self, domain: str, count: int = 1) -> list[str]:
"""Get secondary agents for a domain."""
domain_map = {
"physics": ["Quantum", "DaVinci"],
"mathematics": ["Quantum", "Philosophy"],
"creativity": ["Quantum", "Empathy"],
"ethics": ["Philosophy", "Empathy"],
"philosophy": ["Empathy", "Ethics"],
"meaning": ["Quantum", "DaVinci"],
"consciousness": ["Philosophy", "Quantum"],
"uncertainty": ["Philosophy", "DaVinci"],
"systems": ["DaVinci", "Philosophy"],
}
candidates = domain_map.get(domain, ["Philosophy", "DaVinci"])
return candidates[:count]
def _get_cross_domain_agents(self, domain: str, count: int = 1) -> list[str]:
"""Get cross-domain agents (useful for all domains)."""
# Philosophy and Empathy are useful everywhere
candidates = ["Philosophy", "Empathy", "DaVinci"]
return candidates[:count]
|