File size: 7,297 Bytes
7a2795f
0bfc45c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7a2795f
0bfc45c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
---
language:
- en
license: mit
library_name: catboost
pipeline_tag: text-classification
tags:
- prompt-routing
- llm-routing
- multi-label-classification
- prompt-complexity
- catboost
- scikit-learn
- model-router
- token-budgeting
pretty_name: Prompt Router (CatBoost Multi-Label Classifier)
datasets:
- Nasim435/Multi-label-Prompt-Dataset
---

# Multi-Label Prompt Classifier

A fast, lightweight multi-label machine learning model designed for prompt complexity estimation, task intent classification, output token length forecasting, and dynamic LLM routing. The model executes inference in **< 10ms on CPU** with **zero GPU dependencies**.

## Model Summary

- **Architecture**: Scikit-Learn `OneVsRestClassifier` ensemble of 23 binary `CatBoostClassifier` estimators
- **Feature Pipeline**: 5,000 TF-IDF features (unigram + bigram) combined with 19 handcrafted structural/semantic text features
- **Number of Target Classes**: 23 multi-label categories across 4 semantic dimensions
- **Inference Latency**: < 10ms per prompt on standard CPU
- **Memory Footprint**: ~13 MB model weights
- **Primary Use Case**: Classifying raw user prompts to route them to the most cost-effective LLM tier and enforce pre-inference token budgets without calling an auxiliary LLM.

## Model Files & Artifacts

The repository contains four serialized artifacts:

| File | Size | Description |
|:---|:---:|:---|
| **`feature_extractor.pkl`** | 211 KB | Scikit-Learn transformer pipeline combining 5,000 TF-IDF n-gram features with 19 structural heuristics (sentence count, code blocks, math symbols, domain keywords). |
| **`prompt_router.pkl`** | 13.0 MB | Trained `OneVsRestClassifier` wrapping 23 individual `CatBoostClassifier` models (iterations=300, depth=6, learning_rate=0.1). |
| **`label_binarizer.pkl`** | 826 B | Fitted Scikit-Learn `MultiLabelBinarizer` mapping categorical label names to binary arrays. |
| **`thresholds.npy`** | 312 B | Optimal decision threshold matrix ($t_{\text{opt}}$) tuned per class to maximize individual F1 scores. |

## Target Classes (23 Multi-Label Tags)

The model predicts across 23 categorical dimensions simultaneously:

1. **Complexity Tier**: `easy`, `moderate`, `hard`
2. **Reasoning Depth**: `reasoning-light`, `reasoning-moderate`, `reasoning-intensive`
3. **Expected Output Token Length**: `short-output` ($\le 200$), `medium-output` ($\approx 500$), `long-output` ($\ge 1,200$)
4. **Execution Priority & Compute Tier**: `cheap`, `balanced`, `premium`, `realtime`, `interactive`, `background`
5. **Task & Domain Intent**: `coding`, `debugging`, `infrastructure`, `architecture`, `architecture-heavy`, `mlops`, `analysis`, `research`

## Evaluation & Benchmark Performance

Evaluated on an independent 20% holdout test set (372 samples):

| Metric | Baseline ($t=0.50$) | Tuned Thresholds ($t=t_{\text{opt}}$) | Relative Change |
|:---|:---:|:---:|:---:|
| **Macro F1 Score** | **0.8094** | **0.8320** | **+2.79%** |
| **Micro F1 Score** | **0.8282** | **0.8419** | **+1.65%** |
| **Weighted F1 Score** | **0.8300** | **0.8447** | **+1.77%** |
| **Hamming Loss** | **0.0907** | **0.0840** | **-7.39% (Lower is better)** |
| **Inference Latency** | **< 10ms** | **< 10ms** | **CPU Real-Time** |

### Per-Class Evaluation Breakdown

