skill-extractor / OPTIMIZATION_PLAN.md
Eng-Musa's picture
optimizations
a4de6da
|
Raw
History Blame Contribute Delete
6.5 kB
# 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