Skip to content

Commit 239924c

Browse files
committed
feat: 模型助手新增默认模型参数配置-助手新增/编辑弹窗新增模型参数区(默认供应商+模型下拉/深度思考开关/温度0-2滑杆/最大输出字数/随机种子),AiAssistantEntity与AiConversationEntity新增provider_id/model/temperature/max_tokens/seed/enable_thinking字段(建表ALTER补列),开启对话时参数快照到会话,多轮对话/结束对话按会话参数透传(enable_thinking/max_tokens/seed),运行助手接口同样生效,运行页优先使用助手配置的默认供应商与模型
1 parent fc2f4e3 commit 239924c

7 files changed

Lines changed: 148 additions & 5 deletions

File tree

‎Juggle.Api/Controllers/Api/AiController.cs‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,12 @@ public async Task<ApiResult> SaveAssistant([FromBody] AiAssistantSaveRequest req
236236
entity.QuickPrompts = req.QuickPrompts;
237237
entity.Icon = req.Icon;
238238
entity.Capabilities = req.Capabilities;
239+
entity.ProviderId = req.ProviderId;
240+
entity.Model = string.IsNullOrWhiteSpace(req.Model) ? null : req.Model.Trim();
241+
entity.Temperature = req.Temperature;
242+
entity.MaxTokens = req.MaxTokens is > 0 ? req.MaxTokens : null;
243+
entity.Seed = req.Seed is > 0 ? req.Seed : null;
244+
entity.EnableThinking = req.EnableThinking ? 1 : 0;
239245
entity.Enabled = req.Enabled ? 1 : 0;
240246
entity.UpdatedAt = DateTime.Now.ToString("o");
241247
await _db.SaveChangesAsync();
@@ -480,6 +486,18 @@ public class AiAssistantSaveRequest
480486
public bool Enabled { get; set; } = true;
481487
/// <summary>支持的能力(JSON: {skills,apis,flows,tools})</summary>
482488
public string? Capabilities { get; set; }
489+
/// <summary>默认供应商 ID(0=第一个启用供应商)</summary>
490+
public long ProviderId { get; set; }
491+
/// <summary>默认模型(空=供应商默认)</summary>
492+
public string? Model { get; set; }
493+
/// <summary>温度(0-2,null=服务默认)</summary>
494+
public double? Temperature { get; set; }
495+
/// <summary>最大输出字数(0=不限制)</summary>
496+
public int? MaxTokens { get; set; }
497+
/// <summary>随机种子(0=随机)</summary>
498+
public int? Seed { get; set; }
499+
/// <summary>是否启用深度思考</summary>
500+
public bool EnableThinking { get; set; }
483501
}
484502

485503
public class AiOptimizePromptRequest

