feat: 支持 Agent 并发批测与洞察导出

This commit is contained in:
2026-08-13 17:25:22 +08:00
parent 3faecab6ac
commit f952d6dc58
22 changed files with 666 additions and 44 deletions

View File

@@ -15,6 +15,8 @@ const props = defineProps<{
const fileInput = ref<HTMLInputElement | null>(null);
const selectedFile = ref<File | null>(null);
const taskName = ref("");
const executionMode = ref<"sequential" | "concurrent">("sequential");
const concurrencyLimit = ref(5);
const creating = ref(false);
const loading = ref(false);
const exportingId = ref<number | null>(null);
@@ -81,7 +83,12 @@ async function createJob() {
if (!String(props.config.modelId || "")) return ElMessage.warning("请先在调试配置中选择模型");
creating.value = true;
try {
const created = await api.createAgentBatch(selectedFile.value, { ...props.config, name: taskName.value.trim() });
const created = await api.createAgentBatch(selectedFile.value, {
...props.config,
name: taskName.value.trim(),
executionMode: executionMode.value,
concurrencyLimit: executionMode.value === "sequential" ? 1 : concurrencyLimit.value,
});
ElMessage.success(`已创建批量测试任务,共 ${created.totalCount} 个问题`);
clearFile();
taskName.value = "";
@@ -154,6 +161,10 @@ function statusType(status: string) {
return "warning";
}
function executionLabel(job: AgentBatchJob) {
return job.executionMode === "concurrent" ? `并发 · ${job.concurrencyLimit}` : "逐条串行";
}
function formatDate(value?: string | null) {
return value ? new Date(value).toLocaleString("zh-CN", { hour12: false }) : "—";
}
@@ -170,7 +181,7 @@ function errorMessage(error: unknown, fallback: string) {
<template>
<div class="agent-batch-panel">
<div class="agent-section-intro">
<div><h3>Excel 批量测试</h3><p>使用当前编辑框中的提示词调试模型知识库和生成参数创建配置快照后台逐条生成答案</p></div>
<div><h3>Excel 批量测试</h3><p>普通管理员仅看到自己的任务超级管理员可统一审计创建时会固化当前提示词模型知识库和生成参数</p></div>
<el-button @click="downloadTemplate">下载导入模板</el-button>
</div>
@@ -180,6 +191,14 @@ function errorMessage(error: unknown, fallback: string) {
<span><small>知识库</small><strong>{{ knowledgeSummary }}</strong></span>
<span><small>单次上限</small><strong>200 个问题</strong></span>
</div>
<div class="agent-batch-mode-setting">
<div class="agent-batch-mode-copy"><strong>执行方式</strong><span>串行适合日常回归并发适合压测吞吐与稳定性并发数会被系统安全上限约束</span></div>
<el-radio-group v-model="executionMode" class="agent-batch-mode-options">
<el-radio-button value="sequential">逐条串行</el-radio-button>
<el-radio-button value="concurrent">并发测试</el-radio-button>
</el-radio-group>
<label v-if="executionMode === 'concurrent'" class="agent-batch-concurrency"><span>并发数</span><el-input-number v-model="concurrencyLimit" :min="2" :max="10" controls-position="right" /></label>
</div>
<div class="agent-batch-upload-row">
<label class="agent-batch-name"><span>任务名称</span><input v-model="taskName" maxlength="160" placeholder="例如8月主提示词回归测试" /></label>
<label class="agent-batch-file" :class="{ selected: selectedFile }">
@@ -197,6 +216,7 @@ function errorMessage(error: unknown, fallback: string) {
<el-table-column label="任务" min-width="190"><template #default="{ row }"><strong>{{ row.name }}</strong><small class="agent-batch-cell-note">#{{ row.id }} · {{ formatDate(row.createdAt) }}</small></template></el-table-column>
<el-table-column label="配置快照" min-width="180"><template #default="{ row }"><span>{{ row.modelName }}</span><small class="agent-batch-cell-note">{{ row.knowledgeNames.join('、') }}</small></template></el-table-column>
<el-table-column label="进度" min-width="190"><template #default="{ row }"><el-progress :percentage="row.progress" :status="row.status === 'completed' ? 'success' : undefined" /><small class="agent-batch-cell-note">{{ row.processedCount }}/{{ row.totalCount }} · 成功 {{ row.successCount }} · 失败 {{ row.failedCount }}</small></template></el-table-column>
<el-table-column label="执行方式" width="118"><template #default="{ row }"><el-tag type="info">{{ executionLabel(row) }}</el-tag></template></el-table-column>
<el-table-column label="状态" width="108"><template #default="{ row }"><el-tag :type="statusType(row.status)">{{ statusLabel(row.status) }}</el-tag></template></el-table-column>
<el-table-column label="操作" width="190" fixed="right"><template #default="{ row }"><el-button link type="primary" @click="openDetail(row)">查看</el-button><el-button link type="primary" :loading="exportingId === row.id" @click="exportJob(row)">导出</el-button><el-button v-if="['pending','running'].includes(row.status)" link type="danger" @click="cancelJob(row)">取消</el-button></template></el-table-column>
</el-table>
@@ -207,7 +227,7 @@ function errorMessage(error: unknown, fallback: string) {
<div v-loading="detailLoading" class="agent-batch-detail">
<template v-if="selectedJob">
<div class="agent-batch-detail-head">
<div><strong>{{ selectedJob.name }}</strong><span>{{ selectedJob.modelName }} · {{ selectedJob.knowledgeNames.join('、') }}</span></div>
<div><strong>{{ selectedJob.name }}</strong><span>{{ selectedJob.modelName }} · {{ selectedJob.knowledgeNames.join('、') }} · {{ executionLabel(selectedJob) }}</span></div>
<el-tag :type="statusType(selectedJob.status)">{{ statusLabel(selectedJob.status) }}</el-tag>
</div>
<el-table :data="selectedJob.items.items" stripe max-height="520">