| # Pattern-Based Topic Analysis Review and Options | |
| ## Executive Summary | |
| The orchestrator uses hardcoded pattern matching for topic extraction and continuity analysis in three methods: | |
| 1. `_analyze_topic_continuity()` - Hardcoded keyword matching (ML, AI, Data Science only) | |
| 2. `_extract_main_topic()` - Hardcoded keyword matching (10+ topic categories) | |
| 3. `_extract_keywords()` - Hardcoded important terms list | |
| These methods are used extensively throughout the workflow, affecting reasoning chains, hypothesis generation, and agent execution tracking. | |
| ## Current Implementation Analysis | |
| ### 1. `_analyze_topic_continuity()` (Lines 1026-1069) | |
| **Current Approach:** | |
| - Pattern matching against 3 hardcoded topics: "machine learning", "artificial intelligence", "data science" | |
| - Checks session context summary and interaction context summaries for keywords | |
| - Returns: "Continuing {topic} discussion" or "New topic: {topic}" | |
| **Limitations:** | |
| - Only recognizes 3 topics | |
| - Misses domain-specific topics (e.g., healthcare, finance, legal) | |
| - Misses nuanced topics (e.g., "transformer architectures" β classified as "general") | |
| - Brittle: fails on synonyms, typos, or domain-specific terminology | |
| - Not learning-enabled: requires manual updates for new domains | |
| **Usage:** | |
| - Reasoning chain step_1 evidence (line 187) | |
| - Used once per request for context analysis | |
| ### 2. `_extract_main_topic()` (Lines 1251-1279) | |
| **Current Approach:** | |
| - Pattern matching against 10+ topic categories: | |
| - AI chatbot course curriculum | |
| - Programming course curriculum | |
| - Educational course design | |
| - Machine learning concepts | |
| - Artificial intelligence and chatbots | |
| - Data science and analysis | |
| - Software development and programming | |
| - General inquiry (fallback) | |
| **Limitations:** | |
| - Hardcoded keyword lists | |
| - Hierarchical but limited (e.g., curriculum β AI vs Programming) | |
| - Fallback to first 4 words if no match | |
| - Same brittleness as topic continuity | |
| **Usage:** | |
| - **Extensively used (18 times):** | |
| - Reasoning chain step_1 hypothesis (line 182) | |
| - Reasoning chain step_1 reasoning (line 191) | |
| - Reasoning chain step_2 reasoning (skills) (line 238) | |
| - Reasoning chain step_3 hypothesis (line 243) | |
| - Reasoning chain step_3 reasoning (line 251) | |
| - Reasoning chain step_4 hypothesis (line 260) | |
| - Reasoning chain step_4 reasoning (line 268) | |
| - Reasoning chain step_5 hypothesis (line 296) | |
| - Reasoning chain step_5 reasoning (line 304) | |
| - Reasoning chain step_6 hypothesis (line 376) | |
| - Reasoning chain step_6 reasoning (line 384) | |
| - Alternative reasoning paths (line 1110) | |
| - Error recovery (line 1665) | |
| ### 3. `_extract_keywords()` (Lines 1281-1295) | |
| **Current Approach:** | |
| - Extracts keywords from hardcoded important terms list | |
| - Returns comma-separated string of matched keywords | |
| **Limitations:** | |
| - Static list requires manual updates | |
| - May miss domain-specific terminology | |
| **Usage:** | |
| - Reasoning chain step_1 evidence (line 188) | |
| - Used once per request | |
| ## Current Workflow Impact | |
| ### Pattern Matching Usage Flow: | |
| ``` | |
| Request β Context Retrieval | |
| β | |
| Reasoning Chain Step 1: | |
| - Hypothesis: Uses _extract_main_topic() β "User is asking about: '{topic}'" | |
| - Evidence: Uses _analyze_topic_continuity() β "Topic continuity: ..." | |
| - Evidence: Uses _extract_keywords() β "Query keywords: ..." | |
| - Reasoning: Uses _extract_main_topic() β "...focused on {topic}..." | |
| β | |
| Intent Recognition (Agent executes independently) | |
| β | |
| Reasoning Chain Step 2-6: | |
| - All hypothesis/reasoning strings use _extract_main_topic() | |
| - Topic appears in 12+ reasoning chain fields | |
| β | |
| Alternative Reasoning Paths: | |
| - Uses _extract_main_topic() for path generation | |
| β | |
| Error Recovery: | |
| - Uses _extract_main_topic() for error context | |
| ``` | |
| ### Impact Points: | |
| 1. **Reasoning Chain Documentation**: All reasoning chain steps include topic strings | |
| 2. **Agent Execution Tracking**: Topic appears in hypothesis and reasoning fields | |
| 3. **Error Recovery**: Uses topic for context in error scenarios | |
| 4. **Logging/Debugging**: Topic strings appear in logs and execution traces | |
| **Important Note:** Pattern matching does NOT affect agent execution logic. Agents (Intent, Skills, Synthesis, Safety) execute independently using LLM inference. Pattern matching only affects: | |
| - Reasoning chain metadata (for debugging/analysis) | |
| - Logging messages | |
| - Hypothesis/reasoning strings in execution traces | |
| ## Options for Resolution | |
| ### Option 1: Remove Pattern Matching, Make Context Independent | |
| **Approach:** | |
| - Remove `_analyze_topic_continuity()`, `_extract_main_topic()`, `_extract_keywords()` | |
| - Replace with generic placeholders or remove from reasoning chains | |
| - Use actual context data (session_context, interaction_contexts, user_context) directly | |
| **Implementation Changes:** | |
| 1. **Replace topic extraction with context-based strings:** | |
| ```python | |
| # Before: | |
| hypothesis = f"User is asking about: '{self._extract_main_topic(user_input)}'" | |
| # After: | |
| hypothesis = f"User query analyzed with {len(interaction_contexts)} previous contexts" | |
| ``` | |
| 2. **Replace topic continuity with context-based analysis:** | |
| ```python | |
| # Before: | |
| f"Topic continuity: {self._analyze_topic_continuity(context, user_input)}" | |
| # After: | |
| f"Session context available: {bool(session_context)}" | |
| f"Interaction contexts: {len(interaction_contexts)}" | |
| ``` | |
| 3. **Replace keywords with user input excerpt:** | |
| ```python | |
| # Before: | |
| f"Query keywords: {self._extract_keywords(user_input)}" | |
| # After: | |
| f"Query: {user_input[:100]}..." | |
| ``` | |
| **Impact Analysis:** | |
| β **Benefits:** | |
| - **No hardcoded patterns**: Context independent of pattern learning | |
| - **Simpler code**: Removes 100+ lines of pattern matching logic | |
| - **More accurate**: Uses actual context data instead of brittle keyword matching | |
| - **Domain agnostic**: Works for any topic/domain without updates | |
| - **Maintainability**: No need to update keyword lists for new domains | |
| - **Performance**: No pattern matching overhead (minimal, but measurable) | |
| β **Drawbacks:** | |
| - **Less descriptive reasoning chains**: Hypothesis strings less specific (e.g., "User query analyzed" vs "User is asking about: Machine learning concepts") | |
| - **Reduced human readability**: Reasoning chain traces less informative for debugging | |
| - **Lost topic continuity insight**: No explicit "continuing topic X" vs "new topic Y" distinction | |
| **Workflow Impact:** | |
| - **No impact on agent execution**: Agents already use LLM inference, not pattern matching | |
| - **Reasoning chains less informative**: But still functional for debugging | |
| - **Logging less specific**: But still captures context availability | |
| - **No breaking changes**: All downstream components work with generic strings | |
| **Files Modified:** | |
| - `src/orchestrator_engine.py`: Remove 3 methods, update 18+ usage sites | |
| **Estimated Effort:** Low (1-2 hours) | |
| **Risk Level:** Low (only affects metadata, not logic) | |
| --- | |
| ### Option 2: Use LLM API for Zero-Shot Classification | |
| **Approach:** | |
| - Replace pattern matching with LLM-based zero-shot topic classification | |
| - Use LLM router to classify topics dynamically | |
| - Cache results to minimize API calls | |
| **Implementation Changes:** | |
| 1. **Create LLM-based topic extraction:** | |
| ```python | |
| async def _extract_main_topic_llm(self, user_input: str, context: dict) -> str: | |
| """Extract topic using LLM zero-shot classification""" | |
| prompt = f"""Classify the main topic of this query in 2-5 words: | |
| Query: "{user_input}" | |
| Available context: | |
| - Session summary: {context.get('session_context', {}).get('summary', 'N/A')[:200]} | |
| - Recent interactions: {len(context.get('interaction_contexts', []))} | |
| Respond with ONLY the topic name (e.g., "Machine Learning", "Healthcare Analytics", "Financial Modeling").""" | |
| topic = await self.llm_router.route_inference( | |
| task_type="classification", | |
| prompt=prompt, | |
| max_tokens=20, | |
| temperature=0.3 | |
| ) | |
| return topic.strip() if topic else "General inquiry" | |
| ``` | |
| 2. **Create LLM-based topic continuity:** | |
| ```python | |
| async def _analyze_topic_continuity_llm(self, context: dict, user_input: str) -> str: | |
| """Analyze topic continuity using LLM""" | |
| session_context = context.get('session_context', {}).get('summary', '') | |
| recent_interactions = context.get('interaction_contexts', [])[:3] | |
| prompt = f"""Determine if the current query continues the previous conversation topic or introduces a new topic. | |
| Session Summary: {session_context[:300]} | |
| Recent Interactions: | |
| {chr(10).join([ic.get('summary', '') for ic in recent_interactions])} | |
| Current Query: "{user_input}" | |
| Respond with one of: | |
| - "Continuing [topic] discussion" if same topic | |
| - "New topic: [topic]" if different topic | |
| Keep response under 50 words.""" | |
| continuity = await self.llm_router.route_inference( | |
| task_type="general_reasoning", | |
| prompt=prompt, | |
| max_tokens=50, | |
| temperature=0.5 | |
| ) | |
| return continuity.strip() if continuity else "No previous context" | |
| ``` | |
| 3. **Update method signatures to async:** | |
| - `_extract_main_topic()` β `async def _extract_main_topic_llm()` | |
| - `_analyze_topic_continuity()` β `async def _analyze_topic_continuity_llm()` | |
| - `_extract_keywords()` β Keep pattern-based or remove (keywords less critical) | |
| 4. **Add caching:** | |
| ```python | |
| # Cache topic extraction per user_input (hash) | |
| topic_cache = {} | |
| input_hash = hashlib.md5(user_input.encode()).hexdigest() | |
| if input_hash in topic_cache: | |
| return topic_cache[input_hash] | |
| topic = await _extract_main_topic_llm(...) | |
| topic_cache[input_hash] = topic | |
| return topic | |
| ``` | |
| **Impact Analysis:** | |
| β **Benefits:** | |
| - **Accurate topic classification**: LLM understands context, synonyms, nuances | |
| - **Domain adaptive**: Works for any domain without code changes | |
| - **Context-aware**: Uses session_context and interaction_contexts for continuity | |
| - **Human-readable**: Maintains descriptive reasoning chain strings | |
| - **Scalable**: No manual keyword list maintenance | |
| β **Drawbacks:** | |
| - **API latency**: Adds 2-3 LLM calls per request (~200-500ms total) | |
| - **API costs**: Additional tokens consumed per request | |
| - **Dependency on LLM availability**: Requires LLM router to be functional | |
| - **Complexity**: More code to maintain (async handling, caching, error handling) | |
| - **Inconsistency risk**: LLM responses may vary slightly between calls (though temperature=0.3 mitigates) | |
| **Workflow Impact:** | |
| **Positive:** | |
| - **More accurate reasoning chains**: Topic classification more reliable | |
| - **Better debugging**: More informative hypothesis/reasoning strings | |
| - **Context-aware continuity**: Uses actual session/interaction contexts | |
| **Negative:** | |
| - **Latency increase**: +200-500ms per request (2-3 LLM calls) | |
| - **Error handling complexity**: Need fallbacks if LLM calls fail | |
| - **Async complexity**: All 18+ usage sites need await statements | |
| **Implementation Complexity:** | |
| - **Method conversion**: 3 methods β async LLM calls | |
| - **Usage site updates**: 18+ sites need await/async propagation | |
| - **Caching infrastructure**: Add cache layer to reduce API calls | |
| - **Error handling**: Fallbacks if LLM unavailable | |
| - **Testing**: Verify LLM responses are reasonable | |
| **Files Modified:** | |
| - `src/orchestrator_engine.py`: Rewrite 3 methods, update 18+ usage sites with async/await | |
| - May need `process_request()` refactoring for async topic extraction | |
| **Estimated Effort:** Medium-High (4-6 hours) | |
| **Risk Level:** Medium (adds latency and LLM dependency) | |
| --- | |
| ## Recommendation | |
| ### Recommended: **Option 1 (Remove Pattern Matching)** | |
| **Rationale:** | |
| 1. **No impact on core functionality**: Pattern matching only affects metadata strings, not agent execution | |
| 2. **Simpler implementation**: Low risk, fast to implement | |
| 3. **No performance penalty**: Removes overhead instead of adding LLM calls | |
| 4. **Maintainability**: Less code to maintain | |
| 5. **Context independence**: Aligns with user requirement for pattern-independent context | |
| **If descriptive reasoning chains are critical:** | |
| - **Hybrid Approach**: Use Option 1 for production, but add optional LLM-based topic extraction as a debug/logging enhancement (non-blocking, optional) | |
| ### Alternative: **Option 2 (LLM Classification) if reasoning chain quality is critical** | |
| **Use Case:** | |
| - If reasoning chain metadata is used for: | |
| - User-facing explanations | |
| - Advanced debugging/analysis tools | |
| - External integrations requiring topic metadata | |
| - Then the latency/API cost may be justified | |
| ## Migration Path | |
| ### Option 1 Implementation Steps: | |
| 1. **Remove methods:** | |
| - Delete `_analyze_topic_continuity()` (lines 1026-1069) | |
| - Delete `_extract_main_topic()` (lines 1251-1279) | |
| - Delete `_extract_keywords()` (lines 1281-1295) | |
| 2. **Replace usages:** | |
| - Line 182: `hypothesis` β Use generic: "User query analysis" | |
| - Line 187: `Topic continuity` β Use: "Session context available: {bool(session_context)}" | |
| - Line 188: `Query keywords` β Use: "Query: {user_input[:100]}" | |
| - Line 191: `reasoning` β Remove topic references | |
| - Lines 238, 243, 251, 260, 268, 296, 304, 376, 384: Remove topic from reasoning strings | |
| - Line 1110: Remove topic from alternative paths | |
| - Line 1665: Use generic error context | |
| 3. **Test:** | |
| - Verify reasoning chains still populate correctly | |
| - Verify no syntax errors | |
| - Verify agents execute normally | |
| ### Option 2 Implementation Steps: | |
| 1. **Create async LLM methods** (as shown above) | |
| 2. **Add caching layer** | |
| 3. **Update `process_request()` to await topic extraction before reasoning chain** | |
| 4. **Add error handling with fallbacks** | |
| 5. **Test latency impact** | |
| 6. **Monitor API usage** | |
| ## Conclusion | |
| **Option 1** is recommended for immediate implementation due to: | |
| - Low risk and complexity | |
| - No performance penalty | |
| - Aligns with context independence requirement | |
| - Pattern matching doesn't affect agent execution | |
| **Option 2** should be considered only if reasoning chain metadata quality is critical for user-facing features or advanced debugging. | |