Skip to content

Commit ef89bcd

Browse files
committed
feat: tool workflow default model setting
1 parent 645374b commit ef89bcd

6 files changed

Lines changed: 121 additions & 11 deletions

File tree

‎apps/application/workflow/nodes/tool_workflow_lib_node/tool_workflow_lib_node.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ def execute(self):
104104
"position": position.get("children") if position else None,
105105
"chunk_id": workflow_params.get("chunk_id"),
106106
"form_data": workflow_params.get("form_data"),
107+
"default_model_setting": tool_workflow_version.default_model_setting or {},
107108
**parameters,
108109
}
109110

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Generated by Django 6.1 on 2026-09-10 07:58
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("tools", "0007_alter_tool_tool_type_toolworkflow_and_more"),
9+
]
10+
11+
operations = [
12+
migrations.AddField(
13+
model_name="toolworkflow",
14+
name="default_model_setting",
15+
field=models.JSONField(default=dict, verbose_name="默认模型"),
16+
),
17+
migrations.AddField(
18+
model_name="toolworkflowversion",
19+
name="default_model_setting",
20+
field=models.JSONField(default=dict, verbose_name="默认模型"),
21+
),
22+
migrations.AlterField(
23+
model_name="tool",
24+
name="tool_type",
25+
field=models.CharField(
26+
choices=[
27+
("INTERNAL", "内置"),
28+
("CUSTOM", "自定义"),
29+
("SKILL", "技能"),
30+
("MCP", "MCP工具"),
31+
("DATA_SOURCE", "数据源"),
32+
("WORKFLOW", "工作流"),
33+
],
34+
db_index=True,
35+
default="CUSTOM",
36+
max_length=20,
37+
verbose_name="工具类型",
38+
),
39+
),
40+
migrations.AlterField(
41+
model_name="toolrecord",
42+
name="source_type",
43+
field=models.CharField(
44+
choices=[
45+
("APPLICATION", "Application"),
46+
("KNOWLEDGE", "Knowledge"),
47+
("TOOL", "Tool"),
48+
("TRIGGER", "Trigger"),
49+
],
50+
default="APPLICATION",
51+
max_length=256,
52+
verbose_name="触发器任务类型",
53+
),
54+
),
55+
]

‎apps/tools/models/tool_workflow.py‎

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# coding=utf-8
22
"""
3-
@project: MaxKB
4-
@Author:虎虎
5-
@file: tool_workflow.py
6-
@date:2026/3/3 13:59
7-
@desc:
3+
@project: MaxKB
4+
@Author:虎虎
5+
@file: tool_workflow.py
6+
@date:2026/3/3 13:59
7+
@desc:
88
"""
9+
910
from django.db import models
1011

1112
from common.mixins.app_model_mixin import AppModelMixin
@@ -18,13 +19,16 @@ class ToolWorkflow(AppModelMixin):
1819
"""
1920
知识库工作流表
2021
"""
22+
2123
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
22-
tool = models.OneToOneField(Tool, on_delete=models.CASCADE, verbose_name="工具",
23-
db_constraint=False, related_name='workflow')
24+
tool = models.OneToOneField(
25+
Tool, on_delete=models.CASCADE, verbose_name="工具", db_constraint=False, related_name="workflow"
26+
)
2427
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
2528
work_flow = models.JSONField(verbose_name="工作流数据", default=dict)
2629
is_publish = models.BooleanField(verbose_name="是否发布", default=False, db_index=True)
2730
publish_time = models.DateTimeField(verbose_name="发布时间", null=True, blank=True)
31+
default_model_setting = models.JSONField(verbose_name="默认模型", default=dict)
2832

2933
class Meta:
3034
db_table = "tool_workflow"
@@ -34,13 +38,15 @@ class ToolWorkflowVersion(AppModelMixin):
3438
"""
3539
知识库工作流版本表 - 记录工作流历史版本
3640
"""
41+
3742
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
3843
tool = models.ForeignKey(Tool, on_delete=models.CASCADE, verbose_name="工具", db_constraint=False)
3944
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
4045
name = models.CharField(verbose_name="版本名称", max_length=128, default="")
4146
work_flow = models.JSONField(verbose_name="工作流数据", default=dict)
4247
publish_user_id = models.UUIDField(verbose_name="发布者id", max_length=128, default=None, null=True)
4348
publish_user_name = models.CharField(verbose_name="发布者名称", max_length=128, default="")
49+
default_model_setting = models.JSONField(verbose_name="默认模型", default=dict)
4450

