Skip to content

Commit 5d9718b

Browse files
committed
feat: AI 辅助知识库描述生成功能
1 parent fd9dc40 commit 5d9718b

File tree

6 files changed

+214
-4
lines changed

6 files changed

+214
-4
lines changed

server/routers/knowledge_router.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,3 +1295,66 @@ async def get_all_embedding_models_status(current_user: User = Depends(get_admin
12951295
except Exception as e:
12961296
logger.error(f"获取所有embedding模型状态失败: {e}, {traceback.format_exc()}")
12971297
return {"message": f"获取所有embedding模型状态失败: {e}", "status": {"models": {}, "total": 0, "available": 0}}
1298+
1299+
1300+
# =============================================================================
1301+
# === AI 辅助功能分组 ===
1302+
# =============================================================================
1303+
1304+
1305+
@knowledge.post("/generate-description")
1306+
async def generate_description(
1307+
name: str = Body(..., description="知识库名称"),
1308+
current_description: str = Body("", description="当前描述(可选,用于优化)"),
1309+
current_user: User = Depends(get_admin_user),
1310+
):
1311+
"""使用 LLM 生成或优化知识库描述
1312+
1313+
根据知识库名称和现有描述,使用 LLM 生成适合作为智能体工具描述的内容。
1314+
"""
1315+
from src.models import select_model
1316+
1317+
logger.debug(f"Generating description for knowledge base: {name}")
1318+
1319+
# 构建提示词
1320+
if current_description.strip():
1321+
prompt = textwrap.dedent(f"""
1322+
请帮我优化以下知识库的描述。
1323+
1324+
知识库名称: {name}
1325+
当前描述: {current_description}
1326+
1327+
要求:
1328+
1. 这个描述将作为智能体工具的描述使用
1329+
2. 智能体会根据知识库的标题和描述来选择合适的工具
1330+
3. 所以描述需要清晰、具体,说明该知识库包含什么内容、适合解答什么类型的问题
1331+
4. 描述应该简洁有力,通常 2-4 句话即可
1332+
5. 不要使用 Markdown 格式
1333+
1334+
请直接输出优化后的描述,不要有任何前缀说明。
1335+
""").strip()
1336+
else:
1337+
prompt = textwrap.dedent(f"""
1338+
请为以下知识库生成一个描述。
1339+
1340+
知识库名称: {name}
1341+
1342+
要求:
1343+
1. 这个描述将作为智能体工具的描述使用
1344+
2. 智能体会根据知识库的标题和描述来选择合适的工具
1345+
3. 所以描述需要清晰、具体,说明该知识库可能包含什么内容、适合解答什么类型的问题
1346+
4. 描述应该简洁有力,通常 2-4 句话即可
1347+
5. 不要使用 Markdown 格式
1348+
1349+
请直接输出描述,不要有任何前缀说明。
1350+
""").strip()
1351+
1352+
try:
1353+
model = select_model()
1354+
response = await asyncio.to_thread(model.call, prompt)
1355+
description = response.content.strip()
1356+
logger.debug(f"Generated description: {description}")
1357+
return {"description": description, "status": "success"}
1358+
except Exception as e:
1359+
logger.error(f"生成描述失败: {e}, {traceback.format_exc()}")
1360+
raise HTTPException(status_code=500, detail=f"生成描述失败: {e}")

web/src/apis/knowledge_api.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,19 @@ export const databaseApi = {
5353
*/
5454
deleteDatabase: async (dbId) => {
5555
return apiAdminDelete(`/api/knowledge/databases/${dbId}`)
56+
},
57+
58+
/**
59+
* 使用 AI 生成或优化知识库描述
60+
* @param {string} name - 知识库名称
61+
* @param {string} currentDescription - 当前描述(可选)
62+
* @returns {Promise} - 生成结果
63+
*/
64+
generateDescription: async (name, currentDescription = '') => {
65+
return apiAdminPost('/api/knowledge/generate-description', {
66+
name,
67+
current_description: currentDescription
68+
})
5669
}
5770
}
5871

web/src/components/AiTextarea.vue

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<template>
2+
<div class="ai-textarea-wrapper">
3+
<a-textarea
4+
:value="modelValue"
5+
@update:value="$emit('update:modelValue', $event)"
6+
:placeholder="placeholder"
7+
:rows="rows"
8+
:auto-size="autoSize"
9+
/>
10+
<a-tooltip v-if="name" title="使用 AI 生成或优化描述">
11+
<a-button
12+
class="ai-btn"
13+
type="text"
14+
size="small"
15+
:loading="loading"
16+
@click="generateDescription"
17+
>
18+
<template #icon>
19+
<svg v-if="!loading" viewBox="0 0 24 24" width="16" height="16" fill="currentColor">
20+
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
21+
</svg>
22+
</template>
23+
<span v-if="!loading" class="ai-text">AI</span>
24+
</a-button>
25+
</a-tooltip>
26+
</div>
27+
</template>
28+
29+
<script setup>
30+
import { ref } from 'vue'
31+
import { message } from 'ant-design-vue'
32+
import { databaseApi } from '@/apis/knowledge_api'
33+
34+
const props = defineProps({
35+
modelValue: {
36+
type: String,
37+
default: ''
38+
},
39+
name: {
40+
type: String,
41+
default: ''
42+
},
43+
placeholder: {
44+
type: String,
45+
default: ''
46+
},
47+
rows: {
48+
type: Number,
49+
default: 4
50+
},
51+
autoSize: {
52+
type: [Boolean, Object],
53+
default: false
54+
}
55+
})
56+
57+
const emit = defineEmits(['update:modelValue'])
58+
59+
const loading = ref(false)
60+
61+
const generateDescription = async () => {
62+
if (!props.name?.trim()) {
63+
message.warning('请先输入知识库名称')
64+
return
65+
}
66+
67+
loading.value = true
68+
try {
69+
const result = await databaseApi.generateDescription(props.name, props.modelValue)
70+
if (result.status === 'success' && result.description) {
71+
emit('update:modelValue', result.description)
72+
message.success('描述生成成功')
73+
} else {
74+
message.error(result.message || '生成失败')
75+
}
76+
} catch (error) {
77+
console.error('生成描述失败:', error)
78+
message.error(error.message || '生成描述失败')
79+
} finally {
80+
loading.value = false
81+
}
82+
}
83+
</script>
84+
85+
<style lang="less" scoped>
86+
.ai-textarea-wrapper {
87+
position: relative;
88+
89+
.ai-btn {
90+
position: absolute;
91+
top: 4px;
92+
right: 4px;
93+
z-index: 1;
94+
display: flex;
95+
align-items: center;
96+
gap: 2px;
97+
padding: 2px 6px;
98+
height: 24px;
99+
color: var(--main-color);
100+
background: var(--gray-50);
101+
border: 1px solid var(--gray-200);
102+
border-radius: 4px;
103+
font-size: 12px;
104+
transition: all 0.2s ease;
105+
106+
&:hover {
107+
background: var(--main-10);
108+
border-color: var(--main-color);
109+
}
110+
111+
.ai-text {
112+
font-weight: 500;
113+
}
114+
}
115+
116+
:deep(.ant-input) {
117+
padding-right: 50px;
118+
}
119+
}
120+
</style>

web/src/components/DatabaseHeader.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,12 @@
4545
<a-input v-model:value="editForm.name" placeholder="请输入知识库名称" />
4646
</a-form-item>
4747
<a-form-item label="知识库描述" name="description">
48-
<a-textarea v-model:value="editForm.description" placeholder="请输入知识库描述" :rows="4" />
48+
<AiTextarea
49+
v-model="editForm.description"
50+
:name="editForm.name"
51+
placeholder="请输入知识库描述"
52+
:rows="4"
53+
/>
4954
</a-form-item>
5055
<!-- 仅对 LightRAG 类型显示 LLM 配置 -->
5156
<a-form-item v-if="database.kb_type === 'lightrag'" label="语言模型 (LLM)" name="llm_info">
@@ -72,6 +77,7 @@ import {
7277
} from '@ant-design/icons-vue';
7378
import HeaderComponent from '@/components/HeaderComponent.vue';
7479
import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue';
80+
import AiTextarea from '@/components/AiTextarea.vue';
7581
import { h } from 'vue';
7682
7783
const router = useRouter();

web/src/components/KnowledgeBaseCard.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,12 @@
6565
<a-input v-model:value="editForm.name" placeholder="请输入知识库名称" />
6666
</a-form-item>
6767
<a-form-item label="知识库描述" name="description">
68-
<a-textarea v-model:value="editForm.description" placeholder="请输入知识库描述" :rows="4" />
68+
<AiTextarea
69+
v-model="editForm.description"
70+
:name="editForm.name"
71+
placeholder="请输入知识库描述"
72+
:rows="4"
73+
/>
6974
</a-form-item>
7075

7176
<a-form-item label="自动生成问题" name="auto_generate_questions">
@@ -99,6 +104,7 @@ import {
99104
CopyOutlined,
100105
} from '@ant-design/icons-vue';
101106
import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue';
107+
import AiTextarea from '@/components/AiTextarea.vue';
102108
103109
const router = useRouter();
104110
const store = useDatabaseStore();

web/src/views/DataBaseView.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,9 @@
8181

8282
<h3 style="margin-top: 20px;">知识库描述</h3>
8383
<p style="color: var(--gray-700); font-size: 14px;">在智能体流程中,这里的描述会作为工具的描述。智能体会根据知识库的标题和描述来选择合适的工具。所以这里描述的越详细,智能体越容易选择到合适的工具。</p>
84-
<a-textarea
85-
v-model:value="newDatabase.description"
84+
<AiTextarea
85+
v-model="newDatabase.description"
86+
:name="newDatabase.name"
8687
placeholder="新建知识库描述"
8788
:auto-size="{ minRows: 3, maxRows: 10 }"
8889
/>
@@ -244,6 +245,7 @@ import HeaderComponent from '@/components/HeaderComponent.vue';
244245
import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue';
245246
import EmbeddingModelSelector from '@/components/EmbeddingModelSelector.vue';
246247
import dayjs, { parseToShanghai } from '@/utils/time';
248+
import AiTextarea from '@/components/AiTextarea.vue';
247249
248250
const route = useRoute()
249251
const router = useRouter()

0 commit comments

Comments
 (0)