Skip to content

Commit db323a5

Browse files
authored
refactor(config): move reasoning fields from Category to ModelScore (#414)
* refactor(config): move reasoning fields from Category to ModelScore Move ReasoningDescription and ReasoningEffort from Category level to ModelScore level to enable model-specific reasoning configuration. **What type of PR is this?** [Refactoring / Breaking Change] **What this PR does / why we need it**: This PR refactors the reasoning configuration structure by moving and fields from the Category level to the ModelScore level. This change enables more granular control over reasoning behavior at the model level rather than the category level. **Key Changes:** - Remove and from struct - These fields now exist in struct (model-level configuration) - Update to accept parameter - Update all configuration files to new format (9 files) - Update Python training scripts to generate new format - Update TypeScript dashboard to read from best model - Update all test files **Breaking Change:** This is a breaking change with no backward compatibility. Old configuration files must be migrated to the new format. **Migration:** Old format: ```yaml categories: - name: math reasoning_description: "..." reasoning_effort: high model_scores: - model: model-a use_reasoning: true ``` New format: ```yaml categories: - name: math model_scores: - model: model-a use_reasoning: true reasoning_description: "..." reasoning_effort: high ``` **Testing:** - All Go tests pass - All configuration files validated - TypeScript type checking passes Signed-off-by: Xunzhuo <[email protected]> Signed-off-by: bitliu <[email protected]> * fix(test): move ReasoningEffort to ModelScore in classification test Update generic_category_mapping_test.go to use the new structure where reasoning_effort is a field of ModelScore instead of Category. Signed-off-by: Xunzhuo <[email protected]> Signed-off-by: bitliu <[email protected]> --------- Signed-off-by: Xunzhuo <[email protected]> Signed-off-by: bitliu <[email protected]>
1 parent 4963c3d commit db323a5

File tree

9 files changed

+123
-143
lines changed

9 files changed

+123
-143
lines changed

config/config.e2e.yaml

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -86,187 +86,175 @@ classifier:
8686
pii_mapping_path: "models/pii_classifier_modernbert-base_presidio_token_model/pii_type_mapping.json"
8787
categories:
8888
- name: business
89-
use_reasoning: false
90-
reasoning_description: "Business content is typically conversational"
91-
reasoning_effort: low # Business conversations need low reasoning effort
9289
model_scores:
9390
- model: "Model-A"
9491
score: 0.8
9592
use_reasoning: false
93+
reasoning_description: "Business content is typically conversational"
94+
reasoning_effort: low
9695
- model: "Model-B"
9796
score: 0.4
9897
use_reasoning: false
9998
- model: "Model-A"
10099
score: 0.2
101100
use_reasoning: false
102101
- name: law
103-
use_reasoning: false
104-
reasoning_description: "Legal content is typically explanatory"
105102
model_scores:
106103
- model: "Model-B"
107104
score: 0.8
108105
use_reasoning: false
106+
reasoning_description: "Legal content is typically explanatory"
109107
- model: "Model-A"
110108
score: 0.6
111109
use_reasoning: false
112110
- model: "Model-A"
113111
score: 0.4
114112
use_reasoning: false
115113
- name: psychology
116-
use_reasoning: false
117-
reasoning_description: "Psychology content is usually explanatory"
118114
model_scores:
119115
- model: "Model-A"
120116
score: 0.6
121117
use_reasoning: false
118+
reasoning_description: "Psychology content is usually explanatory"
122119
- model: "Model-B"
123120
score: 0.4
124121
use_reasoning: false
125122
- model: "Model-A"
126123
score: 0.4
127124
use_reasoning: false
128125
- name: biology
129-
use_reasoning: true
130-
reasoning_description: "Biological processes benefit from structured analysis"
131126
model_scores:
132127
- model: "Model-A"
133128
score: 0.8
134129
use_reasoning: false
130+
reasoning_description: "Biological processes benefit from structured analysis"
135131
- model: "Model-B"
136132
score: 0.6
137133
use_reasoning: false
138134
- model: "Model-A"
139135
score: 0.2
140136
use_reasoning: false
141137
- name: chemistry
142-
use_reasoning: true
143-
reasoning_description: "Chemical reactions and formulas require systematic thinking"
144-
reasoning_effort: high # Chemistry requires high reasoning effort
145138
model_scores:
146139
- model: "Model-A"
147140
score: 0.8
148141
use_reasoning: true
142+
reasoning_description: "Chemical reactions and formulas require systematic thinking"
143+
reasoning_effort: high
149144
- model: "Model-B"
150145
score: 0.6
151146
use_reasoning: false
152147
- model: "Model-A"
153148
score: 0.6
154149
use_reasoning: false
155150
- name: history
156-
use_reasoning: false
157-
reasoning_description: "Historical content is narrative-based"
158151
model_scores:
159152
- model: "Model-A"
160153
score: 0.8
161154
use_reasoning: false
155+
reasoning_description: "Historical content is narrative-based"
162156
- model: "Model-A"
163157
score: 0.6
164158
use_reasoning: false
165159
- model: "Model-B"
166160
score: 0.4
167161
use_reasoning: false
168162
- name: other
169-
use_reasoning: false
170-
reasoning_description: "General content doesn't require reasoning"
171163
model_scores:
172164
- model: "Model-B"
173165
score: 0.8
174166
use_reasoning: false
167+
reasoning_description: "General content doesn't require reasoning"
175168
- model: "Model-A"
176169
score: 0.6
177170
use_reasoning: false
178171
- model: "Model-A"
179172
score: 0.6
180173
use_reasoning: false
181174
- name: health
182-
use_reasoning: false
183-
reasoning_description: "Health information is typically informational"
184175
model_scores:
185176
- model: "Model-B"
186177
score: 0.8
187178
use_reasoning: false
179+
reasoning_description: "Health information is typically informational"
188180
- model: "Model-A"
189181
score: 0.8
190182
use_reasoning: false
191183
- model: "Model-A"
192184
score: 0.6
193185
use_reasoning: false
194186
- name: economics
195-
use_reasoning: false
196-
reasoning_description: "Economic discussions are usually explanatory"
197187
model_scores:
198188
- model: "Model-B"
199189
score: 0.8
200190
use_reasoning: false
191+
reasoning_description: "Economic discussions are usually explanatory"
201192
- model: "Model-A"
202193
score: 0.8
203194
use_reasoning: false
204195
- model: "Model-A"
205196
score: 0.1
206197
use_reasoning: false
207198
- name: math
208-
use_reasoning: true
209-
reasoning_description: "Mathematical problems require step-by-step reasoning"
210-
reasoning_effort: high # Math problems need high reasoning effort
211199
model_scores:
212200
- model: "Model-B"
213201
score: 1.0
214202
use_reasoning: true
203+
reasoning_description: "Mathematical problems require step-by-step reasoning"
204+
reasoning_effort: high
215205
- model: "Model-A"
216206
score: 0.9
217207
use_reasoning: true
208+
reasoning_description: "Mathematical problems require step-by-step reasoning"
209+
reasoning_effort: high
218210
- model: "Model-A"
219211
score: 0.8
220212
use_reasoning: false
221213
- model: "Model-B"
222214
score: 0.6
223215
use_reasoning: false
224216
- name: physics
225-
use_reasoning: true
226-
reasoning_description: "Physics concepts need logical analysis"
227217
model_scores:
228218
- model: "Model-B"
229219
score: 0.4
230220
use_reasoning: true
221+
reasoning_description: "Physics concepts need logical analysis"
231222
- model: "Model-A"
232223
score: 0.4
233224
use_reasoning: false
234225
- model: "Model-A"
235226
score: 0.4
236227
use_reasoning: false
237228
- name: computer science
238-
use_reasoning: true
239-
reasoning_description: "Programming and algorithms need logical reasoning"
240229
model_scores:
241230
- model: "Model-B"
242231
score: 0.6
243232
use_reasoning: false
233+
reasoning_description: "Programming and algorithms need logical reasoning"
244234
- model: "Model-A"
245235
score: 0.6
246236
use_reasoning: false
247237
- model: "Model-A"
248238
score: 0.1
249239
use_reasoning: false
250240
- name: philosophy
251-
use_reasoning: false
252-
reasoning_description: "Philosophical discussions are conversational"
253241
model_scores:
254242
- model: "Model-A"
255243
score: 0.6
256244
use_reasoning: false
245+
reasoning_description: "Philosophical discussions are conversational"
257246
- model: "Model-B"
258247
score: 0.2
259248
use_reasoning: false
260249
- model: "Model-A"
261250
score: 0.2
262251
use_reasoning: false
263252
- name: engineering
264-
use_reasoning: true
265-
reasoning_description: "Engineering problems require systematic problem-solving"
266253
model_scores:
267254
- model: "Model-B"
268255
score: 0.6
269256
use_reasoning: false
257+
reasoning_description: "Engineering problems require systematic problem-solving"
270258
- model: "Model-A"
271259
score: 0.6
272260
use_reasoning: false

dashboard/frontend/src/pages/ConfigPage.tsx

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,13 @@ interface ModelScore {
3838
model: string
3939
score: number
4040
use_reasoning: boolean
41+
reasoning_description?: string
42+
reasoning_effort?: string
4143
}
4244

4345
interface Category {
4446
name: string
4547
system_prompt?: string
46-
use_reasoning: boolean
47-
reasoning_description: string
48-
reasoning_effort: string
4948
model_scores: ModelScore[]
5049
}
5150

@@ -1408,14 +1407,21 @@ const ConfigPage: React.FC<ConfigPageProps> = ({ activeSection = 'models' }) =>
14081407

14091408
{config?.categories && config.categories.length > 0 ? (
14101409
<div className={styles.categoryGridTwoColumn}>
1411-
{config.categories.map((category, index) => (
1410+
{config.categories.map((category, index) => {
1411+
// Get reasoning info from best model (first model score)
1412+
const bestModel = category.model_scores?.[0]
1413+
const useReasoning = bestModel?.use_reasoning || false
1414+
const reasoningEffort = bestModel?.reasoning_effort || 'medium'
1415+
const reasoningDescription = bestModel?.reasoning_description || ''
1416+
1417+
return (
14121418
<div key={index} className={styles.categoryCard}>
14131419
<div className={styles.categoryHeader}>
14141420
<span className={styles.categoryName}>{category.name}</span>
14151421
<div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
1416-
{category.use_reasoning && (
1417-
<span className={`${styles.reasoningBadge} ${styles[`reasoning${category.reasoning_effort}`]}`}>
1418-
{category.reasoning_effort}
1422+
{useReasoning && (
1423+
<span className={`${styles.reasoningBadge} ${styles[`reasoning${reasoningEffort}`]}`}>
1424+
{reasoningEffort}
14191425
</span>
14201426
)}
14211427
<button
@@ -1424,10 +1430,7 @@ const ConfigPage: React.FC<ConfigPageProps> = ({ activeSection = 'models' }) =>
14241430
openEditModal(
14251431
`Edit Category: ${category.name}`,
14261432
{
1427-
system_prompt: category.system_prompt || '',
1428-
use_reasoning: category.use_reasoning || false,
1429-
reasoning_effort: category.reasoning_effort || 'medium',
1430-
reasoning_description: category.reasoning_description || ''
1433+
system_prompt: category.system_prompt || ''
14311434
},
14321435
[
14331436
{
@@ -1436,26 +1439,6 @@ const ConfigPage: React.FC<ConfigPageProps> = ({ activeSection = 'models' }) =>
14361439
type: 'textarea',
14371440
placeholder: 'Enter system prompt for this category...',
14381441
description: 'Instructions for the model when handling this category'
1439-
},
1440-
{
1441-
name: 'use_reasoning',
1442-
label: 'Use Reasoning',
1443-
type: 'boolean',
1444-
description: 'Enable reasoning for this category'
1445-
},
1446-
{
1447-
name: 'reasoning_effort',
1448-
label: 'Reasoning Effort',
1449-
type: 'select',
1450-
options: ['low', 'medium', 'high'],
1451-
description: 'Computational effort level for reasoning'
1452-
},
1453-
{
1454-
name: 'reasoning_description',
1455-
label: 'Reasoning Description',
1456-
type: 'textarea',
1457-
placeholder: 'Describe the reasoning approach...',
1458-
description: 'Description of how reasoning is applied'
14591442
}
14601443
],
14611444
async (data) => {
@@ -1484,7 +1467,9 @@ const ConfigPage: React.FC<ConfigPageProps> = ({ activeSection = 'models' }) =>
14841467
</div>
14851468
)}
14861469

1487-
<p className={styles.categoryDescription}>{category.reasoning_description}</p>
1470+
{reasoningDescription && (
1471+
<p className={styles.categoryDescription}>{reasoningDescription}</p>
1472+
)}
14881473

14891474
<div className={styles.categoryModels}>
14901475
<div className={styles.categoryModelsHeader}>
@@ -1635,7 +1620,7 @@ const ConfigPage: React.FC<ConfigPageProps> = ({ activeSection = 'models' }) =>
16351620
)}
16361621
</div>
16371622
</div>
1638-
))}
1623+
)})}
16391624
</div>
16401625
) : (
16411626
<div className={styles.emptyState}>No categories configured</div>

src/semantic-router/pkg/config/config.go

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -332,18 +332,18 @@ func (c *RouterConfig) GetCacheSimilarityThreshold() float32 {
332332

333333
// ModelScore associates an LLM with its selection weight and reasoning flag within a category.
334334
type ModelScore struct {
335-
Model string `yaml:"model"`
336-
Score float64 `yaml:"score"`
337-
UseReasoning *bool `yaml:"use_reasoning"` // Pointer to detect missing field
335+
Model string `yaml:"model"`
336+
Score float64 `yaml:"score"`
337+
UseReasoning *bool `yaml:"use_reasoning"` // Pointer to detect missing field
338+
ReasoningDescription string `yaml:"reasoning_description,omitempty"` // Model-specific reasoning description
339+
ReasoningEffort string `yaml:"reasoning_effort,omitempty"` // Model-specific reasoning effort level (low, medium, high)
338340
}
339341

340342
// Category represents a category for routing queries
341343
type Category struct {
342-
Name string `yaml:"name"`
343-
Description string `yaml:"description,omitempty"`
344-
ReasoningDescription string `yaml:"reasoning_description,omitempty"`
345-
ReasoningEffort string `yaml:"reasoning_effort,omitempty"` // Configurable reasoning effort level (low, medium, high)
346-
ModelScores []ModelScore `yaml:"model_scores"`
344+
Name string `yaml:"name"`
345+
Description string `yaml:"description,omitempty"`
346+
ModelScores []ModelScore `yaml:"model_scores"`
347347
// MMLUCategories optionally maps this generic category to one or more MMLU-Pro categories
348348
// used by the classifier model. When provided, classifier outputs will be translated
349349
// from these MMLU categories to this generic category name.
@@ -359,8 +359,6 @@ type Category struct {
359359
SystemPromptMode string `yaml:"system_prompt_mode,omitempty"`
360360
}
361361

362-
// Legacy types - can be removed once migration is complete
363-
364362
// GetModelReasoningFamily returns the reasoning family configuration for a given model name
365363
func (rc *RouterConfig) GetModelReasoningFamily(modelName string) *ReasoningFamilyConfig {
366364
if rc == nil || rc.ModelConfig == nil || rc.ReasoningFamilies == nil {
@@ -382,18 +380,6 @@ func (rc *RouterConfig) GetModelReasoningFamily(modelName string) *ReasoningFami
382380
return &familyConfig
383381
}
384382

385-
// Legacy functions - can be removed once migration is complete
386-
387-
// contains checks if a slice contains a string
388-
func contains(slice []string, item string) bool {
389-
for _, s := range slice {
390-
if s == item {
391-
return true
392-
}
393-
}
394-
return false
395-
}
396-
397383
var (
398384
config *RouterConfig
399385
configOnce sync.Once

0 commit comments

Comments
 (0)