4551
class Meta:
4652
db_table = "tool_workflow_version"

‎apps/tools/serializers/tool_workflow.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ def debug(self, instance: Dict, user, with_valid=True):
170170
self.is_valid(raise_exception=True)
171171
tool_workflow = QuerySet(ToolWorkflow).filter(tool_id=self.data.get("tool_id")).first()
172172
workspace_id = tool_workflow.workspace_id
173+
default_model_setting = tool_workflow.default_model_setting
173174
tool_record_id = instance.get("chat_record_id") or str(uuid.uuid7())
174175
# 表单节点等断点续跑:position 指向要从其恢复执行的节点,机制与 chat 一致
175176
position = instance.get("position")
@@ -184,6 +185,7 @@ def debug(self, instance: Dict, user, with_valid=True):
184185
"debug": True,
185186
"workspace_id": workspace_id,
186187
"user_id": self.data.get("user_id"),
188+
"default_model_setting": default_model_setting,
187189
**{k: v for k, v in instance.items() if k not in identity_keys},
188190
}
189191

@@ -356,6 +358,7 @@ def publish(self, with_valid=True):
356358
publish_user_id=user_id,
357359
publish_user_name=user.username,
358360
workspace_id=workspace_id,
361+
default_model_setting=tool_workflow.default_model_setting,
359362
)
360363
work_flow_version.save()
361364
QuerySet(ToolWorkflow).filter(tool_id=self.data.get("tool_id")).update(
@@ -444,11 +447,13 @@ def edit(self, instance: Dict):
444447
"tool_id": self.data.get("tool_id"),
445448
"workspace_id": workflow_id,
446449
"work_flow": instance.get("work_flow", {}),
450+
"default_model_setting": instance.get("default_model_setting", {}),
447451
},
448452
defaults={
449453
"tool_id": self.data.get("tool_id"),
450454
"workspace_id": workflow_id,
451455
"work_flow": instance.get("work_flow"),
456+
"default_model_setting": instance.get("default_model_setting", {}),
452457
},
453458
)
454459
# 当前用户可修改关联的知识库列表

‎ui/src/api/types/tool.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import type LogicFlow from '@logicflow/core'
44
import { TOOL_SCOPE, TOOL_TYPE } from '@/api/enums'
55
import type { DynamicFormField } from './common'
6+
import type { DefaultModelSettingPayload } from '@/api/types/model.ts'
67

78
export type ToolScope = (typeof TOOL_SCOPE)[keyof typeof TOOL_SCOPE]
89
export type ToolType = (typeof TOOL_TYPE)[keyof typeof TOOL_TYPE]
@@ -71,6 +72,7 @@ export interface ToolItem {
7172
}
7273

