From df65d3e2f67059123ebf43644e39488b1dfa526f Mon Sep 17 00:00:00 2001 From: jialin Date: Mon, 27 Oct 2025 13:13:37 +0800 Subject: [PATCH] fix: kv cache support in builtin backend --- config/routes.ts | 18 ++++----- src/atoms/models.ts | 1 + src/components/seal-form/checkbox-field.tsx | 18 +++++---- src/locales/en-US/models.ts | 8 +++- src/locales/ja-JP/models.ts | 12 +++++- src/locales/ru-RU/models.ts | 11 ++++- src/locales/zh-CN/models.ts | 8 +++- src/pages/backends/components/import-yaml.tsx | 4 +- src/pages/backends/config/index.ts | 16 +++----- .../config/schema/update-builtin.json | 4 +- .../config/backend-parameters/index.ts | 6 ++- src/pages/llmodels/config/types.ts | 2 + src/pages/llmodels/forms/index.tsx | 15 +++++++ src/pages/llmodels/forms/kv-cache.tsx | 40 ++++++++++++++++++- .../llmodels/hooks/use-query-backends.ts | 1 + 15 files changed, 124 insertions(+), 40 deletions(-) diff --git a/config/routes.ts b/config/routes.ts index c26a047f..400e0cdd 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -135,15 +135,6 @@ export default [ defaultIcon: 'icon-gpu1', component: './resources/components/gpus' }, - { - name: 'modelfiles', - path: '/resources/modelfiles', - key: 'modelfiles', - icon: 'icon-files', - selectedIcon: 'icon-files-filled', - defaultIcon: 'icon-files', - component: './resources/components/model-files' - }, { name: 'backendsList', path: '/resources/backends', @@ -153,6 +144,15 @@ export default [ defaultIcon: 'icon-backend', access: 'canSeeAdmin', component: './backends/index' + }, + { + name: 'modelfiles', + path: '/resources/modelfiles', + key: 'modelfiles', + icon: 'icon-files', + selectedIcon: 'icon-files-filled', + defaultIcon: 'icon-files', + component: './resources/components/model-files' } ] }, diff --git a/src/atoms/models.ts b/src/atoms/models.ts index 5a5e53cc..b4bc1a42 100644 --- a/src/atoms/models.ts +++ b/src/atoms/models.ts @@ -30,6 +30,7 @@ export const backendOptionsAtom = atom< label: string; default_backend_param: string[]; default_version: string; + isBuiltIn: boolean; versions: { label: string; value: string }[]; }[] >([]); diff --git a/src/components/seal-form/checkbox-field.tsx b/src/components/seal-form/checkbox-field.tsx index b215fef2..65c9851a 100644 --- a/src/components/seal-form/checkbox-field.tsx +++ b/src/components/seal-form/checkbox-field.tsx @@ -1,16 +1,18 @@ import { QuestionCircleOutlined } from '@ant-design/icons'; -import { Checkbox, Tooltip } from 'antd'; +import { Checkbox, CheckboxProps, Tooltip } from 'antd'; import { CheckboxChangeEvent } from 'antd/es/checkbox'; import React from 'react'; -const CheckboxField: React.FC<{ - description?: React.ReactNode; - label: React.ReactNode; - checked?: boolean; - onChange?: (e: CheckboxChangeEvent) => void; -}> = ({ description, label, checked, onChange }) => { +const CheckboxField: React.FC< + { + description?: React.ReactNode; + label: React.ReactNode; + checked?: boolean; + onChange?: (e: CheckboxChangeEvent) => void; + } & CheckboxProps +> = ({ description, label, checked, onChange, ...rest }) => { return ( - + {label} {!!description && ( diff --git a/src/locales/en-US/models.ts b/src/locales/en-US/models.ts index 33321e70..a458ed62 100644 --- a/src/locales/en-US/models.ts +++ b/src/locales/en-US/models.ts @@ -187,6 +187,8 @@ export default { 'models.form.chunkSize': 'Size Of Cache Chunks', 'models.form.maxCPUSize': 'Maximum CPU Cache Size (GiB)', 'models.form.remoteURL': 'Remote Storage URL', + 'models.form.remoteURL.tips': + 'Refer to the configuration documentation for details.', 'models.form.runCommandPlaceholder': 'e.g., vllm serve Qwen/Qwen2.5-1.5B-Instruct', 'models.accessSettings.public': 'Public', @@ -206,5 +208,9 @@ export default { 'You can specify the exact number of GPUs per replica.', 'models.mymodels.status.inactive': 'Stopped', 'models.mymodels.status.degrade': 'Abnormal', - 'models.mymodels.status.active': 'Active' + 'models.mymodels.status.active': 'Active', + 'models.form.kvCache.tips': + 'Available only with built-in backends (vLLM / SGLang) — switch backend in Advanced to enable.', + 'models.form.kvCache.tips2': + 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).' }; diff --git a/src/locales/ja-JP/models.ts b/src/locales/ja-JP/models.ts index b3e4ab59..4dfca12e 100644 --- a/src/locales/ja-JP/models.ts +++ b/src/locales/ja-JP/models.ts @@ -184,6 +184,8 @@ export default { 'models.form.chunkSize': 'Size Of Cache Chunks', 'models.form.maxCPUSize': 'Maximum CPU Cache Size (GiB)', 'models.form.remoteURL': 'Remote Storage URL', + 'models.form.remoteURL.tips': + 'Refer to the configuration documentation for details.', 'models.form.runCommandPlaceholder': 'e.g., vllm serve Qwen/Qwen2.5-1.5B-Instruct', 'models.accessSettings.public': 'Public', @@ -203,7 +205,11 @@ export default { 'You can specify the exact number of GPUs per replica.', 'models.mymodels.status.inactive': 'Stopped', 'models.mymodels.status.degrade': 'Abnormal', - 'models.mymodels.status.active': 'Active' + 'models.mymodels.status.active': 'Active', + 'models.form.kvCache.tips': + 'Available only with built-in backends (vLLM / SGLang) — switch backend in Advanced to enable.', + 'models.form.kvCache.tips2': + 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).' }; // ========== To-Do: Translate Keys (Remove After Translation) ========== @@ -247,5 +253,7 @@ export default { // 39. 'models.mymodels.status.inactive': 'Stopped', // 41. 'models.mymodels.status.degrade': 'Abnormal', // 42. 'models.mymodels.status.active': 'Active' - +// 43. 'models.form.remoteURL.tips': 'Refer to the configuration documentation for details.', +// 44. 'models.form.kvCache.tips': 'Available only with built-in backends (vLLM / SGLang) — switch backend in Advanced to enable.' +// 45. 'models.form.kvCache.tips2': 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).' // ========== End of To-Do List ========== diff --git a/src/locales/ru-RU/models.ts b/src/locales/ru-RU/models.ts index f511a6c6..19e67e9d 100644 --- a/src/locales/ru-RU/models.ts +++ b/src/locales/ru-RU/models.ts @@ -187,6 +187,8 @@ export default { 'models.form.chunkSize': 'Размер чанков кэша', 'models.form.maxCPUSize': 'Максимальный размер CPU кэша (ГиБ)', 'models.form.remoteURL': 'URL удаленного хранилища', + 'models.form.remoteURL.tips': + 'Refer to the configuration documentation for details.', 'models.form.runCommandPlaceholder': 'напр., vllm serve Qwen/Qwen2.5-1.5B-Instruct', 'models.accessSettings.public': 'Публичный', @@ -206,11 +208,18 @@ export default { 'Вы можете указать точное количество GPU на реплику.', 'models.mymodels.status.inactive': 'Stopped', 'models.mymodels.status.degrade': 'Abnormal', - 'models.mymodels.status.active': 'Active' + 'models.mymodels.status.active': 'Active', + 'models.form.kvCache.tips': + 'Available only with built-in backends (vLLM / SGLang) — switch backend in Advanced to enable.', + 'models.form.kvCache.tips2': + 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).' }; // ========== To-Do: Translate Keys (Remove After Translation) ========== // 1. 'models.mymodels.status.inactive': 'Stopped', // 3. 'models.mymodels.status.degrade': 'Abnormal', // 4. 'models.mymodels.status.active': 'Active' +// 5. 'models.form.remoteURL.tips': 'Refer to the configuration documentation for details.', +// 6. 'models.form.kvCache.tips': 'Available only with built-in backends (vLLM / SGLang) — switch backend in Advanced to enable.' +// 7. 'models.form.kvCache.tips2': 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).'; // ========== End of To-Do List ========== diff --git a/src/locales/zh-CN/models.ts b/src/locales/zh-CN/models.ts index c2abef55..736ce4f7 100644 --- a/src/locales/zh-CN/models.ts +++ b/src/locales/zh-CN/models.ts @@ -176,6 +176,8 @@ export default { 'models.form.chunkSize': '缓存分块大小', 'models.form.maxCPUSize': 'CPU 缓存最大占用 (GiB)', 'models.form.remoteURL': '远程存储地址', + 'models.form.remoteURL.tips': + '参考 配置文档 配置', 'models.form.runCommandPlaceholder': '例如,vllm serve Qwen/Qwen2.5-1.5B-Instruct', 'models.accessSettings.public': '公开', @@ -194,5 +196,9 @@ export default { 'models.form.gpusAllocationType.custom.tips': '您可以指定每个副本的 GPU 数量', 'models.mymodels.status.inactive': '已停止', 'models.mymodels.status.degrade': '异常', - 'models.mymodels.status.active': '可用' + 'models.mymodels.status.active': '可用', + 'models.form.kvCache.tips': + '仅在内置后端(vLLM / SGLang)可用 —— 请在高级配置中切换后端以启用。', + 'models.form.kvCache.tips2': + '仅在使用内置推理后端(vLLM 或 SGLang)时支持 KV 缓存。' }; diff --git a/src/pages/backends/components/import-yaml.tsx b/src/pages/backends/components/import-yaml.tsx index 35f96aae..2182641b 100644 --- a/src/pages/backends/components/import-yaml.tsx +++ b/src/pages/backends/components/import-yaml.tsx @@ -101,7 +101,7 @@ const ImportYAML: React.FC = forwardRef( const renderHeader = () => { return (
- YAML Editor + YAML = forwardRef( accept=".yaml,.yml,text/yaml,application/x-yaml" >
diff --git a/src/pages/backends/config/index.ts b/src/pages/backends/config/index.ts index 09251bfc..c38d6b92 100644 --- a/src/pages/backends/config/index.ts +++ b/src/pages/backends/config/index.ts @@ -2,6 +2,7 @@ import MindIELogo from '@/assets/logo/ascend.png'; import SGLangLogo from '@/assets/logo/sglang.png'; import vLLMLogo from '@/assets/logo/vllm.png'; import icons from '@/components/icon-font/icons'; +import { backendOptionsMap } from '@/pages/llmodels/config/backend-parameters'; import jsYaml from 'js-yaml'; import { trim } from 'lodash'; @@ -16,18 +17,11 @@ const SealYamlType = new jsYaml.Type('!seal', { const SEAL_SCHEMA = jsYaml.DEFAULT_SCHEMA.extend([SealYamlType]); -export const builtInBackends = { - SGLang: 'SGLang', - vLLM: 'vLLM', - MindIE: 'MindIE', - VoxBox: 'voxbox' -}; - export const builtInBackendLogos: Record = { - [builtInBackends.SGLang]: SGLangLogo, - [builtInBackends.vLLM]: vLLMLogo, - [builtInBackends.MindIE]: MindIELogo, - [builtInBackends.VoxBox]: '' + [backendOptionsMap.SGLang]: SGLangLogo, + [backendOptionsMap.vllm]: vLLMLogo, + [backendOptionsMap.ascendMindie]: MindIELogo, + [backendOptionsMap.voxBox]: '' }; export const backendActions = [ diff --git a/src/pages/backends/config/schema/update-builtin.json b/src/pages/backends/config/schema/update-builtin.json index c64e33bb..6c5773bc 100644 --- a/src/pages/backends/config/schema/update-builtin.json +++ b/src/pages/backends/config/schema/update-builtin.json @@ -23,7 +23,7 @@ "version_configs": { "type": "object", "patternProperties": { - "^[a-zA-Z0-9._-]+-custom$": { + "^[a-zA-Z0-9._-]+$": { "type": "object", "properties": { "image_name": { @@ -44,7 +44,7 @@ } }, "additionalProperties": false, - "description": "multiple backend versions ending with -custom" + "description": "multiple backend versions" } }, "required": ["version_configs"], diff --git a/src/pages/llmodels/config/backend-parameters/index.ts b/src/pages/llmodels/config/backend-parameters/index.ts index e99420c2..fefe597e 100644 --- a/src/pages/llmodels/config/backend-parameters/index.ts +++ b/src/pages/llmodels/config/backend-parameters/index.ts @@ -7,7 +7,8 @@ export const backendOptionsMap = { vllm: 'vLLM', voxBox: 'VoxBox', ascendMindie: 'MindIE', - custom: 'Custom' + custom: 'Custom', + SGLang: 'SGLang' }; export interface BackendParameter { @@ -36,5 +37,6 @@ export default { [backendOptionsMap.vllm]: generateBackendParameters(vllmParameters), [backendOptionsMap.ascendMindie]: generateBackendParameters(mindieParameters), [backendOptionsMap.voxBox]: [], - [backendOptionsMap.custom]: [] + [backendOptionsMap.custom]: [], + [backendOptionsMap.SGLang]: [] }; diff --git a/src/pages/llmodels/config/types.ts b/src/pages/llmodels/config/types.ts index a3255217..fc137981 100644 --- a/src/pages/llmodels/config/types.ts +++ b/src/pages/llmodels/config/types.ts @@ -260,6 +260,7 @@ export interface BackendOption { label: string; default_backend_param: string[]; default_version: string; + isBuiltIn: boolean; versions: { label: string; value: string }[]; } @@ -273,6 +274,7 @@ export interface BackendItem { from_config: boolean; default_version: string; default_backend_param: string[]; + is_built_in: boolean; versions: { version: string; is_deprecated: boolean; diff --git a/src/pages/llmodels/forms/index.tsx b/src/pages/llmodels/forms/index.tsx index ec695733..e7bc387d 100644 --- a/src/pages/llmodels/forms/index.tsx +++ b/src/pages/llmodels/forms/index.tsx @@ -184,11 +184,26 @@ const DataForm: React.FC = forwardRef((props, ref) => { }; }; + const updateKVCacheConfig = (backend: string, option: BackendOption) => { + if ( + !option.isBuiltIn && + [backendOptionsMap.SGLang, backendOptionsMap.vllm].includes(backend) + ) { + return { + extended_kv_cache: { + enabled: false + } + }; + } + return {}; + }; + const handleBackendChange = async (val: string, option: BackendOption) => { form.setFieldsValue({ env: null, backend_version: option.default_version || '', backend_parameters: option.default_backend_param || [], + ...updateKVCacheConfig(val, option), ...updateGPUSelector(val) }); onBackendChange?.(val); diff --git a/src/pages/llmodels/forms/kv-cache.tsx b/src/pages/llmodels/forms/kv-cache.tsx index 0a66ff35..0f79d6ac 100644 --- a/src/pages/llmodels/forms/kv-cache.tsx +++ b/src/pages/llmodels/forms/kv-cache.tsx @@ -3,14 +3,17 @@ import SealInputNumber from '@/components/seal-form/input-number'; import SealInput from '@/components/seal-form/seal-input'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; +import { useMemo } from 'react'; +import { backendOptionsMap } from '../config/backend-parameters'; import { useFormContext } from '../config/form-context'; import { FormData } from '../config/types'; const KVCacheForm = () => { const intl = useIntl(); const form = Form.useFormInstance(); - const { onValuesChange } = useFormContext(); + const { onValuesChange, backendOptions } = useFormContext(); const kvCacheEnabled = Form.useWatch(['extended_kv_cache', 'enabled'], form); + const backend = Form.useWatch('backend', form); const handleOnChange = async (e: any) => { if (e.target.checked) { @@ -29,6 +32,19 @@ const KVCacheForm = () => { onValuesChange?.({}, form.getFieldsValue()); }; + const builtInBackend = useMemo(() => { + const currentBackend = backendOptions.find( + (item) => item.value === backend + ); + + return ( + currentBackend?.isBuiltIn && + [backendOptionsMap.SGLang, backendOptionsMap.vllm].includes( + backend as string + ) + ); + }, [backend, backendOptions]); + return ( <>
@@ -37,8 +53,21 @@ const KVCacheForm = () => { name={['extended_kv_cache', 'enabled']} valuePropName="checked" style={{ padding: '0 10px', marginBottom: 0 }} + extra={ + !builtInBackend && ( + + ) + } > @@ -65,6 +94,15 @@ const KVCacheForm = () => { name={['extended_kv_cache', 'remote_url']}> + } label={intl.formatMessage({ id: 'models.form.remoteURL' })} min={0} step={1} diff --git a/src/pages/llmodels/hooks/use-query-backends.ts b/src/pages/llmodels/hooks/use-query-backends.ts index 199a98b2..418586c2 100644 --- a/src/pages/llmodels/hooks/use-query-backends.ts +++ b/src/pages/llmodels/hooks/use-query-backends.ts @@ -14,6 +14,7 @@ export default function useQueryBackends() { label: item.backend_name, default_backend_param: item.default_backend_param || [], default_version: item.default_version, + isBuiltIn: item.is_built_in, versions: (item.versions || []).map((vItem) => ({ label: vItem.version, value: vItem.version