From 86904332bca9f3afa7880f1f46c50df7fe8ecca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E8=AF=A3?= Date: Sat, 2 May 2026 01:08:09 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(knowledge):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E8=AF=AD=E8=A8=80=E6=A8=A1=E5=9E=8B=E9=80=89=E6=8B=A9=E5=90=8E?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E5=9B=9E=E6=98=BE=E4=B8=94=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E4=B8=BA=E7=A9=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V2 模型 spec 格式为 provider_id:model_id(冒号分隔), 但 handleLLMSelect 使用斜杠拆分,导致 provider 和 model_name 均为空。 新增 model_spec 字段直接存储完整 spec,抽取 parseModelSpec/buildDisplaySpec 工具函数统一处理 V1/V2 两种格式,消除 3 处重复逻辑。 --- web/src/components/DatabaseHeader.vue | 26 ++++++------------- web/src/components/KnowledgeBaseCard.vue | 26 ++++++------------- web/src/utils/kb_utils.js | 22 ++++++++++++++++ web/src/views/DataBaseView.vue | 32 ++++++++++-------------- 4 files changed, 51 insertions(+), 55 deletions(-) diff --git a/web/src/components/DatabaseHeader.vue b/web/src/components/DatabaseHeader.vue index d6cd3285..8bbc672f 100644 --- a/web/src/components/DatabaseHeader.vue +++ b/web/src/components/DatabaseHeader.vue @@ -75,7 +75,7 @@ import { ref, reactive, computed } from 'vue' import { useRouter } from 'vue-router' import { useDatabaseStore } from '@/stores/database' -import { getKbTypeLabel, getKbTypeIcon, getKbTypeColor } from '@/utils/kb_utils' +import { getKbTypeLabel, getKbTypeIcon, getKbTypeColor, parseModelSpec, buildDisplaySpec } from '@/utils/kb_utils' import { LeftOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue' import HeaderComponent from '@/components/HeaderComponent.vue' import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue' @@ -94,6 +94,7 @@ const editForm = reactive({ name: '', description: '', llm_info: { + model_spec: '', provider: '', model_name: '' } @@ -113,6 +114,7 @@ const showEditModal = () => { // 如果是 LightRAG 类型,加载当前的 LLM 配置 if (database.value.kb_type === 'lightrag') { const llmInfo = database.value.llm_info || {} + editForm.llm_info.model_spec = llmInfo.model_spec || '' editForm.llm_info.provider = llmInfo.provider || '' editForm.llm_info.model_name = llmInfo.model_name || '' } @@ -131,6 +133,7 @@ const handleEditSubmit = () => { // 如果是 LightRAG 类型,包含 llm_info if (database.value.kb_type === 'lightrag') { updateData.llm_info = { + model_spec: editForm.llm_info.model_spec, provider: editForm.llm_info.provider, model_name: editForm.llm_info.model_name } @@ -145,25 +148,12 @@ const handleEditSubmit = () => { } // LLM 模型选择处理 -const llmModelSpec = computed(() => { - const provider = editForm.llm_info?.provider || '' - const modelName = editForm.llm_info?.model_name || '' - if (provider && modelName) { - return `${provider}/${modelName}` - } - return '' -}) +const llmModelSpec = computed(() => buildDisplaySpec(editForm.llm_info)) const handleLLMSelect = (spec) => { - console.log('LLM选择:', spec) - if (typeof spec !== 'string' || !spec) return - - const index = spec.indexOf('/') - const provider = index !== -1 ? spec.slice(0, index) : '' - const modelName = index !== -1 ? spec.slice(index + 1) : '' - - editForm.llm_info.provider = provider - editForm.llm_info.model_name = modelName + const parsed = parseModelSpec(spec) + if (!parsed) return + Object.assign(editForm.llm_info, parsed) } const deleteDatabase = () => { diff --git a/web/src/components/KnowledgeBaseCard.vue b/web/src/components/KnowledgeBaseCard.vue index 6ddb02bc..b4912e42 100644 --- a/web/src/components/KnowledgeBaseCard.vue +++ b/web/src/components/KnowledgeBaseCard.vue @@ -158,7 +158,7 @@ import { ref, reactive, computed, h, onMounted } from 'vue' import { useRouter } from 'vue-router' import { useDatabaseStore } from '@/stores/database' import { useUserStore } from '@/stores/user' -import { getKbTypeLabel, getKbTypeColor } from '@/utils/kb_utils' +import { getKbTypeLabel, getKbTypeColor, parseModelSpec, buildDisplaySpec } from '@/utils/kb_utils' import { CHUNK_PRESET_OPTIONS, CHUNK_PRESET_LABEL_MAP, @@ -264,6 +264,7 @@ const editForm = reactive({ auto_generate_questions: false, chunk_preset_id: 'general', llm_info: { + model_spec: '', provider: '', model_name: '' }, @@ -296,6 +297,7 @@ const showEditModal = () => { // 如果是 LightRAG 类型,加载当前的 LLM 配置 if (database.value.kb_type === 'lightrag') { const llmInfo = database.value.llm_info || {} + editForm.llm_info.model_spec = llmInfo.model_spec || '' editForm.llm_info.provider = llmInfo.provider || '' editForm.llm_info.model_name = llmInfo.model_name || '' } @@ -376,6 +378,7 @@ const handleEditSubmit = () => { // 如果是 LightRAG 类型,包含 llm_info if (database.value.kb_type === 'lightrag') { updateData.llm_info = { + model_spec: editForm.llm_info.model_spec, provider: editForm.llm_info.provider, model_name: editForm.llm_info.model_name } @@ -390,25 +393,12 @@ const handleEditSubmit = () => { } // LLM 模型选择处理 -const llmModelSpec = computed(() => { - const provider = editForm.llm_info?.provider || '' - const modelName = editForm.llm_info?.model_name || '' - if (provider && modelName) { - return `${provider}/${modelName}` - } - return '' -}) +const llmModelSpec = computed(() => buildDisplaySpec(editForm.llm_info)) const handleLLMSelect = (spec) => { - console.log('LLM选择:', spec) - if (typeof spec !== 'string' || !spec) return - - const index = spec.indexOf('/') - const provider = index !== -1 ? spec.slice(0, index) : '' - const modelName = index !== -1 ? spec.slice(index + 1) : '' - - editForm.llm_info.provider = provider - editForm.llm_info.model_name = modelName + const parsed = parseModelSpec(spec) + if (!parsed) return + Object.assign(editForm.llm_info, parsed) } const deleteDatabase = () => { diff --git a/web/src/utils/kb_utils.js b/web/src/utils/kb_utils.js index cefa3bd4..2fbb50e4 100644 --- a/web/src/utils/kb_utils.js +++ b/web/src/utils/kb_utils.js @@ -26,3 +26,25 @@ export const getKbTypeColor = (type) => { } return colors[type] || 'blue' } + +// 解析模型 spec 为 { model_spec, provider, model_name } +// V2 格式: provider_id:model_id(冒号分隔) +// V1 格式: provider/model_name(斜杠分隔) +export const parseModelSpec = (spec) => { + if (typeof spec !== 'string' || !spec) return null + const sep = spec.includes(':') ? ':' : '/' + const index = spec.indexOf(sep) + return { + model_spec: spec, + provider: index !== -1 ? spec.slice(0, index) : '', + model_name: index !== -1 ? spec.slice(index + 1) : '' + } +} + +// 从 llm_info 构造显示用的 spec 字符串 +export const buildDisplaySpec = (llmInfo) => { + if (llmInfo?.model_spec) return llmInfo.model_spec + const provider = llmInfo?.provider || '' + const modelName = llmInfo?.model_name || '' + return provider && modelName ? `${provider}/${modelName}` : '' +} diff --git a/web/src/views/DataBaseView.vue b/web/src/views/DataBaseView.vue index ad1cf5cd..89120681 100644 --- a/web/src/views/DataBaseView.vue +++ b/web/src/views/DataBaseView.vue @@ -250,7 +250,7 @@ import ExtensionCardGrid from '@/components/extensions/ExtensionCardGrid.vue' import InfoCard from '@/components/shared/InfoCard.vue' import dayjs, { parseToShanghai } from '@/utils/time' import AiTextarea from '@/components/AiTextarea.vue' -import { getKbTypeLabel, getKbTypeIcon, getKbTypeColor } from '@/utils/kb_utils' +import { getKbTypeLabel, getKbTypeIcon, getKbTypeColor, parseModelSpec, buildDisplaySpec } from '@/utils/kb_utils' import { CHUNK_PRESET_OPTIONS, getChunkPresetDescription } from '@/utils/chunk_presets' const route = useRoute() @@ -324,6 +324,7 @@ const createEmptyDatabaseForm = () => ({ chunk_preset_id: 'general', language: 'Chinese', llm_info: { + model_spec: '', provider: '', model_name: '' }, @@ -338,14 +339,7 @@ const selectedPresetDescription = computed(() => getChunkPresetDescription(newDatabase.chunk_preset_id) ) -const llmModelSpec = computed(() => { - const provider = newDatabase.llm_info?.provider || '' - const modelName = newDatabase.llm_info?.model_name || '' - if (provider && modelName) { - return `${provider}/${modelName}` - } - return '' -}) +const llmModelSpec = computed(() => buildDisplaySpec(newDatabase.llm_info)) // 支持的知识库类型 const supportedKbTypes = ref({}) @@ -427,15 +421,9 @@ const handleKbTypeChange = (type) => { // 处理LLM选择 const handleLLMSelect = (spec) => { - console.log('LLM选择:', spec) - if (typeof spec !== 'string' || !spec) return - - const index = spec.indexOf('/') - const provider = index !== -1 ? spec.slice(0, index) : '' - const modelName = index !== -1 ? spec.slice(index + 1) : '' - - newDatabase.llm_info.provider = provider - newDatabase.llm_info.model_name = modelName + const parsed = parseModelSpec(spec) + if (!parsed) return + Object.assign(newDatabase.llm_info, parsed) } // 构建请求数据(只负责表单数据转换) @@ -470,7 +458,13 @@ const buildRequestData = () => { if (newDatabase.kb_type === 'lightrag') { requestData.additional_params.language = newDatabase.language || 'English' - if (newDatabase.llm_info.provider && newDatabase.llm_info.model_name) { + if (newDatabase.llm_info.model_spec) { + requestData.llm_info = { + model_spec: newDatabase.llm_info.model_spec, + provider: newDatabase.llm_info.provider, + model_name: newDatabase.llm_info.model_name + } + } else if (newDatabase.llm_info.provider && newDatabase.llm_info.model_name) { requestData.llm_info = { provider: newDatabase.llm_info.provider, model_name: newDatabase.llm_info.model_name From 250885cb4de0b67b9023dbd8bf0e3c0bbfcb7d33 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Mon, 4 May 2026 08:12:54 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E4=BD=BF=E7=94=A8=20buildLlmInfoPay?= =?UTF-8?q?load=20=E5=87=BD=E6=95=B0=E6=9E=84=E9=80=A0=20llm=5Finfo?= =?UTF-8?q?=EF=BC=8C=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81=E5=B9=B6=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E7=A9=BA=E5=80=BC=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/components/DatabaseHeader.vue | 8 ++------ web/src/components/KnowledgeBaseCard.vue | 8 ++------ web/src/utils/kb_utils.js | 17 ++++++++++++++--- web/src/views/DataBaseView.vue | 15 +++------------ 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/web/src/components/DatabaseHeader.vue b/web/src/components/DatabaseHeader.vue index 8bbc672f..99ba673d 100644 --- a/web/src/components/DatabaseHeader.vue +++ b/web/src/components/DatabaseHeader.vue @@ -75,7 +75,7 @@ import { ref, reactive, computed } from 'vue' import { useRouter } from 'vue-router' import { useDatabaseStore } from '@/stores/database' -import { getKbTypeLabel, getKbTypeIcon, getKbTypeColor, parseModelSpec, buildDisplaySpec } from '@/utils/kb_utils' +import { getKbTypeLabel, getKbTypeIcon, getKbTypeColor, parseModelSpec, buildDisplaySpec, buildLlmInfoPayload } from '@/utils/kb_utils' import { LeftOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue' import HeaderComponent from '@/components/HeaderComponent.vue' import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue' @@ -132,11 +132,7 @@ const handleEditSubmit = () => { // 如果是 LightRAG 类型,包含 llm_info if (database.value.kb_type === 'lightrag') { - updateData.llm_info = { - model_spec: editForm.llm_info.model_spec, - provider: editForm.llm_info.provider, - model_name: editForm.llm_info.model_name - } + updateData.llm_info = buildLlmInfoPayload(editForm.llm_info) } await store.updateDatabaseInfo(updateData) diff --git a/web/src/components/KnowledgeBaseCard.vue b/web/src/components/KnowledgeBaseCard.vue index b4912e42..04ca9072 100644 --- a/web/src/components/KnowledgeBaseCard.vue +++ b/web/src/components/KnowledgeBaseCard.vue @@ -158,7 +158,7 @@ import { ref, reactive, computed, h, onMounted } from 'vue' import { useRouter } from 'vue-router' import { useDatabaseStore } from '@/stores/database' import { useUserStore } from '@/stores/user' -import { getKbTypeLabel, getKbTypeColor, parseModelSpec, buildDisplaySpec } from '@/utils/kb_utils' +import { getKbTypeLabel, getKbTypeColor, parseModelSpec, buildDisplaySpec, buildLlmInfoPayload } from '@/utils/kb_utils' import { CHUNK_PRESET_OPTIONS, CHUNK_PRESET_LABEL_MAP, @@ -377,11 +377,7 @@ const handleEditSubmit = () => { // 如果是 LightRAG 类型,包含 llm_info if (database.value.kb_type === 'lightrag') { - updateData.llm_info = { - model_spec: editForm.llm_info.model_spec, - provider: editForm.llm_info.provider, - model_name: editForm.llm_info.model_name - } + updateData.llm_info = buildLlmInfoPayload(editForm.llm_info) } await store.updateDatabaseInfo(updateData) diff --git a/web/src/utils/kb_utils.js b/web/src/utils/kb_utils.js index 2fbb50e4..e210c524 100644 --- a/web/src/utils/kb_utils.js +++ b/web/src/utils/kb_utils.js @@ -29,11 +29,12 @@ export const getKbTypeColor = (type) => { // 解析模型 spec 为 { model_spec, provider, model_name } // V2 格式: provider_id:model_id(冒号分隔) -// V1 格式: provider/model_name(斜杠分隔) +// V1 格式: provider/model_name(斜杠分隔,model_name 可包含冒号) export const parseModelSpec = (spec) => { if (typeof spec !== 'string' || !spec) return null - const sep = spec.includes(':') ? ':' : '/' - const index = spec.indexOf(sep) + const slashIndex = spec.indexOf('/') + const colonIndex = spec.indexOf(':') + const index = slashIndex !== -1 ? slashIndex : colonIndex return { model_spec: spec, provider: index !== -1 ? spec.slice(0, index) : '', @@ -48,3 +49,13 @@ export const buildDisplaySpec = (llmInfo) => { const modelName = llmInfo?.model_name || '' return provider && modelName ? `${provider}/${modelName}` : '' } + +// 构造提交给后端的 llm_info,避免旧数据写入空 model_spec +export const buildLlmInfoPayload = (llmInfo) => { + const payload = { + provider: llmInfo?.provider || '', + model_name: llmInfo?.model_name || '' + } + if (llmInfo?.model_spec) payload.model_spec = llmInfo.model_spec + return payload +} diff --git a/web/src/views/DataBaseView.vue b/web/src/views/DataBaseView.vue index 89120681..25660647 100644 --- a/web/src/views/DataBaseView.vue +++ b/web/src/views/DataBaseView.vue @@ -250,7 +250,7 @@ import ExtensionCardGrid from '@/components/extensions/ExtensionCardGrid.vue' import InfoCard from '@/components/shared/InfoCard.vue' import dayjs, { parseToShanghai } from '@/utils/time' import AiTextarea from '@/components/AiTextarea.vue' -import { getKbTypeLabel, getKbTypeIcon, getKbTypeColor, parseModelSpec, buildDisplaySpec } from '@/utils/kb_utils' +import { getKbTypeLabel, getKbTypeIcon, getKbTypeColor, parseModelSpec, buildDisplaySpec, buildLlmInfoPayload } from '@/utils/kb_utils' import { CHUNK_PRESET_OPTIONS, getChunkPresetDescription } from '@/utils/chunk_presets' const route = useRoute() @@ -458,17 +458,8 @@ const buildRequestData = () => { if (newDatabase.kb_type === 'lightrag') { requestData.additional_params.language = newDatabase.language || 'English' - if (newDatabase.llm_info.model_spec) { - requestData.llm_info = { - model_spec: newDatabase.llm_info.model_spec, - provider: newDatabase.llm_info.provider, - model_name: newDatabase.llm_info.model_name - } - } else if (newDatabase.llm_info.provider && newDatabase.llm_info.model_name) { - requestData.llm_info = { - provider: newDatabase.llm_info.provider, - model_name: newDatabase.llm_info.model_name - } + if (newDatabase.llm_info.model_spec || (newDatabase.llm_info.provider && newDatabase.llm_info.model_name)) { + requestData.llm_info = buildLlmInfoPayload(newDatabase.llm_info) } }