feat(S2): max_tokens dynamic from template, remove hardcoded 500
- PromptTemplate model: add max_tokens (default 500) and example_input fields - generate_with_llm: read max_tokens from template, accept override param - api_prompt_generate: accept optional max_tokens with 100-4096 clamp - Vue: add advanced options toggle with max_tokens input - Vue: auto-populate max_tokens from selected template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -81,6 +81,8 @@ class PromptTemplate(db.Model):
|
||||
sub_category = db.Column(db.String(50))
|
||||
system_prompt = db.Column(db.Text, nullable=False)
|
||||
is_default = db.Column(db.Boolean, default=False)
|
||||
max_tokens = db.Column(db.Integer, default=500)
|
||||
example_input = db.Column(db.Text)
|
||||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
|
||||
class MealPlan(db.Model):
|
||||
|
||||
@@ -49,20 +49,28 @@ def get_system_prompt(template_id=None):
|
||||
|
||||
请直接返回优化后的提示词,不要添加任何解释或其他内容。"""
|
||||
|
||||
def generate_with_llm(input_text, template_id=None, max_retries=3):
|
||||
def generate_with_llm(input_text, template_id=None, max_retries=3, max_tokens=None):
|
||||
"""调用大模型API生成提示词,带重试机制"""
|
||||
import time
|
||||
|
||||
|
||||
system_prompt = get_system_prompt(template_id)
|
||||
start_time = time.time() # 记录开始时间
|
||||
|
||||
|
||||
# 确定 max_tokens: 参数传入 > 模板配置 > 默认 500
|
||||
_max_tokens = max_tokens or 500
|
||||
if not max_tokens and template_id:
|
||||
template = PromptTemplate.query.get(template_id)
|
||||
if template and template.max_tokens:
|
||||
_max_tokens = template.max_tokens
|
||||
|
||||
# 记录参数到日志
|
||||
current_app.logger.info("=== API 调用参数 ===")
|
||||
current_app.logger.info(f"模板ID: {template_id}")
|
||||
current_app.logger.info(f"输入文本: {input_text}")
|
||||
current_app.logger.info(f"系统提示: {system_prompt}")
|
||||
current_app.logger.info(f"max_tokens: {_max_tokens}")
|
||||
current_app.logger.info("==================")
|
||||
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
response = client.chat.completions.create(
|
||||
@@ -72,7 +80,7 @@ def generate_with_llm(input_text, template_id=None, max_retries=3):
|
||||
{"role": "user", "content": input_text}
|
||||
],
|
||||
temperature=0.7,
|
||||
max_tokens=500,
|
||||
max_tokens=_max_tokens,
|
||||
timeout=60 # 设置60秒超时
|
||||
)
|
||||
|
||||
@@ -342,6 +350,7 @@ def get_templates_by_category(category):
|
||||
'profession': template.profession,
|
||||
'sub_category': template.sub_category,
|
||||
'system_prompt': template.system_prompt,
|
||||
'max_tokens': template.max_tokens or 500,
|
||||
'sample_input': build_sample_input_text(template),
|
||||
}
|
||||
template_list.append(template_dict)
|
||||
@@ -401,8 +410,18 @@ def api_prompt_generate():
|
||||
if len(input_text) > 1000:
|
||||
return jsonify({'success': False, 'message': '需求描述请勿超过 1000 字'}), 400
|
||||
|
||||
# 可选 max_tokens 覆盖
|
||||
_mt = data.get('max_tokens')
|
||||
_max_tokens = None
|
||||
if _mt is not None and _mt != '':
|
||||
try:
|
||||
_max_tokens = int(_mt)
|
||||
_max_tokens = max(100, min(4096, _max_tokens))
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
|
||||
try:
|
||||
generated_text = generate_with_llm(input_text, template_id)
|
||||
generated_text = generate_with_llm(input_text, template_id, max_tokens=_max_tokens)
|
||||
if not generated_text or (
|
||||
isinstance(generated_text, str) and generated_text.startswith('提示词生成失败')
|
||||
):
|
||||
|
||||
@@ -14,6 +14,6 @@ export function fetchTemplatesByCategory(category: string) {
|
||||
return client.get<TemplatesByCategoryResponse>(path).then((r) => r.data)
|
||||
}
|
||||
|
||||
export function generatePrompt(body: { input_text: string; template_id: number | null }) {
|
||||
export function generatePrompt(body: { input_text: string; template_id: number | null; max_tokens?: number }) {
|
||||
return client.post<GeneratePromptResponse>('/api/prompt/generate', body).then((r) => r.data)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface PromptTemplateItem {
|
||||
profession: string | null
|
||||
sub_category: string | null
|
||||
system_prompt: string
|
||||
max_tokens: number
|
||||
sample_input: string
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ const selectedTemplateId = ref<number | undefined>(undefined)
|
||||
|
||||
const inputText = ref('')
|
||||
const autoFillSample = ref(true)
|
||||
const showAdvanced = ref(false)
|
||||
const maxTokensOverride = ref<number | undefined>(undefined)
|
||||
|
||||
const result = ref<{ id: number; input_text: string; generated_text: string } | null>(null)
|
||||
|
||||
@@ -100,9 +102,11 @@ watch(filteredTemplates, (list) => {
|
||||
})
|
||||
|
||||
watch(selectedTemplateId, (id) => {
|
||||
if (!autoFillSample.value || id == null) return
|
||||
const t = templates.value.find((x) => x.id === id)
|
||||
if (t?.sample_input) inputText.value = t.sample_input
|
||||
if (id != null) {
|
||||
const t = templates.value.find((x) => x.id === id)
|
||||
if (autoFillSample.value && t?.sample_input) inputText.value = t.sample_input
|
||||
maxTokensOverride.value = t?.max_tokens || undefined
|
||||
}
|
||||
})
|
||||
|
||||
async function loadMeta() {
|
||||
@@ -201,6 +205,7 @@ async function onSubmit() {
|
||||
const res = await generatePrompt({
|
||||
input_text: text,
|
||||
template_id: selectedTemplateId.value,
|
||||
max_tokens: maxTokensOverride.value,
|
||||
})
|
||||
if (!res.success) {
|
||||
ElMessage.error(res.message || '生成失败')
|
||||
@@ -356,9 +361,27 @@ onMounted(async () => {
|
||||
placeholder="请描述目标、背景、约束与期望输出…"
|
||||
/>
|
||||
<div class="actions">
|
||||
<el-button type="primary" size="large" :loading="generating" @click="onSubmit">
|
||||
生成专业提示词
|
||||
</el-button>
|
||||
<el-space>
|
||||
<el-button type="primary" size="large" :loading="generating" @click="onSubmit">
|
||||
生成专业提示词
|
||||
</el-button>
|
||||
<el-button text type="info" @click="showAdvanced = !showAdvanced">
|
||||
{{ showAdvanced ? '收起' : '高级选项' }}
|
||||
</el-button>
|
||||
</el-space>
|
||||
</div>
|
||||
<div v-if="showAdvanced" class="advanced-options">
|
||||
<el-form-item label="输出长度 (tokens)" label-width="140px">
|
||||
<el-input-number
|
||||
v-model="maxTokensOverride"
|
||||
:min="100"
|
||||
:max="4096"
|
||||
:step="100"
|
||||
placeholder="由模板决定"
|
||||
style="width: 220px"
|
||||
/>
|
||||
<span class="hint">留空由模板决定,范围 100–4096</span>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user