mirror of
http://112.124.100.131/ebiz-ai/ebiz-ai-knowledge-manage.git
synced 2025-12-06 09:26:48 +08:00
feat(knowledge): 新增知识库检索设置功能
- 添加检索设置相关 API 和功能组件 - 实现嵌入式模型列表获取和选择 - 添加重新排序模型配置功能 - 实现权重设置和混合检索功能 - 优化检索设置界面布局和交互
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
module.exports = {
|
||||
presets: ['@vue/app'],
|
||||
plugins: [
|
||||
[
|
||||
'transform-remove-console',
|
||||
{
|
||||
exclude: ['warn', 'error'] // 可选:保留 warn 和 error
|
||||
}
|
||||
]
|
||||
// [
|
||||
// 'transform-remove-console',
|
||||
// {
|
||||
// exclude: ['warn', 'error'] // 可选:保留 warn 和 error
|
||||
// }
|
||||
// ]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ handle.set('layout', false)
|
||||
* @param e {MessageEvent}
|
||||
*/
|
||||
self.onmessage = function initHandler(e) {
|
||||
const {ports = [], data} = e
|
||||
const { ports = [], data } = e
|
||||
// console.log(`Worker收到消息:`, data)
|
||||
// 只处理初始化消息
|
||||
if (data !== 'init-worker' || ports.length === 0) {
|
||||
@@ -36,7 +36,7 @@ self.onmessage = function initHandler(e) {
|
||||
function messageHandler(event) {
|
||||
// console.log('has been received event',event)
|
||||
|
||||
if (handle.has(event.data.type)){
|
||||
if (handle.has(event.data.type)) {
|
||||
self.port.postMessage(handle.get(event.data.type))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,3 +10,22 @@ export function getRerankModels() {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description 知识库检索模式配置
|
||||
*/
|
||||
export function retrievalSetting(data) {
|
||||
return request({
|
||||
url: getUrl('/datasets/detailConfigEx/retrievalSetting'),
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description 查询系统支持的embedding模型列表
|
||||
*/
|
||||
export function getEmbeddingModels() {
|
||||
return request({
|
||||
url: getUrl('/third/models/text-embedding'),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
let envInfo = process.env
|
||||
let [admin, jifen, zixi, hz] = [
|
||||
envInfo.VUE_APP_ADMIN,
|
||||
'http://192.168.2.62:7196/',
|
||||
'http://192.168.8.58:7196/',
|
||||
'http://192.168.8.165:7196/',
|
||||
'http://10.147.17.161:7196/'
|
||||
]
|
||||
|
||||
@@ -1,51 +1,31 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer
|
||||
title="搜索设置"
|
||||
title="检索设置"
|
||||
:visible.sync="visible"
|
||||
size="50%"
|
||||
size="40%"
|
||||
@close="handleClose"
|
||||
>
|
||||
<el-form ref="form" :model="form" label-width="80%" label-position="top">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-col :span="10">
|
||||
<el-form-item label="Embedding模型">
|
||||
<el-select v-model="form.embeddingModel" placeholder="请选择">
|
||||
<el-select
|
||||
v-model="form.embeddingModel"
|
||||
@change="getModel"
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in modelList"
|
||||
:key="item.value"
|
||||
:key="item.model"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:value="item.model"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- <el-form-item label="检索设置">
|
||||
<div class="flex justify-content-b">
|
||||
<div
|
||||
v-for="(item, index) in settingList"
|
||||
:key="item.name"
|
||||
class="setting_item flex"
|
||||
:class="{ activeItem: index === activeIndex }"
|
||||
@click="handleClick(index)"
|
||||
>
|
||||
<img
|
||||
src="@/assets/images/konwledge/knowledge-5.png"
|
||||
alt=""
|
||||
style="height: 40px"
|
||||
/>
|
||||
<div class="ml10">
|
||||
<p class="fwb label fs15">
|
||||
{{ item.name }}
|
||||
<span v-if="index === 2" class="point fs12 ml10">推荐</span>
|
||||
</p>
|
||||
<p class="desc">{{ item.desc }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>-->
|
||||
<el-collapse v-model="activeName" accordion>
|
||||
<el-collapse v-model="searchMethod" accordion>
|
||||
<el-collapse-item
|
||||
v-for="(item, index) in settingList"
|
||||
:key="item.name"
|
||||
@@ -69,16 +49,28 @@
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<search-form :activeIndex="activeName"></search-form>
|
||||
<search-form
|
||||
ref="searchForm"
|
||||
:searchMethod="searchMethod"
|
||||
:embeddingItem="embeddingItem"
|
||||
@handleClose="handleClose"
|
||||
></search-form>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-form>
|
||||
<div class="demo-drawer__footer mt10 text-right">
|
||||
<el-button @click="handleCancel" size="medium">取 消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" size="medium"
|
||||
>保存</el-button
|
||||
>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import SearchForm from '@/views/knowledge/detail/components/SearchSetting/SearchForm.vue'
|
||||
import { getEmbeddingModels } from '@/api/knowledge/hit-test'
|
||||
|
||||
export default {
|
||||
name: 'SearchSetting',
|
||||
@@ -86,7 +78,9 @@ export default {
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
activeName: 0,
|
||||
// 0-向量检索 1-全文检索 2-混合检索
|
||||
searchMethod: 0,
|
||||
embeddingItem: {},
|
||||
visible: false,
|
||||
form: {
|
||||
embeddingModel: '',
|
||||
@@ -116,15 +110,38 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getModelList()
|
||||
},
|
||||
methods: {
|
||||
// 获取Embedding模型列表
|
||||
getModelList() {
|
||||
getEmbeddingModels().then(res => {
|
||||
if (res) {
|
||||
const { content } = res.content
|
||||
this.modelList = content.flatMap(item => item.models)
|
||||
}
|
||||
})
|
||||
},
|
||||
init() {
|
||||
this.visible = true
|
||||
},
|
||||
handleClose() {
|
||||
this.$emit('close')
|
||||
this.visible = false
|
||||
},
|
||||
handleClick(index) {
|
||||
this.activeIndex = index
|
||||
handleSubmit() {
|
||||
console.log(this.$refs.searchForm)
|
||||
this.$refs.searchForm[this.searchMethod].submitData()
|
||||
// this.$refs.searchForm.submitData()
|
||||
},
|
||||
handleCancel() {
|
||||
this.visible = false
|
||||
},
|
||||
getModel() {
|
||||
console.log(this.form.embeddingModel)
|
||||
this.embeddingItem = this.modelList.find(
|
||||
item => item.model === this.form.embeddingModel
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="pl10 searchForm_cont">
|
||||
<el-form :model="form" label-width="80%" label-position="top">
|
||||
<el-form-item label="">
|
||||
<el-switch v-model="form.modelOpen"></el-switch>
|
||||
<el-form :model="form" label-width="80%" label-position="top" class="pt20">
|
||||
<el-form-item label="" v-if="searchMethod !== 2">
|
||||
<el-switch v-model="form.rerankingEnable"></el-switch>
|
||||
<span>Rerank 模型</span>
|
||||
<el-tooltip
|
||||
class="item"
|
||||
@@ -13,26 +13,80 @@
|
||||
<i class="el-icon-info ml5" style="color: #909399;"></i>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-row v-if="activeIndex === 2">
|
||||
<el-slider v-model="value" :marks="marks"> </el-slider
|
||||
></el-row>
|
||||
<el-row v-else>
|
||||
<el-col :span="8">
|
||||
<!-- 混合检索 -->
|
||||
<div v-if="searchMethod === 2" class="flex mb20">
|
||||
<div
|
||||
class="fixItem flex"
|
||||
v-for="(item, index) in fixSearchList"
|
||||
:key="index"
|
||||
@click="chooseFixSearch(item)"
|
||||
>
|
||||
<img
|
||||
src="@/assets/images/konwledge/knowledge-2.png"
|
||||
alt=""
|
||||
style="height: 30px"
|
||||
/>
|
||||
<div class="ml10">
|
||||
<div class="flex justify-content-b">
|
||||
<p>{{ item.name }}</p>
|
||||
<i
|
||||
class="el-icon-check"
|
||||
v-if="item.isCheck"
|
||||
style="color: #4f47f5"
|
||||
></i>
|
||||
</div>
|
||||
|
||||
<p>{{ item.desc }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-row
|
||||
v-if="
|
||||
(form.rerankingEnable && searchMethod !== 2) ||
|
||||
(searchMethod === 2 && fixSearchList[1].isCheck === true)
|
||||
"
|
||||
>
|
||||
<el-col :span="10">
|
||||
<el-form-item label="">
|
||||
<el-select v-model="form.embeddingModel" placeholder="请选择">
|
||||
<el-select
|
||||
v-model="form.rerankingModelName"
|
||||
@change="getRankModel"
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in modelList"
|
||||
:key="item.value"
|
||||
v-for="item in rankModelList"
|
||||
:key="item.model"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:value="item.model"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-row v-if="searchMethod === 2 && fixSearchList[0].isCheck === true">
|
||||
<RSlider
|
||||
v-model="form.weights"
|
||||
:hit-test="true"
|
||||
:show-tooltip="false"
|
||||
@input="getWeight"
|
||||
style="width: 98%"
|
||||
/>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<!-- Top K -->
|
||||
<el-col :span="10" class="flex">
|
||||
<el-form-item label="Top K">
|
||||
<el-form-item label="">
|
||||
<div class="flex align-items-c">
|
||||
<p class="ml5 fwb">Top K</p>
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
content="用于筛选与用户问题相似度最高的文档片段。系统同时会根据选用模型上下文窗口大小动态调整分段数量。"
|
||||
placement="top"
|
||||
>
|
||||
<i class="el-icon-info ml5" style="color: #909399;"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-input-number
|
||||
v-model="form.topK"
|
||||
:min="1"
|
||||
@@ -42,53 +96,169 @@
|
||||
size="mini"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
<div style="width: 300px;">
|
||||
<el-slider v-model="value" :min="1" :max="10" :step="1"></el-slider>
|
||||
<div class="ml20 mt40" style="width: 80%;">
|
||||
<el-slider
|
||||
v-model="form.topK"
|
||||
:min="1"
|
||||
:max="10"
|
||||
:step="1"
|
||||
></el-slider>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="10">
|
||||
<el-form-item label="Score阈值">
|
||||
<el-slider
|
||||
v-model="value"
|
||||
show-input
|
||||
show-input-controls
|
||||
<!-- Score阈值-->
|
||||
<el-col :span="10" class="flex">
|
||||
<el-form-item label="">
|
||||
<template slot="label">
|
||||
<div class="flex align-items-c">
|
||||
<el-switch v-model="form.scoreThresholdEnabled"></el-switch>
|
||||
<p class="ml5 fwb">Score阈值</p>
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
content="用于设置文本片段筛选的相似度阈值"
|
||||
placement="top"
|
||||
>
|
||||
<i class="el-icon-info ml5" style="color: #909399;"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="form.scoreThreshold"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
:precision="2"
|
||||
></el-slider>
|
||||
label="Top K"
|
||||
controls-position="right"
|
||||
size="mini"
|
||||
:disabled="!form.scoreThresholdEnabled"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
<div class="ml20 mt40" style="width: 80%;">
|
||||
<el-slider
|
||||
v-model="form.scoreThreshold"
|
||||
:disabled="!form.scoreThresholdEnabled"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
></el-slider>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getRerankModels, retrievalSetting } from '@/api/knowledge/hit-test'
|
||||
|
||||
export default {
|
||||
name: 'SearchForm',
|
||||
props: {
|
||||
activeIndex: {
|
||||
searchMethod: {
|
||||
type: Number
|
||||
},
|
||||
embeddingItem: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
modelOpen: true,
|
||||
embeddingModel: 'sentence-transformers/all-MiniLM-L6-v2',
|
||||
topK: 3,
|
||||
scoreThreshold: 0.5
|
||||
// 是否启用rerank模型
|
||||
rerankingEnable: true,
|
||||
// Rerank模型
|
||||
rerankingModelName: '',
|
||||
rerankingProviderName: '',
|
||||
|
||||
topK: 0,
|
||||
|
||||
// 是否启用score阈值
|
||||
scoreThresholdEnabled: false,
|
||||
// score阈值
|
||||
scoreThreshold: 0,
|
||||
|
||||
// 混合模式- reranking_model:使用rerank模型; weighted_score:使用权重
|
||||
rerankingMode: '',
|
||||
// 关键词
|
||||
keywordWeight: 0,
|
||||
// 语义
|
||||
vectorWeight: 0
|
||||
},
|
||||
modelList: [
|
||||
rankModelList: [
|
||||
{
|
||||
value: 'sentence-transformers/all-MiniLM-L6-v2',
|
||||
label: 'sentence-transformers/all-MiniLM-L6-v2'
|
||||
},
|
||||
{}
|
||||
],
|
||||
fixSearchList: [
|
||||
{
|
||||
name: '权重设置',
|
||||
desc:
|
||||
'通过调整分配的权重,重新排序策略确定是优先进行语义匹配还是关键字匹配',
|
||||
isCheck: true,
|
||||
value: 'weighted_score'
|
||||
},
|
||||
{
|
||||
name: 'Rerank 模型',
|
||||
value: 'reranking_model',
|
||||
desc:
|
||||
'重排序模型将根据候选文档列表与用户问题语义匹配度进行重新排序,从而改进语义排序的结果'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getRerankModelList()
|
||||
},
|
||||
methods: {
|
||||
getRerankModelList() {
|
||||
getRerankModels().then(res => {
|
||||
if (res) {
|
||||
const { content } = res.content
|
||||
this.rankModelList = content.flatMap(item => item.models)
|
||||
}
|
||||
})
|
||||
},
|
||||
getRankModel() {
|
||||
let rankItem = this.rankModelList.find(
|
||||
item => item.model === this.form.rerankingModelName
|
||||
)
|
||||
this.form.rerankingProviderName = rankItem.provider
|
||||
},
|
||||
chooseFixSearch(val) {
|
||||
this.fixSearchList.forEach(item => {
|
||||
item.isCheck = false
|
||||
})
|
||||
val.isCheck = true
|
||||
this.form.rerankingMode = val.value
|
||||
},
|
||||
getWeight(val) {
|
||||
console.log(val)
|
||||
},
|
||||
submitData() {
|
||||
let params = {
|
||||
datasetId: this.$route.query.datasetId,
|
||||
searchMethod: this.searchMethod,
|
||||
embeddingModel: this.embeddingItem.model,
|
||||
embeddingModelProvider: this.embeddingItem.provider,
|
||||
...this.form
|
||||
}
|
||||
params.rerankingEnable = this.handleBoolean(this.form.rerankingEnable)
|
||||
params.scoreThresholdEnabled = this.handleBoolean(
|
||||
this.form.scoreThresholdEnabled
|
||||
)
|
||||
retrievalSetting(params).then(res => {
|
||||
if (res) {
|
||||
this.$message.success('保存成功')
|
||||
this.$emit('handleClose')
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
handleBoolean(val) {
|
||||
let value = JSON.parse(JSON.stringify(val))
|
||||
return value ? 1 : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -100,4 +270,10 @@ export default {
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
border-radius: 0 5px 5px 0;
|
||||
}
|
||||
.fixItem {
|
||||
border: 1px solid #ebeef5;
|
||||
margin-right: 10px;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,14 +15,15 @@
|
||||
<li
|
||||
v-for="(item, index) in list"
|
||||
:key="index"
|
||||
class="block flex justify-content-b"
|
||||
class="block flex justify-content-b "
|
||||
style="align-items: baseline"
|
||||
>
|
||||
<div class="flex">
|
||||
<div class="flex" style="align-items: baseline">
|
||||
<i class="el-icon-reading"></i>
|
||||
<p class="ml5 mr5">{{ item.metadataKey }}</p>
|
||||
<p>{{ item.dataType }}</p>
|
||||
<p class="ml5 mr10">{{ item.metadataKey }}</p>
|
||||
<p class="fs12">{{ item.dataType }}</p>
|
||||
</div>
|
||||
<div class="flex align-items-c">
|
||||
<div class="flex align-items-c" >
|
||||
<div class="amount">{{ item.amount ? item.amount :0}}个值</div>
|
||||
<div class="action-buttons">
|
||||
<el-button
|
||||
|
||||
@@ -65,14 +65,14 @@
|
||||
@click="jumpEditKnowledge"
|
||||
>修改知识库
|
||||
</el-button>
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- size="medium"-->
|
||||
<!-- icon="el-icon-search"-->
|
||||
<!-- class="line-button"-->
|
||||
<!-- @click="searchSetting"-->
|
||||
<!-- >检索设置-->
|
||||
<!-- </el-button>-->
|
||||
<el-button
|
||||
type="primary"
|
||||
size="medium"
|
||||
icon="el-icon-search"
|
||||
class="line-button"
|
||||
@click="searchSetting"
|
||||
>检索设置
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-s-promotion"
|
||||
|
||||
Reference in New Issue
Block a user