feat(data-process): 增加可配置思维链生成

This commit is contained in:
caoxiaozhu
2026-07-27 14:41:38 +08:00
parent 97cdb5cc68
commit f97245b814
12 changed files with 224 additions and 29 deletions

View File

@@ -5,6 +5,7 @@ export type DataProcessType = 'structured' | 'unstructured' | 'external'
export type DataProcessResultStatus = 'valid' | 'modified' | 'invalid'
export type DataProcessSplit = 'train' | 'validation' | 'test'
export type DataProcessOutputType = 'standard' | 'reasoning'
export type DataProcessReasoningDetail = 'normal' | 'detailed'
export interface DataProcessPage<T> {
items: T[]
@@ -22,6 +23,7 @@ export interface DataProcessDatasetSplit {
export type DataProcessConfig = Record<string, unknown> & {
dataset_split?: DataProcessDatasetSplit
output_type?: DataProcessOutputType
reasoning_detail?: DataProcessReasoningDetail
}
export interface DataProcessTask {

View File

@@ -202,6 +202,7 @@ function toBackendConfig(): DataProcessConfig {
generation_model_id: options.generationModelId,
generation_prompt: options.generationPrompt,
output_type: options.outputType,
reasoning_detail: options.reasoningDetail,
temperature: options.temperature,
max_tokens: options.maxTokens,
json_mode: options.jsonMode,
@@ -210,7 +211,6 @@ function toBackendConfig(): DataProcessConfig {
filter_short_content: options.filterShortContent,
min_output_length: options.minOutputLength,
}
if (processType.value === 'unstructured') {
return {
...common,

View File

@@ -71,6 +71,7 @@ const configLabelMap: Record<string, string> = {
generation_model_id: '数据生成模型',
generation_prompt: '生成提示语',
output_type: '输出类型',
reasoning_detail: '推理详细程度',
temperature: '生成温度',
max_tokens: '最大输出长度',
json_mode: 'JSON 输出',
@@ -225,15 +226,19 @@ const durationText = computed(() => {
return minutes ? `${minutes}${restSeconds}` : `${restSeconds}`
})
const configRows = computed(() => Object.entries(detail.value?.config || {})
.filter(([key]) => (
key !== 'generation_model_snapshot'
&& !/(?:password|secret|token|api_key)/i.test(key)
))
.map(([key, value]) => ({
label: configLabelMap[key] || key.split('_').join(' '),
value: formatConfigValue(key, value),
})))
const configRows = computed(() => {
const config = detail.value?.config || {}
return Object.entries(config)
.filter(([key]) => (
key !== 'generation_model_snapshot'
&& (key !== 'reasoning_detail' || config.output_type === 'reasoning')
&& !/(?:password|secret|token|api_key)/i.test(key)
))
.map(([key, value]) => ({
label: configLabelMap[key] || key.split('_').join(' '),
value: formatConfigValue(key, value),
}))
})
function formatConfigValue(key: string, value: unknown) {
if (key === 'generation_model_id') {
@@ -249,6 +254,9 @@ function formatConfigValue(key: string, value: unknown) {
if (key === 'output_type') {
return value === 'reasoning' ? '思维链回答' : '标准回答'
}
if (key === 'reasoning_detail') {
return value === 'detailed' ? '详细推理' : '普通推理'
}
if (key === 'dataset_split' && value && typeof value === 'object') {
const split = value as Partial<DataProcessDatasetSplit>
return `训练集 ${split.train ?? 0}% / 验证集 ${split.validation ?? 0}% / 测试集 ${split.test ?? 0}%`

View File

@@ -1,7 +1,10 @@
<script setup lang="ts">
import { ref } from 'vue'
import type { ModelItem } from '@/types'
import type { GenerationControlOptions } from './types'
import {
defaultGenerationPrompt,
isBuiltInGenerationPrompt,
} from './dataProcessCreateState'
const props = defineProps<{
options: GenerationControlOptions
@@ -31,7 +34,18 @@ function updateQualityRules(value: Array<string | number>) {
}
function updateOutputType(value: string | number | boolean | undefined) {
updateField('outputType', value === 'reasoning' ? 'reasoning' : 'standard')
const outputType = value === 'reasoning' ? 'reasoning' : 'standard'
emit('update:options', {
...props.options,
outputType,
generationPrompt: isBuiltInGenerationPrompt(props.options.generationPrompt)
? defaultGenerationPrompt(outputType)
: props.options.generationPrompt,
})
}
function updateReasoningDetail(value: string | number | boolean | undefined) {
updateField('reasoningDetail', value === 'detailed' ? 'detailed' : 'normal')
}
const selectedQualityRules = () => [
@@ -91,7 +105,10 @@ function modelMeta(model: ModelItem) {
<div class="model-field">
<div class="field-copy">
<strong>默认提示语</strong>
<small>用于约束生成内容的格式语气和完整性可按任务需要修改</small>
<small v-if="options.outputType === 'reasoning'">
当前使用思维链专用提示语系统还会按所选详细程度约束推理结构
</small>
<small v-else>当前使用标准回答提示语只要求问题和最终答案</small>
</div>
<el-input
class="prompt-input"
@@ -177,9 +194,28 @@ function modelMeta(model: ModelItem) {
<el-option label="思维链回答" value="reasoning" />
</el-select>
</div>
<div v-if="options.outputType === 'reasoning'" class="output-type-row">
<div class="field-copy">
<strong>推理详细程度</strong>
<small>控制推理过程保留关键步骤或完整展开依据与中间推导</small>
</div>
<el-select
class="output-type-select"
:model-value="options.reasoningDetail"
aria-label="推理详细程度"
@update:model-value="updateReasoningDetail"
>
<el-option label="普通推理(推荐)" value="normal" />
<el-option label="详细推理" value="detailed" />
</el-select>
</div>
<p class="output-type-hint">
<template v-if="options.outputType === 'reasoning'">
生成结果将按 <code>&lt;think&gt;推理过程&lt;/think&gt;</code>
<template v-if="options.reasoningDetail === 'detailed'">
完整展开条件来源依据中间推导和结论核对
</template>
<template v-else>保留关键依据与必要步骤</template>
最终按 <code>&lt;think&gt;推理过程&lt;/think&gt;</code>
</template>
<template v-else>仅保存最终答案不包含推理过程</template>
</p>

View File

@@ -9,7 +9,25 @@ import type {
} from './types'
import { normalizeQaPairsGenerationCount } from './types'
export const DEFAULT_GENERATION_PROMPT = '你是一名专业的数据生成助手。请根据输入内容生成准确、完整、可直接用于模型训练的问答数据。仅输出符合所选输出类型和目标格式的内容,答案应事实清晰、语言自然,不要添加无关说明。'
const LEGACY_DEFAULT_GENERATION_PROMPT = '你是一名专业的数据生成助手。请根据输入内容生成准确、完整、可直接用于模型训练的问答数据。仅输出符合所选输出类型和目标格式的内容,答案应事实清晰、语言自然,不要添加无关说明。'
export const DEFAULT_STANDARD_GENERATION_PROMPT = '你是一名专业的数据生成助手。请严格依据输入内容生成准确、完整、可直接用于监督微调的问答数据。只生成问题和最终答案,不输出分析、推理过程或来源中不存在的信息;答案应事实清晰、语言自然。'
export const DEFAULT_REASONING_GENERATION_PROMPT = '你是一名专业的推理数据生成助手。请严格依据输入内容生成问题、可核验的推理过程和最终答案。推理需要说明关键依据与必要步骤,不得引入来源中不存在的事实;最终答案应准确、完整且语言自然。'
export function defaultGenerationPrompt(outputType: 'standard' | 'reasoning') {
return outputType === 'reasoning'
? DEFAULT_REASONING_GENERATION_PROMPT
: DEFAULT_STANDARD_GENERATION_PROMPT
}
export function isBuiltInGenerationPrompt(value: string) {
return [
LEGACY_DEFAULT_GENERATION_PROMPT,
DEFAULT_STANDARD_GENERATION_PROMPT,
DEFAULT_REASONING_GENERATION_PROMPT,
].includes(value)
}
export function createDefaultStructuredOptions(): StructuredProcessOptions {
return {
@@ -18,8 +36,9 @@ export function createDefaultStructuredOptions(): StructuredProcessOptions {
qaPairsPerRow: 1,
datasetSplit: { train: 80, validation: 10, test: 10 },
generationModelId: '',
generationPrompt: DEFAULT_GENERATION_PROMPT,
generationPrompt: DEFAULT_STANDARD_GENERATION_PROMPT,
outputType: 'standard',
reasoningDetail: 'normal',
temperature: 0.7,
maxTokens: 1024,
jsonMode: false,
@@ -52,8 +71,9 @@ export function createDefaultUnstructuredOptions(): UnstructuredProcessOptions {
qaPairsPerChunk: 1,
datasetSplit: { train: 80, validation: 10, test: 10 },
generationModelId: '',
generationPrompt: DEFAULT_GENERATION_PROMPT,
generationPrompt: DEFAULT_STANDARD_GENERATION_PROMPT,
outputType: 'standard',
reasoningDetail: 'normal',
temperature: 0.7,
maxTokens: 1024,
jsonMode: false,
@@ -92,12 +112,21 @@ function generationOptionsFromConfig(
config: DataProcessConfig,
defaults: GenerationControlOptions,
): GenerationControlOptions {
const outputType = configValue(config, 'output_type', defaults.outputType) === 'reasoning'
? 'reasoning'
: 'standard'
const configuredPrompt = String(
configValue(config, 'generation_prompt', defaults.generationPrompt),
)
return {
generationModelId: configValue(config, 'generation_model_id', defaults.generationModelId),
generationPrompt: String(configValue(config, 'generation_prompt', defaults.generationPrompt)),
outputType: configValue(config, 'output_type', defaults.outputType) === 'reasoning'
? 'reasoning'
: 'standard',
generationPrompt: isBuiltInGenerationPrompt(configuredPrompt)
? defaultGenerationPrompt(outputType)
: configuredPrompt,
outputType,
reasoningDetail: configValue(config, 'reasoning_detail', defaults.reasoningDetail) === 'detailed'
? 'detailed'
: 'normal',
temperature: numberValue(config, 'temperature', defaults.temperature),
maxTokens: numberValue(config, 'max_tokens', defaults.maxTokens),
jsonMode: Boolean(configValue(config, 'json_mode', defaults.jsonMode)),
@@ -224,6 +253,7 @@ export function generationAffectingOptionsFor(
generationModelId: options.generationModelId,
generationPrompt: options.generationPrompt,
outputType: options.outputType,
reasoningDetail: options.reasoningDetail,
temperature: options.temperature,
maxTokens: options.maxTokens,
jsonMode: options.jsonMode,

View File

@@ -1,4 +1,8 @@
import type { DataProcessOutputType, DataProcessPreviewFileStatus } from '@/types/dataProcess'
import type {
DataProcessOutputType,
DataProcessPreviewFileStatus,
DataProcessReasoningDetail,
} from '@/types/dataProcess'
export type ProcessType = 'structured' | 'unstructured' | 'external'
@@ -33,6 +37,7 @@ export interface GenerationControlOptions {
generationModelId: string | number | ''
generationPrompt: string
outputType: DataProcessOutputType
reasoningDetail: DataProcessReasoningDetail
temperature: number
maxTokens: number
jsonMode: boolean