‎Juggle.Api/Program.cs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,18 @@ await ctx.Response.WriteAsync(
256256
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_assistant ADD COLUMN icon TEXT DEFAULT NULL;"); } catch { }
257257
// 助手支持的能力(skills/apis/flows/tools)
258258
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_assistant ADD COLUMN capabilities TEXT DEFAULT NULL;"); } catch { }
259+
// 助手默认模型参数(供应商/模型/温度/最大输出/随机种子/深度思考)
260+
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_assistant ADD COLUMN provider_id INTEGER DEFAULT 0;"); } catch { }
261+
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_assistant ADD COLUMN model TEXT DEFAULT NULL;"); } catch { }
262+
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_assistant ADD COLUMN temperature REAL DEFAULT NULL;"); } catch { }
263+
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_assistant ADD COLUMN max_tokens INTEGER DEFAULT NULL;"); } catch { }
264+
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_assistant ADD COLUMN seed INTEGER DEFAULT NULL;"); } catch { }
265+
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_assistant ADD COLUMN enable_thinking INTEGER DEFAULT 0;"); } catch { }
266+
// 会话模型参数快照(温度/最大输出/随机种子/深度思考)
267+
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_conversation ADD COLUMN temperature REAL DEFAULT NULL;"); } catch { }
268+
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_conversation ADD COLUMN max_tokens INTEGER DEFAULT NULL;"); } catch { }
269+
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_conversation ADD COLUMN seed INTEGER DEFAULT NULL;"); } catch { }
270+
try { db.Database.ExecuteSqlRaw("ALTER TABLE t_ai_conversation ADD COLUMN enable_thinking INTEGER DEFAULT 0;"); } catch { }
259271
// AI 助手对话会话表
260272
try { db.Database.ExecuteSqlRaw("CREATE TABLE IF NOT EXISTS t_ai_conversation(id INTEGER PRIMARY KEY AUTOINCREMENT, assistant_id INTEGER, assistant_name TEXT, system_prompt TEXT, input_params TEXT, output_params TEXT, messages TEXT, outputs TEXT, provider_id INTEGER, model TEXT, title TEXT, status INTEGER DEFAULT 0, created_at TEXT, created_by INTEGER, updated_at TEXT, updated_by INTEGER, tenant_id INTEGER, deleted INTEGER DEFAULT 0);"); } catch { }
261273
// Redis 多实例配置表

‎Juggle.Domain/Entities/AiAssistantEntity.cs‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,22 @@ public class AiAssistantEntity : BaseEntity
3333

3434
/// <summary>支持的能力(JSON: {skills:[id],apis:["code"],flows:["key"],tools:["name"]})</summary>
3535
public string? Capabilities { get; set; }
36+
37+
/// <summary>默认供应商 ID(0=第一个启用供应商)</summary>
38+
public long ProviderId { get; set; }
39+
40+
/// <summary>默认模型(空=供应商默认模型)</summary>
41+
public string? Model { get; set; }
42+
43+
/// <summary>温度(0-2,null=服务默认)</summary>
44+
public double? Temperature { get; set; }
45+
46+
/// <summary>最大输出字数(0/null=不限制)</summary>
47+
public int? MaxTokens { get; set; }
48+
49+
/// <summary>随机种子(0/null=随机)</summary>
50+
public int? Seed { get; set; }
51+
52+
/// <summary>是否启用深度思考(enable_thinking)</summary>
53+
public int EnableThinking { get; set; }
3654
}

‎Juggle.Domain/Entities/AiConversationEntity.cs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ public class AiConversationEntity : BaseEntity
3434
/// <summary>使用的模型</summary>
3535
public string? Model { get; set; }
3636

37+
/// <summary>温度快照(0-2,null=服务默认)</summary>
38+
public double? Temperature { get; set; }
39+
40+
/// <summary>最大输出字数快照(0/null=不限制)</summary>
41+
public int? MaxTokens { get; set; }
42+
43+
/// <summary>随机种子快照(0/null=随机)</summary>
44+
public int? Seed { get; set; }
45+
46+
/// <summary>是否启用深度思考快照</summary>
47+
public int EnableThinking { get; set; }
48+
3749
/// <summary>会话标题(首条用户消息截断)</summary>
3850
public string? Title { get; set; }
3951

‎Juggle.Infrastructure/Persistence/JuggleDbContext.cs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
135135
e.Property(p => p.Icon).HasColumnName("icon");
136136
e.Property(p => p.Enabled).HasColumnName("enabled");
137137
e.Property(p => p.Capabilities).HasColumnName("capabilities");
138+
e.Property(p => p.ProviderId).HasColumnName("provider_id");
139+
e.Property(p => p.Model).HasColumnName("model");
140+
e.Property(p => p.Temperature).HasColumnName("temperature");
141+
e.Property(p => p.MaxTokens).HasColumnName("max_tokens");
142+
e.Property(p => p.Seed).HasColumnName("seed");
143+
e.Property(p => p.EnableThinking).HasColumnName("enable_thinking");
138144
});
139145
modelBuilder.Entity<AiConversationEntity>().ToTable("t_ai_conversation");
140146
modelBuilder.Entity<AiConversationEntity>(e => {
@@ -154,6 +160,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
154160
e.Property(p => p.Outputs).HasColumnName("outputs");
155161
e.Property(p => p.ProviderId).HasColumnName("provider_id");
156162
e.Property(p => p.Model).HasColumnName("model");
163+
e.Property(p => p.Temperature).HasColumnName("temperature");
164+
e.Property(p => p.MaxTokens).HasColumnName("max_tokens");
165+
e.Property(p => p.Seed).HasColumnName("seed");
166+
e.Property(p => p.EnableThinking).HasColumnName("enable_thinking");
157167
e.Property(p => p.Title).HasColumnName("title");
158168
e.Property(p => p.Status).HasColumnName("status");
159169
});

