1
This commit is contained in:
@@ -12,6 +12,10 @@ export function getContractDetail(id) {
|
||||
return request.get('/contract/detail', { params: { id } })
|
||||
}
|
||||
|
||||
export function getContractSummary(id) {
|
||||
return request.get('/contract/summary', { params: { id } })
|
||||
}
|
||||
|
||||
export function deleteContract(id) {
|
||||
return request.post('/contract/delete', { id })
|
||||
}
|
||||
|
||||
+174
-45
@@ -9,7 +9,7 @@
|
||||
<el-upload drag :show-file-list="false" :http-request="doUpload" :disabled="uploading" accept=".txt,.md,.pdf,.docx,.doc,.html,.htm">
|
||||
<div class="upload-hint">
|
||||
<el-icon class="upload-icon"><UploadFilled /></el-icon>
|
||||
<div>上传合同文件,逐条款标注对应法律条文</div>
|
||||
<div>上传合同文件,识别合同条款法律风险</div>
|
||||
</div>
|
||||
</el-upload>
|
||||
</div>
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 任务列表 -->
|
||||
<el-card class="task-card" shadow="never">
|
||||
<template #header><span>标注任务</span></template>
|
||||
<template #header><span>风险审查任务</span></template>
|
||||
<el-table :data="tasks" v-loading="loading" size="default">
|
||||
<el-table-column prop="filename" label="合同文件" min-width="180" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
@@ -51,10 +51,11 @@
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<!-- 详情抽屉:条款 + 标注 -->
|
||||
<!-- 详情抽屉:条款 + 风险点 -->
|
||||
<el-drawer v-model="detailVisible" :title="detailTitle" size="80%" destroy-on-close>
|
||||
<div v-if="detail" class="detail-toolbar">
|
||||
<el-button type="primary" size="small" @click="exportAnnotated">导出标注版(HTML)</el-button>
|
||||
<el-button type="primary" size="small" @click="openSummary" :disabled="detail.task.status !== 2">风险报告</el-button>
|
||||
<el-button size="small" @click="exportAnnotated">导出风险审查版(HTML)</el-button>
|
||||
</div>
|
||||
<div v-if="detail" class="detail-body">
|
||||
<div class="clause-panel">
|
||||
@@ -66,27 +67,64 @@
|
||||
<div class="clause-preview">{{ cl.content.slice(0, 60) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mark-panel">
|
||||
<div class="risk-panel">
|
||||
<template v-if="activeClause">
|
||||
<div class="panel-title">标注结果({{ (marksFor(activeClause.id) || []).length }})</div>
|
||||
<div class="panel-title">风险识别({{ (risksFor(activeClause.id) || []).length }})</div>
|
||||
<div class="clause-full">
|
||||
<span class="clause-full-title">{{ activeClause.title }}</span>
|
||||
{{ activeClause.content }}
|
||||
</div>
|
||||
<div v-for="m in sortedMarks(activeClause.id)" :key="m.id" class="mark-card" :class="{ weak: m.score < 5 }">
|
||||
<div class="mark-head">
|
||||
<el-tag :type="scoreType(m.score)" size="small">{{ m.score }} 分</el-tag>
|
||||
<span class="mark-law">《{{ m.law_title }}》{{ m.law_item }}</span>
|
||||
<div v-for="r in risksFor(activeClause.id)" :key="r.id" class="risk-card" :class="r.level">
|
||||
<div class="risk-head">
|
||||
<el-tag :type="levelType(r.level)" size="small">{{ levelText(r.level) }}</el-tag>
|
||||
</div>
|
||||
<div class="mark-content">{{ m.content }}</div>
|
||||
<div class="mark-reason">{{ m.reason }}</div>
|
||||
<div class="risk-desc">{{ r.desc }}</div>
|
||||
<el-collapse v-if="(r.laws || []).length" class="risk-laws">
|
||||
<el-collapse-item :title="`法律依据(${r.laws.length})`">
|
||||
<div v-for="(law, i) in r.laws" :key="i" class="risk-law">
|
||||
<span class="law-title">《{{ law.law_title }}》{{ law.law_item }}</span>
|
||||
<div class="law-content">{{ law.content }}</div>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
<el-empty v-if="!(marksFor(activeClause.id) || []).length" description="暂无标注" :image-size="60" />
|
||||
<el-empty v-if="!(risksFor(activeClause.id) || []).length" description="未发现明显风险" :image-size="60" />
|
||||
</template>
|
||||
<el-empty v-else description="点击左侧条款查看标注" :image-size="80" />
|
||||
<el-empty v-else description="点击左侧条款查看风险识别" :image-size="80" />
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 风险报告弹窗 -->
|
||||
<el-dialog v-model="summaryVisible" title="合同风险报告" width="760px" top="4vh" destroy-on-close>
|
||||
<div v-loading="summaryLoading" class="summary-body">
|
||||
<template v-if="summary">
|
||||
<div class="summary-stats">
|
||||
<el-tag type="danger" size="small">高风险 {{ summary.high_count }}</el-tag>
|
||||
<el-tag type="warning" size="small">中风险 {{ summary.mid_count }}</el-tag>
|
||||
<el-tag type="primary" size="small">低风险 {{ summary.low_count }}</el-tag>
|
||||
<el-tag type="info" size="small">无风险条款 {{ summary.no_risk_clauses }} 条</el-tag>
|
||||
</div>
|
||||
<div class="summary-overview">{{ summary.overview }}</div>
|
||||
<div v-for="lv in ['high', 'mid', 'low']" :key="lv" class="summary-group">
|
||||
<div v-if="(summary.groups[lv] || []).length" class="summary-group-title" :class="lv">
|
||||
{{ levelText(lv) }}({{ summary.groups[lv].length }})
|
||||
</div>
|
||||
<div v-for="(item, i) in (summary.groups[lv] || [])" :key="i" class="summary-item" :class="lv">
|
||||
<div class="summary-item-head">
|
||||
<span class="summary-clause">{{ item.clause_title }}</span>
|
||||
<el-tag :type="levelType(lv)" size="small">{{ levelText(lv) }}</el-tag>
|
||||
</div>
|
||||
<div class="summary-item-desc">{{ item.risks[0].desc }}</div>
|
||||
<div v-for="(law, j) in (item.risks[0].laws || [])" :key="j" class="summary-law">
|
||||
<span class="law-title">《{{ law.law_title }}》{{ law.law_item }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-if="!summary.total" description="未发现明显法律风险" :image-size="60" />
|
||||
</template>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -95,7 +133,7 @@ import { onMounted, onUnmounted, computed, ref } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { UploadFilled } from '@element-plus/icons-vue'
|
||||
import { listDatasets } from '../api/dataset.js'
|
||||
import { uploadContract, listContracts, getContractDetail, deleteContract, exportAnnotatedContract } from '../api/contract.js'
|
||||
import { uploadContract, listContracts, getContractDetail, getContractSummary, deleteContract, exportAnnotatedContract } from '../api/contract.js'
|
||||
|
||||
const datasets = ref([])
|
||||
const dsIds = ref([])
|
||||
@@ -105,6 +143,9 @@ const loading = ref(false)
|
||||
const detailVisible = ref(false)
|
||||
const detail = ref(null)
|
||||
const activeClauseId = ref(null)
|
||||
const summaryVisible = ref(false)
|
||||
const summaryLoading = ref(false)
|
||||
const summary = ref(null)
|
||||
let pollTimer = null
|
||||
|
||||
const dsNameMap = computed(() => {
|
||||
@@ -125,11 +166,12 @@ onUnmounted(stopPolling)
|
||||
|
||||
function dsName(id) { return dsNameMap.value[id] || ('#' + id) }
|
||||
function parseDsIds(s) { return (s || '').split(',').filter(Boolean).map(Number) }
|
||||
function statusText(s) { return ['待处理', '标注中', '完成', '失败'][s] || '-' }
|
||||
function statusText(s) { return ['待处理', '审查中', '完成', '失败'][s] || '-' }
|
||||
function statusType(s) { return ['info', 'warning', 'success', 'danger'][s] || 'info' }
|
||||
function clauseStatusText(s) { return ['待处理', '标注中', '完成', '失败'][s] || '-' }
|
||||
function clauseStatusText(s) { return ['待处理', '审查中', '完成', '失败'][s] || '-' }
|
||||
function clauseStatusType(s) { return ['info', 'warning', 'success', 'danger'][s] || 'info' }
|
||||
function scoreType(score) { return score >= 8 ? 'success' : score >= 5 ? 'warning' : 'info' }
|
||||
function levelText(lv) { return { high: '高风险', mid: '中风险', low: '低风险' }[lv] || lv }
|
||||
function levelType(lv) { return { high: 'danger', mid: 'warning', low: 'primary' }[lv] || 'info' }
|
||||
|
||||
async function loadTasks() {
|
||||
loading.value = true
|
||||
@@ -167,7 +209,7 @@ async function doUpload({ file }) {
|
||||
formData.append('dataset_ids', JSON.stringify(dsIds.value))
|
||||
formData.append('file', file)
|
||||
await uploadContract(formData)
|
||||
ElMessage.success('已提交标注任务')
|
||||
ElMessage.success('已提交风险审查任务')
|
||||
await loadTasks()
|
||||
} catch (e) {
|
||||
ElMessage.error(e.message || '上传失败')
|
||||
@@ -186,6 +228,20 @@ async function openDetail(row) {
|
||||
}
|
||||
}
|
||||
|
||||
async function openSummary() {
|
||||
if (!detail.value) return
|
||||
summaryVisible.value = true
|
||||
summaryLoading.value = true
|
||||
summary.value = null
|
||||
try {
|
||||
summary.value = await getContractSummary(detail.value.task.id)
|
||||
} catch (e) {
|
||||
ElMessage.error(e.message || '生成报告失败')
|
||||
} finally {
|
||||
summaryLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function exportAnnotated() {
|
||||
if (!detail.value) return
|
||||
try {
|
||||
@@ -193,10 +249,10 @@ async function exportAnnotated() {
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = '标注版-' + detail.value.task.filename.replace(/\.[^.]+$/, '') + '.html'
|
||||
a.download = '风险审查-' + detail.value.task.filename.replace(/\.[^.]+$/, '') + '.html'
|
||||
a.click()
|
||||
URL.revokeObjectURL(url)
|
||||
ElMessage.success('已导出标注版')
|
||||
ElMessage.success('已导出风险审查版')
|
||||
} catch (e) {
|
||||
ElMessage.error(e.message || '导出失败')
|
||||
}
|
||||
@@ -204,7 +260,7 @@ async function exportAnnotated() {
|
||||
|
||||
async function removeTask(row) {
|
||||
try {
|
||||
await ElMessageBox.confirm('删除任务将同时删除条款与标注结果,确认?', '删除任务', { type: 'warning' })
|
||||
await ElMessageBox.confirm('删除任务将同时删除条款与风险识别结果,确认?', '删除任务', { type: 'warning' })
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
@@ -218,12 +274,8 @@ const activeClause = computed(() => {
|
||||
return detail.value.clauses.find(c => c.id === activeClauseId.value) || null
|
||||
})
|
||||
|
||||
function marksFor(clauseId) {
|
||||
return (detail.value && detail.value.marks && detail.value.marks[clauseId]) || []
|
||||
}
|
||||
|
||||
function sortedMarks(clauseId) {
|
||||
return [...marksFor(clauseId)].sort((a, b) => b.score - a.score)
|
||||
function risksFor(clauseId) {
|
||||
return (detail.value && detail.value.risks && detail.value.risks[clauseId]) || []
|
||||
}
|
||||
|
||||
const detailTitle = computed(() => detail.value ? detail.value.task.filename : '')
|
||||
@@ -253,6 +305,7 @@ const detailTitle = computed(() => detail.value ? detail.value.task.filename : '
|
||||
.detail-toolbar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.detail-body {
|
||||
@@ -297,7 +350,7 @@ const detailTitle = computed(() => detail.value ? detail.value.task.filename : '
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.mark-panel {
|
||||
.risk-panel {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@@ -315,37 +368,113 @@ const detailTitle = computed(() => detail.value ? detail.value.task.filename : '
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
.mark-card {
|
||||
.risk-card {
|
||||
border: 1px solid #e4e7ed;
|
||||
border-left: 3px solid #909399;
|
||||
border-radius: 8px;
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 10px;
|
||||
background: #fff;
|
||||
}
|
||||
.mark-card.weak {
|
||||
background: #fafafa;
|
||||
}
|
||||
.mark-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
.risk-card.high { border-left-color: #f56c6c; }
|
||||
.risk-card.mid { border-left-color: #e6a23c; }
|
||||
.risk-card.low { border-left-color: #409eff; }
|
||||
.risk-head {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.mark-law {
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
.mark-content {
|
||||
.risk-desc {
|
||||
font-size: 13px;
|
||||
color: #303133;
|
||||
line-height: 1.7;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.risk-laws {
|
||||
margin-top: 4px;
|
||||
}
|
||||
.risk-law {
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
line-height: 1.7;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.mark-reason {
|
||||
.risk-law .law-title {
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
.law-content {
|
||||
font-size: 12px;
|
||||
color: #409eff;
|
||||
background: #ecf5ff;
|
||||
color: #909399;
|
||||
margin-top: 2px;
|
||||
background: #fafafa;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
/* 风险报告弹窗 */
|
||||
.summary-body {
|
||||
min-height: 200px;
|
||||
}
|
||||
.summary-stats {
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.summary-overview {
|
||||
background: #f0f9eb;
|
||||
border-left: 3px solid #67c23a;
|
||||
border-radius: 0 6px 6px 0;
|
||||
padding: 10px 12px;
|
||||
font-size: 13px;
|
||||
line-height: 1.8;
|
||||
color: #303133;
|
||||
white-space: pre-wrap;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.summary-group {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.summary-group-title {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
padding-left: 8px;
|
||||
border-left: 3px solid #909399;
|
||||
}
|
||||
.summary-group-title.high { border-left-color: #f56c6c; color: #f56c6c; }
|
||||
.summary-group-title.mid { border-left-color: #e6a23c; color: #e6a23c; }
|
||||
.summary-group-title.low { border-left-color: #409eff; color: #409eff; }
|
||||
.summary-item {
|
||||
border: 1px solid #e4e7ed;
|
||||
border-left: 3px solid #909399;
|
||||
border-radius: 6px;
|
||||
padding: 8px 10px;
|
||||
margin-bottom: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
.summary-item.high { border-left-color: #f56c6c; }
|
||||
.summary-item.mid { border-left-color: #e6a23c; }
|
||||
.summary-item.low { border-left-color: #409eff; }
|
||||
.summary-item-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.summary-clause {
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
color: #409eff;
|
||||
}
|
||||
.summary-item-desc {
|
||||
font-size: 13px;
|
||||
color: #303133;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.summary-law {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
.summary-law .law-title {
|
||||
color: #409eff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -27,43 +27,67 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog v-model="dialogVisible" :title="editing ? '编辑数据集' : '新建数据集'" width="480px">
|
||||
<el-dialog v-model="dialogVisible" :title="editing ? '编辑数据集' : '新建数据集'" width="640px">
|
||||
<el-form :model="form" label-width="90px">
|
||||
<el-form-item label="名称" required>
|
||||
<el-input v-model="form.name" placeholder="如:产品手册" />
|
||||
</el-form-item>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="名称" required>
|
||||
<el-input v-model="form.name" placeholder="如:产品手册" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="向量模型" required>
|
||||
<el-select v-model="form.embedding_cfg_id" placeholder="请选择向量模型" style="width: 100%">
|
||||
<el-option v-for="m in embedders" :key="m.id" :label="m.name" :value="m.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="描述">
|
||||
<el-input v-model="form.description" type="textarea" :rows="2" />
|
||||
</el-form-item>
|
||||
<el-form-item label="向量模型" required>
|
||||
<el-select v-model="form.embedding_cfg_id" placeholder="请选择向量模型" style="width: 100%">
|
||||
<el-option v-for="m in embedders" :key="m.id" :label="m.name" :value="m.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="分块大小">
|
||||
<el-input-number v-model="form.chunk_size" :min="50" :max="5000" :step="50" style="width: 100%" />
|
||||
<div class="ds-tip">每块最大字数。系统自动组合分块策略:优先识别文档结构(条文/章节/编号等)按结构切分,无结构时依次按标题感知、语义、递归切分</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="重叠字数">
|
||||
<el-input-number v-model="form.chunk_overlap" :min="0" :max="500" :step="10" style="width: 100%" />
|
||||
<div class="ds-tip">相邻分块间的重叠字数,用于保持上下文连贯(语义切分路径自动忽略)</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="智能体轮次">
|
||||
<el-input-number v-model="form.react_rounds" :min="0" :max="10" :step="1" style="width: 100%" />
|
||||
<div class="ds-tip">0=关闭(单次检索问答);1~10=启用 ReAct 智能体模式,模型可自主多次调用检索工具,此为轮次上限</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="向量召回数">
|
||||
<el-input-number v-model="form.vec_top_k" :min="-1" :max="50" :step="1" style="width: 100%" />
|
||||
<div class="ds-tip">向量检索原始召回数。0=全局默认(20),-1=尽量多(上限100),正数=固定值</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="全文召回数">
|
||||
<el-input-number v-model="form.fts_top_k" :min="-1" :max="50" :step="1" style="width: 100%" />
|
||||
<div class="ds-tip">全文检索(BM25)原始召回数。0=全局默认(20),-1=尽量多(上限100),正数=固定值</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="重排候选数">
|
||||
<el-input-number v-model="form.rerank_top_k" :min="-1" :max="50" :step="1" style="width: 100%" />
|
||||
<div class="ds-tip">融合后喂给 LLM 重排的候选数,需 ≥ 最终返回数。0=全局默认(10),-1=尽量多(上限60)</div>
|
||||
</el-form-item>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="分块大小">
|
||||
<el-input-number v-model="form.chunk_size" :min="50" :max="5000" :step="50" style="width: 100%" />
|
||||
<div class="ds-tip">每块最大字数。系统自动组合分块策略:优先识别文档结构(条文/章节/编号等)按结构切分,无结构时依次按标题感知、语义、递归切分</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="重叠字数">
|
||||
<el-input-number v-model="form.chunk_overlap" :min="0" :max="500" :step="10" style="width: 100%" />
|
||||
<div class="ds-tip">相邻分块间的重叠字数,用于保持上下文连贯(语义切分路径自动忽略)</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="智能体轮次">
|
||||
<el-input-number v-model="form.react_rounds" :min="0" :max="10" :step="1" style="width: 100%" />
|
||||
<div class="ds-tip">0=关闭(单次检索问答);1~10=启用 ReAct 智能体模式,模型可自主多次调用检索工具,此为轮次上限</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="向量召回数">
|
||||
<el-input-number v-model="form.vec_top_k" :min="-1" :max="50" :step="1" style="width: 100%" />
|
||||
<div class="ds-tip">向量检索原始召回数。0=全局默认(20),-1=尽量多(上限100),正数=固定值</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="全文召回数">
|
||||
<el-input-number v-model="form.fts_top_k" :min="-1" :max="50" :step="1" style="width: 100%" />
|
||||
<div class="ds-tip">全文检索(BM25)原始召回数。0=全局默认(20),-1=尽量多(上限100),正数=固定值</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="重排候选数">
|
||||
<el-input-number v-model="form.rerank_top_k" :min="-1" :max="50" :step="1" style="width: 100%" />
|
||||
<div class="ds-tip">融合后喂给 LLM 重排的候选数,需 ≥ 最终返回数。0=全局默认(10),-1=尽量多(上限60)</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="最终返回数">
|
||||
<el-input-number v-model="form.recall_top_k" :min="-1" :max="50" :step="1" style="width: 100%" />
|
||||
<div class="ds-tip">重排后最终返回给回答的引用条数。0=全局默认(5),-1=全部召回(不限制条数,达到相关性门槛的全部返回,仅受总字符物理保护),正数=固定条数</div>
|
||||
|
||||
Reference in New Issue
Block a user