fix: default spec by mode

This commit is contained in:
jialin
2025-11-03 10:14:30 +08:00
parent 7936d0063d
commit 56eba0d4fc
6 changed files with 269 additions and 60 deletions
+10 -9
View File
@@ -3,11 +3,11 @@ import { downloadFile, listFiles, listModels } from '@huggingface/hub';
import { PipelineType } from '@huggingface/tasks'; import { PipelineType } from '@huggingface/tasks';
import { request } from '@umijs/max'; import { request } from '@umijs/max';
import qs from 'query-string'; import qs from 'query-string';
import testSpecs from '../config/test';
import { import {
AccessControlFormData, AccessControlFormData,
BackendItem, BackendItem,
CatalogItem, CatalogItem,
CatalogSpec,
DraftModelItem, DraftModelItem,
EvaluateResult, EvaluateResult,
EvaluateSpec, EvaluateSpec,
@@ -370,14 +370,15 @@ export async function queryCatalogItemSpec(
params: { id: number }, params: { id: number },
options?: any options?: any
) { ) {
return await request<Global.PageResponse<CatalogSpec>>( // return await request<Global.PageResponse<CatalogSpec>>(
`/model-sets/${params.id}/specs`, // `/model-sets/${params.id}/specs`,
{ // {
method: 'GET', // method: 'GET',
...options, // ...options,
params // params
} // }
); // );
return testSpecs;
} }
export async function evaluationsModelSpec( export async function evaluationsModelSpec(
@@ -25,12 +25,28 @@ import { useCheckCompatibility } from '../hooks';
import useFormInitialValues from '../hooks/use-form-initial-values'; import useFormInitialValues from '../hooks/use-form-initial-values';
import CompatibilityAlert from './compatible-alert'; import CompatibilityAlert from './compatible-alert';
const ModesMap: Record<string, string> = {
latency: 'models.form.mode.latency',
reference: 'models.form.mode.reference',
throughput: 'models.form.mode.throughput'
};
const ModesTipsMap: Record<string, string> = {
latency: 'models.form.mode.latency.tips',
reference: 'models.form.mode.reference.tips',
throughput: 'models.form.mode.throughput.tips'
};
const pickFieldsFromSpec = [ const pickFieldsFromSpec = [
'backend_version',
'backend_parameters',
'env', 'env',
'size', 'size',
'quantization' 'source',
'quantization',
'backend_version',
'backend_parameters',
'backend',
'extended_kv_cache',
'speculative_config'
]; ];
type AddModalProps = { type AddModalProps = {
@@ -115,6 +131,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
const [quantizationOptions, setQuantizationOptions] = useState< const [quantizationOptions, setQuantizationOptions] = useState<
Global.BaseOption<string>[] Global.BaseOption<string>[]
>([]); >([]);
const [modeList, setModeList] = useState<Global.BaseOption<string>[]>([]);
const sourceGroupMap = useRef<any>({}); const sourceGroupMap = useRef<any>({});
const axiosToken = useRef<any>(null); const axiosToken = useRef<any>(null);
const selectSpecRef = useRef<CatalogSpec>({} as CatalogSpec); const selectSpecRef = useRef<CatalogSpec>({} as CatalogSpec);
@@ -167,32 +184,37 @@ const AddModal: React.FC<AddModalProps> = (props) => {
}; };
const getModelSpec = (data: { const getModelSpec = (data: {
mode?: string;
backend: string; backend: string;
size: number; size: number;
quantization: string; quantization: string;
}) => { }) => {
const spec = _.find(specListRef.current, (item: CatalogSpec) => { // const spec = _.find(specListRef.current, (item: CatalogSpec) => {
if (data.size && data.quantization) { // if (data.size && data.quantization) {
return ( // return (
item.size === data.size && // item.size === data.size &&
item.backend === data.backend && // item.backend === data.backend &&
item.quantization === data.quantization // item.quantization === data.quantization
); // );
} // }
if (data.size) { // if (data.size) {
return item.size === data.size && item.backend === data.backend; // return item.size === data.size && item.backend === data.backend;
} // }
if (data.quantization) { // if (data.quantization) {
return ( // return (
item.quantization === data.quantization && // item.quantization === data.quantization &&
item.backend === data.backend // item.backend === data.backend
); // );
} // }
return item.backend === data.backend; // return item.backend === data.backend;
}); // });
selectSpecRef.current = spec; const defaultSpec = _.find(
specListRef.current,
(item: CatalogSpec) => item.mode === data.mode
);
selectSpecRef.current = defaultSpec;
return { return {
..._.pick(spec, pickFieldsFromSpec), ..._.pick(defaultSpec, pickFieldsFromSpec),
categories: _.get(current, 'categories.0', null) categories: _.get(current, 'categories.0', null)
}; };
}; };
@@ -242,6 +264,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
}; };
}); });
const result = _.uniqBy(quantizationList, 'value'); const result = _.uniqBy(quantizationList, 'value');
console.log('quantization options:', result);
setQuantizationOptions(result); setQuantizationOptions(result);
return result; return result;
}; };
@@ -376,6 +399,16 @@ const AddModal: React.FC<AddModalProps> = (props) => {
} }
); );
const groupList = _.groupBy(res.items, 'source'); const groupList = _.groupBy(res.items, 'source');
const modes = _.groupBy(res.items, 'mode');
const modeDataList = _.map(modes, (item: CatalogSpec, key: string) => {
return {
label: ModesMap[key] || key,
isBuiltIn: ModesMap[key] ? true : false,
value: key,
tips: ModesTipsMap[key] || ''
};
});
sourceGroupMap.current = groupList; sourceGroupMap.current = groupList;
@@ -387,20 +420,21 @@ const AddModal: React.FC<AddModalProps> = (props) => {
const list = _.sortBy(res.items, 'size'); const list = _.sortBy(res.items, 'size');
console.log('spec items:', res.items);
hasF16Ref.current = _.some(res.items, (item: CatalogSpec) => { hasF16Ref.current = _.some(res.items, (item: CatalogSpec) => {
return AscendNPUQuant_F16.includes(_.toUpper(item.quantization)); return AscendNPUQuant_F16.includes(_.toUpper(item.quantization));
}); });
const defaultSpec = const defaultSpec = _.find(
_.find(list, (item: CatalogSpec) => { list,
return getDefaultQuant({ (item: CatalogSpec) => item.mode === modeDataList[0]?.value
category: _.get(current, 'categories.0', ''), );
quantOption: item.quantization,
backend: item.backend console.log('default spec:', defaultSpec);
});
}) || _.get(res.items, `0`, {});
selectSpecRef.current = defaultSpec; selectSpecRef.current = defaultSpec;
setModeList(modeDataList);
setSourceList(sources); setSourceList(sources);
handleSetBackendOptions(); handleSetBackendOptions();
handleSetSizeOptions({ handleSetSizeOptions({
@@ -472,6 +506,22 @@ const AddModal: React.FC<AddModalProps> = (props) => {
handleCheckFormData(); handleCheckFormData();
}; };
const handleOnModeChange = (val: string) => {
const data = getModelSpec({
mode: val,
backend: form.current.getFieldValue('backend'),
size: 0,
quantization: ''
});
console.log('mode change data:', data);
form.current.setFieldsValue({
...data
});
handleCheckFormData();
};
const handleOk = async (values: FormData) => { const handleOk = async (values: FormData) => {
const data = { const data = {
..._.omit(selectSpecRef.current, ['name']), ..._.omit(selectSpecRef.current, ['name']),
@@ -542,6 +592,8 @@ const AddModal: React.FC<AddModalProps> = (props) => {
value={{ value={{
sizeOptions: [], sizeOptions: [],
quantizationOptions: [], quantizationOptions: [],
modeList: modeList,
onModeChange: handleOnModeChange,
onSizeChange: handleOnSizeChange, onSizeChange: handleOnSizeChange,
onQuantizationChange: handleOnQuantizationChange onQuantizationChange: handleOnQuantizationChange
}} }}
@@ -30,6 +30,8 @@ interface FormContextProps {
interface CatalogFormContextProps { interface CatalogFormContextProps {
sizeOptions: Global.BaseOption<number>[]; sizeOptions: Global.BaseOption<number>[];
quantizationOptions: Global.BaseOption<string>[]; quantizationOptions: Global.BaseOption<string>[];
modeList: Global.BaseOption<string & { isBuiltIn: boolean; tips: string }>[];
onModeChange: (val: string) => void;
onSizeChange: (val: number) => void; onSizeChange: (val: number) => void;
onQuantizationChange: (val: string) => void; onQuantizationChange: (val: string) => void;
} }
+138
View File
@@ -0,0 +1,138 @@
export default {
items: [
{
source: 'model_scope',
huggingface_repo_id: null,
huggingface_filename: null,
ollama_library_model_name: null,
model_scope_model_id: 'Qwen/Qwen3-30B-A3B-FP8',
model_scope_file_path: null,
local_path: null,
name: null,
description: null,
meta: {},
replicas: 1,
ready_replicas: 0,
categories: [],
embedding_only: false,
image_only: false,
reranker: false,
speech_to_text: false,
text_to_speech: false,
placement_strategy: 'spread',
cpu_offloading: false,
distributed_inference_across_workers: false,
worker_selector: {},
gpu_selector: null,
backend: 'SGLang',
backend_version: null,
backend_parameters: [
'--reasoning-parser=qwen3',
'--tool-call-parser=qwen25'
],
image_name: null,
run_command: null,
env: null,
restart_on_error: true,
distributable: false,
extended_kv_cache: null,
speculative_config: null,
quantization: 'FP8',
mode: 'throughput'
},
{
source: 'model_scope',
huggingface_repo_id: null,
huggingface_filename: null,
ollama_library_model_name: null,
model_scope_model_id: 'Qwen/Qwen3-30B-A3B-FP8',
model_scope_file_path: null,
local_path: null,
name: null,
description: null,
meta: {},
replicas: 1,
ready_replicas: 0,
categories: [],
embedding_only: false,
image_only: false,
reranker: false,
speech_to_text: false,
text_to_speech: false,
placement_strategy: 'spread',
cpu_offloading: false,
distributed_inference_across_workers: false,
worker_selector: {},
gpu_selector: null,
backend: 'SGLang',
backend_version: null,
backend_parameters: [
'--reasoning-parser=qwen3',
'--tool-call-parser=qwen25',
'--speculative-algorithm=EAGLE3',
'--speculative-draft-model-path=Tengyunw/qwen3_30b_moe_eagle3',
'--speculative-num-steps=6',
'--speculative-eagle-topk=10',
'--speculative-num-draft-tokens=32'
],
image_name: null,
run_command: null,
env: null,
restart_on_error: true,
distributable: false,
extended_kv_cache: null,
speculative_config: {
enabled: true,
algorithm: 'eagle3',
draft_model_name: 'Qwen3-30B-A3B-EAGLE3',
num_draft_tokens: 8,
ngram_min_match_length: null,
ngram_max_match_length: null
},
quantization: 'FP8',
mode: 'latency'
},
{
source: 'model_scope',
huggingface_repo_id: null,
huggingface_filename: null,
ollama_library_model_name: null,
model_scope_model_id: 'Qwen/Qwen3-30B-A3B',
model_scope_file_path: null,
local_path: null,
name: null,
description: null,
meta: {},
replicas: 1,
ready_replicas: 0,
categories: [],
embedding_only: false,
image_only: false,
reranker: false,
speech_to_text: false,
text_to_speech: false,
placement_strategy: 'spread',
cpu_offloading: false,
distributed_inference_across_workers: true,
worker_selector: {},
gpu_selector: null,
backend: 'vLLM',
backend_version: null,
backend_parameters: [
'--tool-call-parser=hermes',
'--enable-auto-tool-choice',
'--max-model-len=32768'
],
image_name: null,
run_command: null,
env: null,
restart_on_error: true,
distributable: false,
extended_kv_cache: null,
speculative_config: null,
quantization: 'BF16',
mode: 'reference'
}
],
pagination: { page: 1, perPage: 100, total: 3, totalPage: 1 }
};
+15
View File
@@ -198,12 +198,27 @@ export interface CatalogSpec {
categories: any[]; categories: any[];
placement_strategy: string; placement_strategy: string;
cpu_offloading: boolean; cpu_offloading: boolean;
mode: string;
distributed_inference_across_workers: boolean; distributed_inference_across_workers: boolean;
worker_selector: Record<string, any>; worker_selector: Record<string, any>;
gpu_selector: { gpu_selector: {
gpu_ids: string[]; gpu_ids: string[];
gpus_per_replica: number; gpus_per_replica: number;
}; };
extended_kv_cache: {
enabled: boolean;
chunk_size: number;
max_local_cpu_size: number;
remote_url: string;
};
speculative_config: {
enabled: boolean;
algorithm: string;
draft_model_name: string;
num_draft_tokens: number;
ngram_min_match_length: number;
ngram_max_match_length: number;
};
backend: string; backend: string;
backend_version: string; backend_version: string;
backend_parameters: any[]; backend_parameters: any[];
+20 -19
View File
@@ -1,10 +1,11 @@
import AutoTooltip from '@/components/auto-tooltip';
import SealSelect from '@/components/seal-form/seal-select'; import SealSelect from '@/components/seal-form/seal-select';
import TooltipList from '@/components/tooltip-list'; import TooltipList from '@/components/tooltip-list';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Form } from 'antd'; import { Form, Select } from 'antd';
import React from 'react'; import React from 'react';
import { deployFormKeyMap } from '../config'; import { deployFormKeyMap } from '../config';
import { useFormContext } from '../config/form-context'; import { useCatalogFormContext, useFormContext } from '../config/form-context';
import KVCacheForm from './kv-cache'; import KVCacheForm from './kv-cache';
import SpeculativeDecode from './speculative-decode'; import SpeculativeDecode from './speculative-decode';
@@ -36,6 +37,7 @@ const Performance: React.FC = () => {
const intl = useIntl(); const intl = useIntl();
const form = Form.useFormInstance(); const form = Form.useFormInstance();
const { formKey } = useFormContext(); const { formKey } = useFormContext();
const { modeList, onModeChange } = useCatalogFormContext();
return ( return (
<> <>
@@ -43,25 +45,24 @@ const Performance: React.FC = () => {
{formKey === deployFormKeyMap.catalog && ( {formKey === deployFormKeyMap.catalog && (
<Form.Item name="mode"> <Form.Item name="mode">
<SealSelect <SealSelect
onChange={onModeChange}
description={<TooltipList list={modeTipsList}></TooltipList>} description={<TooltipList list={modeTipsList}></TooltipList>}
label={intl.formatMessage({ id: 'models.form.mode' })} label={intl.formatMessage({ id: 'models.form.mode' })}
options={[ >
{ {modeList.map((item: any) => (
label: intl.formatMessage({ <Select.Option key={item.value} value={item.value}>
id: 'models.form.mode.throughput' <AutoTooltip
}), showTitle={item.isBuiltIn}
value: 'throughput' ghost
}, title={intl.formatMessage({ id: item.tips })}
{ >
label: intl.formatMessage({ id: 'models.form.mode.latency' }), {item.isBuiltIn
value: 'latency' ? intl.formatMessage({ id: item.label })
}, : item.label}
{ </AutoTooltip>
label: intl.formatMessage({ id: 'models.form.mode.reference' }), </Select.Option>
value: 'reference' ))}
} </SealSelect>
]}
></SealSelect>
</Form.Item> </Form.Item>
)} )}
<KVCacheForm></KVCacheForm> <KVCacheForm></KVCacheForm>