7374
export interface ToolWorkflowDetail {
75+
default_model_setting?: DefaultModelSettingPayload
7476
create_time?: string
7577
id: string
7678
is_publish: boolean

‎ui/src/views/workflow/tool/ToolWorkflowView.vue‎

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ import { cloneDeep } from 'lodash'
77
import ModelApi from '@/api/admin/workspace/model/model'
88
import ToolApi from '@/api/admin/workspace/tool/tool'
99
import ToolWorkflowApi from '@/api/admin/workspace/tool/workflow'
10-
import type { ToolItem, ToolWorkflowDetail } from '@/api/types'
11-
import { MsgConfirm, MsgSuccess } from '@/utils/message'
10+
import type { DefaultModelSettingPayload, ToolItem, ToolWorkflowDetail } from '@/api/types'
11+
import { MsgConfirm, MsgSuccess, MsgError } from '@/utils/message'
1212
import WorkflowCanvas from '@/workflow-canvas/index.vue'
1313
import { defaultToolNodes } from '@/workflow-canvas/config/node-mapping'
1414
import { WorkflowMode } from '@/workflow-canvas/types'
1515
import WorkflowViewLayout from '../components/WorkflowViewLayout.vue'
16+
import DefaultModelSettingButton from '@/views/workflow/components/default-model-setting/DefaultModelSettingButton.vue'
1617
1718
defineOptions({ name: 'ToolWorkflowView' })
1819
@@ -35,6 +36,7 @@ const workflowRef = useTemplateRef<InstanceType<typeof WorkflowCanvas>>('workflo
3536
const toolDetail = ref<ToolItem>()
3637
const loading = ref(false)
3738
const saving = ref(false)
39+
const publishing = ref(false)
3840
const savedWorkflow = ref<LogicFlow.GraphData>()
3941
const saveTime = ref<Date | string>()
4042
@@ -57,8 +59,9 @@ function saveToolWorkflow(graphData = getGraphData(), showMessage = false) {
5759
if (!graphData) return Promise.resolve<ToolWorkflowDetail | undefined>(undefined)
5860
5961
saving.value = true
60-
return ToolWorkflowApi.putToolWorkflow(toolId, { work_flow: graphData })
62+
return ToolWorkflowApi.putToolWorkflow(toolId, { work_flow: graphData, default_model_setting: cloneDeep(defaultModelSetting.value) })
6163
.then((toolWorkflow) => {
64+
defaultModelSetting.value = cloneDeep(toolWorkflow.default_model_setting ?? {})
6265
saveTime.value = toolWorkflow.update_time || new Date()
6366
setSavedWorkflow(graphData)
6467
if (showMessage) MsgSuccess('保存成功')
@@ -69,15 +72,43 @@ function saveToolWorkflow(graphData = getGraphData(), showMessage = false) {
6972
})
7073
}
7174
75+
/* 应用默认模型设置:抽屉提交后暂存,保存失败时从详情回滚。 */
76+
const defaultModelSetting = ref<DefaultModelSettingPayload>({})
77+
78+
function handleApplyDefaultModelToAll(graphData: LogicFlow.GraphData) {
79+
workflowRef.value?.renderGraphData(graphData)
80+
}
81+
82+
function handleSaveDefaultModelSetting(settings: DefaultModelSettingPayload) {
83+
defaultModelSetting.value = cloneDeep(settings)
84+
return handleSave()
85+
}
86+
7287
function handleSave() {
7388
saveToolWorkflow(undefined, true)
7489
}
7590
91+
function handlePublish() {
92+
if (!workflowRef.value) return
93+
94+
publishing.value = true
95+
workflowRef.value
96+
.validate()
97+
.then(() => saveToolWorkflow()) // 先保存未落库的画布改动
98+
.then(() => ToolWorkflowApi.putToolWorkflowPublish(toolId))
99+
.then(() => MsgSuccess('发布成功'))
100+
.catch(() => MsgError('发布失败'))
101+
.finally(() => {
102+
publishing.value = false
103+
})
104+
}
105+
76106
function loadToolWorkflow() {
77107
loading.value = true
78108
return Promise.all([ToolApi.getToolDetail(toolId), ToolWorkflowApi.getToolWorkflow(toolId)])
79109
.then(([tool, toolWorkflow]) => {
80110
toolDetail.value = tool
111+
defaultModelSetting.value = cloneDeep(toolWorkflow.default_model_setting ?? {})
81112
saveTime.value = toolWorkflow.update_time
82113
83114
const workflow = toolWorkflow.work_flow?.nodes?.length ? toolWorkflow.work_flow : DEFAULT_WORKFLOW
@@ -133,9 +164,19 @@ onMounted(() => {
133164
<template>
134165
<WorkflowViewLayout :loading="loading" :title="toolDetail?.name" :save-time="saveTime" @back="handleBack">
135166
<template #actions>
167+
<DefaultModelSettingButton
168+
:model-value="defaultModelSetting"
169+
:model-api="ModelApi"
170+
:get-graph-data="getGraphData"
171+
:disabled="loading || saving || publishing"
172+
@save="handleSaveDefaultModelSetting"
173+
@apply-to-all="handleApplyDefaultModelToAll"
174+
/>
175+
176+
<el-button type="primary" :loading="publishing" :disabled="loading || saving || publishing" @click="handlePublish"> 发布 </el-button>
136177
<el-button plain :loading="saving" :disabled="loading || saving" @click="handleSave"> 保存 </el-button>
137178
</template>
138179

139-
<WorkflowCanvas ref="workflowRef" class="min-h-0 flex-1" :loop-workflow-mode="WorkflowMode.ToolLoop" :workflow-mode="WorkflowMode.Tool" />
180+
<WorkflowCanvas ref="workflowRef" class="min-h-0 flex-1" :default-model-settings="defaultModelSetting" :loop-workflow-mode="WorkflowMode.ToolLoop" :workflow-mode="WorkflowMode.Tool" />
140181
</WorkflowViewLayout>
141182
</template>

0 commit comments

Comments
 (0)