Spaces:
Sleeping
Sleeping
| # Skill Extractor Optimization Plan | |
| ## Current Performance | |
| - **Inference time**: 40-60 seconds per request | |
| - **Hardware**: 2 vCPUs, 18GB RAM | |
| - **Model**: Qwen2.5-1.5B-Instruct (Q4_K_M quantization) | |
| ## Optimization Strategies (Ranked by Impact) | |
| ### 1. Switch to Smaller/Faster Model ⚡⚡⚡ | |
| **Impact**: 3-5x speedup | **Effort**: Medium | |
| **Options:** | |
| - **Qwen2.5-0.5B-Instruct-Q4_K_M** (~1.5GB vs 1GB) | |
| - Pros: Much faster inference, lower memory usage | |
| - Cons: Slightly less accurate on complex skills | |
| - Expected speedup: 3-4x | |
| - **Phi-3-mini-4k-instruct-Q4_K_M** (~2GB) | |
| - Pros: Optimized for speed, good reasoning | |
| - Cons: Different model, may need prompt tuning | |
| - Expected speedup: 2-3x | |
| - **Gemma-2-2b-it-Q4_K_M** (~1.6GB) | |
| - Pros: Fast, good instruction following | |
| - Cons: Slightly larger than 0.5B options | |
| - Expected speedup: 2-3x | |
| **Implementation:** | |
| - Update Dockerfile to download new model | |
| - Change default model path in `get_instance()` | |
| - Test accuracy on sample job descriptions | |
| --- | |
| ### 2. Remove Grammar Constraint ⚡⚡ | |
| **Impact**: 20-30% speedup | **Effort**: Low | |
| **Current bottleneck:** JSON grammar validation adds significant overhead | |
| **Approach:** | |
| - Remove `grammar=self.grammar` from `create_chat_completion()` | |
| - Use simpler regex-based JSON parsing | |
| - Add fallback for malformed output | |
| **Trade-off:** Slightly less structured output, but parsing is robust | |
| --- | |
| ### 3. Aggressive Prompt Compression ⚡⚡ | |
| **Impact**: 15-25% speedup | **Effort**: Low | |
| **Current prompt:** ~200 tokens | |
| **Optimized prompt:** ~80 tokens | |
| **Changes:** | |
| ```python | |
| # Current (verbose) | |
| "Extract skills from the job posting as short 2-4 word phrases. " | |
| "Ignore company boilerplate. Never output fragments. " | |
| "required_skills = explicitly mandatory. " | |
| "nice_to_have_skills = preferred/optional. " | |
| "Include mandatory degrees/certifications in required_skills." | |
| # Optimized (concise) | |
| "Extract skills as 2-4 word phrases. " | |
| "required=mandatory, nice_to_have=optional. " | |
| "Include degrees/certs in required." | |
| ``` | |
| --- | |
| ### 4. Reduce Output Tokens ⚡ | |
| **Impact**: 10-15% speedup | **Effort**: Low | |
| **Current:** `_MAX_TOKENS = 64` | |
| **Optimized:** `_MAX_TOKENS = 32` | |
| Most skill extractions need <20 tokens. 32 provides safety margin. | |
| --- | |
| ### 5. Add Response Caching ⚡⚡ | |
| **Impact**: Near-instant for duplicates | **Effort**: Medium | |
| **Strategy:** | |
| - Hash job_description + job_title | |
| - Cache results in memory (dict) or Redis | |
| - Set TTL of 24-48 hours | |
| - Cache hit rate typically 20-30% for job boards | |
| **Implementation:** | |
| ```python | |
| _cache = {} | |
| def extract(self, job_description: str, job_title: str = ""): | |
| key = hashlib.md5(f"{job_title}:{job_description}".encode()).hexdigest() | |
| if key in _cache: | |
| return _cache[key] | |
| result = # ... extraction logic | |
| _cache[key] = result | |
| return result | |
| ``` | |
| --- | |
| ### 6. Hybrid Approach: LLM + Rule-Based ⚡⚡⚡ | |
| **Impact**: 5-10x speedup for common patterns | **Effort**: High | |
| **Strategy:** | |
| - Build regex/keyword-based extractor for common skills | |
| - Use LLM only for complex/ambiguous cases | |
| - 60-80% of requests can be handled by rules | |
| **Rule-based examples:** | |
| - "Python", "Java", "JavaScript" → programming languages | |
| - "AWS", "Azure", "GCP" → cloud platforms | |
| - "Docker", "Kubernetes" → devops tools | |
| - "Bachelor's", "Master's" → degrees | |
| **Fallback:** If rule extraction fails or confidence low, use LLM | |
| --- | |
| ### 7. Optimize Context Window ⚡ | |
| **Impact**: 5-10% speedup | **Effort**: Low | |
| **Current:** `n_ctx = 1024` | |
| **Optimized:** Dynamic based on input length | |
| **Strategy:** | |
| - Calculate input tokens | |
| - Set `n_ctx = input_tokens + _MAX_TOKENS + 100` | |
| - Minimum 512, maximum 2048 | |
| --- | |
| ### 8. Batch Processing (For Bulk Operations) ⚡⚡ | |
| **Impact**: 2-3x throughput | **Effort**: Medium | |
| **Use case:** Processing multiple job descriptions | |
| **Strategy:** | |
| - Add `/extract_batch` endpoint | |
| - Process 5-10 descriptions in parallel | |
| - Use threading with model instance lock | |
| --- | |
| ### 9. Use GPU Acceleration ⚡⚡⚡ | |
| **Impact**: 5-10x speedup | **Effort**: Low (if GPU available) | |
| **Current:** CPU-only inference | |
| **Optimized:** GPU offloading | |
| **Implementation:** | |
| - Already have `n_gpu_layers=-1` in code | |
| - Ensure CUDA-compatible llama-cpp-python is installed | |
| - If no GPU available, this has no effect | |
| **Docker changes:** | |
| ```dockerfile | |
| # Install CUDA toolkit if GPU available | |
| RUN pip install llama-cpp-python --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cu124 | |
| ``` | |
| --- | |
| ### 10. Alternative: Use vLLM or TensorRT-LLM ⚡⚡⚡ | |
| **Impact**: 2-5x speedup | **Effort**: High | |
| **Strategy:** | |
| - Replace llama-cpp-python with vLLM | |
| - Better batching, optimized inference | |
| - Requires more setup but significant speed gains | |
| **Trade-off:** More complex deployment, larger memory footprint | |
| --- | |
| ## Recommended Implementation Order | |
| ### Phase 1: Quick Wins (Total: 2-3x speedup) | |
| 1. Remove grammar constraint (20-30%) | |
| 2. Compress prompt (15-25%) | |
| 3. Reduce max tokens to 32 (10-15%) | |
| 4. Optimize context window (5-10%) | |
| **Expected result:** 15-25 seconds per request | |
| ### Phase 2: Model Change (Total: 3-5x from baseline) | |
| 5. Switch to Qwen2.5-0.5B or Phi-3-mini | |
| **Expected result:** 8-15 seconds per request | |
| ### Phase 3: Advanced Optimizations | |
| 6. Add response caching | |
| 7. Implement hybrid rule-based approach | |
| 8. Enable GPU acceleration (if available) | |
| **Expected result:** 3-8 seconds per request (with cache hits near-instant) | |
| --- | |
| ## Alternative: Non-LLM Approach | |
| ### Pure Rule-Based Extraction | |
| **Speed:** <100ms | **Accuracy:** 70-80% | |
| **Strategy:** | |
| - Build comprehensive skill taxonomy (500-1000 known skills) | |
| - Use fuzzy matching (Levenshtein, TF-IDF) | |
| - Add NLP for context (spaCy, NLTK) | |
| - No LLM required | |
| **Pros:** | |
| - Extremely fast | |
| - Predictable costs | |
| - No model management | |
| **Cons:** | |
| - Lower accuracy on novel skills | |
| - Requires manual taxonomy maintenance | |
| - Misses contextual nuances | |
| --- | |
| ## Performance Targets | |
| | Approach | Target Time | Accuracy | Effort | | |
| |----------|-------------|----------|--------| | |
| | Current | 40-60s | 85-90% | - | | |
| | Phase 1 | 15-25s | 85-90% | Low | | |
| | Phase 1+2 | 8-15s | 80-85% | Medium | | |
| | Phase 1+2+3 | 3-8s | 80-85% | High | | |
| | Hybrid | 1-5s | 75-85% | High | | |
| | Rule-based | <0.1s | 70-80% | High | | |
| --- | |
| ## Next Steps | |
| 1. **Implement Phase 1** (grammar removal, prompt compression) | |
| 2. **Test accuracy** on sample job descriptions | |
| 3. **If acceptable**, deploy and monitor | |
| 4. **If too slow**, proceed to Phase 2 (model change) | |
| 5. **Consider hybrid approach** for production scale | |