| Label | Precision | Recall | F1-Score | Optimal Threshold ($t_{\text{opt}}$) | Test Support |
|:---|:---:|:---:|:---:|:---:|:---:|
| `architecture-heavy` | 1.00 | 0.90 | **0.95** | 0.40 | 29 |
| `interactive` | 0.91 | 0.98 | **0.94** | 0.35 | 230 |
| `mlops` | 1.00 | 0.85 | **0.92** | 0.45 | 27 |
| `hard` | 0.92 | 0.90 | **0.91** | 0.50 | 136 |
| `reasoning-intensive` | 0.92 | 0.90 | **0.91** | 0.50 | 136 |
| `realtime` | 0.90 | 0.92 | **0.91** | 0.40 | 48 |
| `background` | 0.93 | 0.85 | **0.89** | 0.55 | 91 |
| `long-output` | 0.94 | 0.86 | **0.89** | 0.55 | 104 |
| `premium` | 0.84 | 0.93 | **0.88** | 0.40 | 114 |
| `medium-output` | 0.85 | 0.92 | **0.88** | 0.40 | 177 |
| `debugging` | 0.90 | 0.80 | **0.85** | 0.50 | 46 |
| `short-output` | 0.86 | 0.81 | **0.84** | 0.50 | 91 |
| `coding` | 0.77 | 0.90 | **0.83** | 0.40 | 105 |
| `easy` | 0.88 | 0.77 | **0.82** | 0.55 | 96 |
| `reasoning-light` | 0.88 | 0.76 | **0.82** | 0.55 | 96 |
| `cheap` | 0.82 | 0.79 | **0.80** | 0.50 | 90 |
| `balanced` | 0.75 | 0.83 | **0.79** | 0.45 | 122 |
| `moderate` | 0.67 | 0.89 | **0.77** | 0.35 | 140 |
| `reasoning-moderate` | 0.65 | 0.92 | **0.76** | 0.35 | 140 |
| `research` | 0.71 | 0.77 | **0.74** | 0.45 | 22 |
| `infrastructure` | 0.62 | 0.83 | **0.71** | 0.35 | 77 |
| `analysis` | 0.56 | 0.85 | **0.68** | 0.35 | 41 |
| `architecture` | 0.80 | 0.56 | **0.66** | 0.55 | 43 |

## Quick Start & Inference

### Installation

```bash
pip install catboost scikit-learn numpy pandas joblib scipy
```

### Loading and Predicting

```python
import joblib
import numpy as np
import pandas as pd

# 1. Load serialized artifacts
feature_extractor = joblib.load("feature_extractor.pkl")
classifier        = joblib.load("prompt_router.pkl")
mlb               = joblib.load("label_binarizer.pkl")
thresholds        = np.load("thresholds.npy")

def predict_prompt_labels(prompt: str, return_scores: bool = False):
    # Transform input text into combined TF-IDF + structural feature matrix
    X = feature_extractor.transform(pd.Series([prompt]))
    
    # Predict probabilities for each binary classifier in the ensemble
    probs = np.array(classifier.predict_proba(X))
    scores = np.array([p[0][1] if np.ndim(p) == 2 else p[1] for p in probs])
    
    # Apply calibrated decision thresholds
    predictions = (scores >= thresholds).astype(int)
    
    # Fallback to top-scoring class if no threshold is met
    if predictions.sum() == 0:
        predictions[np.argmax(scores)] = 1
        
    labels = list(mlb.inverse_transform(predictions.reshape(1, -1))[0])
    
    if return_scores:
        score_dict = {label: round(float(score), 4) for label, score in zip(mlb.classes_, scores)}
        return labels, score_dict
        
    return labels

# Example usage
query = "Design a distributed real-time fraud detection pipeline with Apache Flink and Kafka."
labels, scores = predict_prompt_labels(query, return_scores=True)
print("Predicted labels:", labels)
# Output: ['architecture-heavy', 'hard', 'infrastructure', 'interactive', 'long-output', 'premium', 'realtime', 'reasoning-intensive']
```

## Intended Use & Integration

- **LLM Routing Middleware**: Classify incoming prompts to route between small/nano (e.g. 8B–9B), medium (e.g. 30B–70B), and large/frontier (e.g. 120B–405B) models.
- **Pre-Inference Token Budgeting**: Forecast expected output token lengths (`short-output`, `medium-output`, `long-output`) before generation to prevent token overspend.
- **Domain Specialization**: Direct code queries to coding models, debugging queries to specialized debug agents, and theoretical research questions to reasoning models.

## Limitations

- **Domain Scope**: The training dataset focuses on technical engineering prompts (software engineering, cloud infrastructure, mathematics, algorithms). Predictions on general casual conversation or creative fiction may be less accurate.
- **Language**: English prompts only (`language: en`).

## License

This model is distributed under the **MIT License**.