‎JuggleNet6.Frontend/src/views/ai/AiAssistantList.vue‎

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,39 @@
103103
<div style="font-size:11px;color:#909399;margin-top:4px">运行页中显示为快捷按钮,点击即填入补充说明,方便常用提问一键发起。</div>
104104
</div>
105105
</el-form-item>
106+
<el-form-item label="模型参数">
107+
<div style="width:100%">
108+
<div style="display:flex;gap:8px;align-items:center;margin-bottom:6px">
109+
<span style="width:64px;font-size:12px;color:#666;flex-shrink:0">默认模型</span>
110+
<el-select v-model="form.providerId" size="small" style="flex:1" clearable placeholder="供应商(空=第一个启用)" @change="onAssistantProviderChange">
111+
<el-option v-for="p in aiProviders" :key="p.id" :label="p.providerName" :value="p.id" />
112+
</el-select>
113+
<el-select v-model="form.model" size="small" style="flex:1" clearable filterable allow-create default-first-option placeholder="模型(空=供应商默认)">
114+
<el-option v-for="m in assistantModelOptions" :key="m" :label="m" :value="m" />
115+
</el-select>
116+
</div>
117+
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
118+
<span style="width:64px;font-size:12px;color:#666;flex-shrink:0">深度思考</span>
119+
<el-switch v-model="form.enableThinking" size="small" />
120+
<span style="font-size:11px;color:#909399">推理模型(deepseek-reasoner / Qwen 思考模式)生效</span>
121+
</div>
122+
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
123+
<span style="width:64px;font-size:12px;color:#666;flex-shrink:0">温度</span>
124+
<el-slider v-model="form.temperature" size="small" style="flex:1" :min="0" :max="2" :step="0.1" :format-tooltip="tempFormat" />
125+
<span style="width:36px;font-size:12px;color:#666;text-align:right;flex-shrink:0">{{ (form.temperature || 0).toFixed(1) }}</span>
126+
</div>
127+
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
128+
<span style="width:64px;font-size:12px;color:#666;flex-shrink:0">最大输出</span>
129+
<el-input-number v-model="form.maxTokens" size="small" style="flex:1" :min="0" :step="100" controls-position="right" />
130+
<span style="font-size:11px;color:#909399;flex-shrink:0">0=不限制</span>
131+
</div>
132+
<div style="display:flex;align-items:center;gap:8px">
133+
<span style="width:64px;font-size:12px;color:#666;flex-shrink:0">随机种子</span>
134+
<el-input-number v-model="form.seed" size="small" style="flex:1" :min="0" :step="1" controls-position="right" />
135+
<span style="font-size:11px;color:#909399;flex-shrink:0">0=随机</span>
136+
</div>
137+
</div>
138+
</el-form-item>
106139
<el-form-item label="支持的能力">
107140
<div style="width:100%">
108141
<div style="display:flex;gap:8px;align-items:center;margin-bottom:6px">
@@ -151,7 +184,7 @@
151184
</template>
152185

153186
<script setup lang="ts">
154-
import { ref, onMounted } from 'vue'
187+
import { ref, computed, onMounted } from 'vue'
155188
import { ElMessage, ElMessageBox } from 'element-plus'
156189
import request from '../../utils/request'
157190
import MarketPublishDialog from '../../components/MarketPublishDialog.vue'
@@ -210,6 +243,28 @@ const skillOptions = ref<any[]>([])
210243
const apiOptions = ref<any[]>([])
211244
const flowOptions = ref<any[]>([])
212245
246+
// 模型参数(默认供应商/模型/深度思考/温度/最大输出/随机种子)
247+
const aiProviders = ref<any[]>([])
248+
const assistantModelOptions = computed(() => {
249+
const p = aiProviders.value.find((x: any) => x.id === form.value.providerId)
250+
const list = String(p?.models || '').split(',').map((s: string) => s.trim()).filter(Boolean)
251+
if (p?.model && !list.includes(p.model)) list.unshift(p.model)
252+
return list.filter(Boolean)
253+
})
254+
function onAssistantProviderChange() {
255+
const p = aiProviders.value.find((x: any) => x.id === form.value.providerId)
256+
if (p) form.value.model = p.model || ''
257+
}
258+
function tempFormat(v: number) { return v.toFixed(1) }
259+
260+
/** 加载启用的供应商(默认模型选择用) */
261+
async function loadAiProviders() {
262+
try {
263+
const res: any = await request.get('/ai/providers/enabled')
264+
aiProviders.value = res.data || []
265+
} catch { /* 未配置供应商 */ }
266+
}
267+
213268
/** 加载能力选项(技能/接口/流程) */
214269
async function loadCapabilityOptions() {
215270
try {
@@ -261,22 +316,36 @@ function countParams(json: string): number {
261316
}
262317
263318
function openAdd() {
264-
form.value = { id: 0, assistantName: '', description: '', systemPrompt: '', icon: '', enabled: true }
319+
form.value = {
320+
id: 0, assistantName: '', description: '', systemPrompt: '', icon: '', enabled: true,
321+
providerId: 0, model: '', enableThinking: false, temperature: 0.7, maxTokens: 0, seed: 0
322+
}
265323
inputParams.value = []
266324
outputParams.value = []
267325
quickPrompts.value = []
268326
parseCapabilities('')
269327
dialogVisible.value = true
270328
loadCapabilityOptions()
329+
loadAiProviders()
271330
}
272331
function openEdit(row: any) {
273-
form.value = { ...row, enabled: row.enabled === 1 }
332+
form.value = {
333+
...row,
334+
enabled: row.enabled === 1,
335+
enableThinking: row.enableThinking === 1,
336+
temperature: row.temperature ?? 0.7,
337+
maxTokens: row.maxTokens || 0,
338+
seed: row.seed || 0,
339+
providerId: row.providerId || 0,
340+
model: row.model || ''
341+
}
274342
try { inputParams.value = JSON.parse(row.inputParams || '[]') } catch { inputParams.value = [] }
275343
try { outputParams.value = JSON.parse(row.outputParams || '[]') } catch { outputParams.value = [] }
276344
try { quickPrompts.value = JSON.parse(row.quickPrompts || '[]') } catch { quickPrompts.value = [] }
277345
parseCapabilities(row.capabilities || '')
278346
dialogVisible.value = true
279347
loadCapabilityOptions()
348+
loadAiProviders()
280349
}
281350
282351
function isImageIcon(icon: string): boolean {

‎JuggleNet6.Frontend/src/views/ai/AssistantRun.vue‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,12 @@ onMounted(async () => {
170170
const res: any = await request.get('/ai/providers/enabled')
171171
providers.value = res.data || []
172172
if (providers.value.length > 0) {
173-
providerId.value = providers.value[0].id
174-
currentModel.value = providers.value[0].model || ''
173+
// 优先助手配置的默认供应商/模型,否则取第一个启用供应商
174+
const ap = assistant.value?.providerId
175+
? providers.value.find((p: any) => p.id === assistant.value.providerId)
176+
: null
177+
providerId.value = ap?.id || providers.value[0].id
178+
currentModel.value = assistant.value?.model || ap?.model || providers.value[0].model || ''
175179
}
176180
} catch { /* 未配置供应商 */ }
177181
})

0 commit comments

Comments
 (0)