feat(chatbot): 增强智能体工具和知识库集成能力

- 在智能体上下文中添加知识库字段,支持从知识库中选择工具
- 重构工具获取逻辑,支持根据上下文动态加载工具
- 优化前端知识库创建和加载逻辑,移入 store 管理
- 改进工具调用结果渲染,支持知识库工具识别
- 添加 clear-btn 样式改进
This commit is contained in:
Wenjie Zhang 2025-12-30 19:01:45 +08:00
parent 34fbd1a13e
commit 8087ef4b00
10 changed files with 187 additions and 128 deletions

View File

@ -3,6 +3,7 @@ from typing import Annotated
from src.agents.common import BaseContext, gen_tool_info from src.agents.common import BaseContext, gen_tool_info
from src.agents.common.mcp import MCP_SERVERS from src.agents.common.mcp import MCP_SERVERS
from src.knowledge import knowledge_base
from .tools import get_tools from .tools import get_tools
@ -14,7 +15,17 @@ class Context(BaseContext):
metadata={ metadata={
"name": "工具", "name": "工具",
"options": lambda: gen_tool_info(get_tools()), # 这里的选择是所有的工具 "options": lambda: gen_tool_info(get_tools()), # 这里的选择是所有的工具
"description": "工具列表", "description": "内置的部分工具,包含 common 工具和本智能体的特有工具(不含 MCP",
},
)
knowledges: list[str] = field(
default_factory=list,
metadata={
"name": "知识库",
"options": lambda: [k["name"] for k in knowledge_base.get_retrievers().values()],
"description": "知识库列表,可以在左侧知识库页面中创建知识库。",
"type": "list", # Explicitly mark as list type for frontend if needed
}, },
) )
@ -23,6 +34,8 @@ class Context(BaseContext):
metadata={ metadata={
"name": "MCP服务器", "name": "MCP服务器",
"options": lambda: list(MCP_SERVERS.keys()), "options": lambda: list(MCP_SERVERS.keys()),
"description": "MCP服务器列表", "description": (
"MCP服务器列表建议使用支持 SSE 的 MCP 服务器,"
"如果需要使用 uvx 或 npx 运行的服务器,也请在项目外部启动 MCP 服务器,并在项目中配置 MCP 服务器。"),
}, },
) )

View File

@ -2,14 +2,13 @@ from langchain.agents import create_agent
from langchain.agents.middleware import ModelRetryMiddleware from langchain.agents.middleware import ModelRetryMiddleware
from src.agents.common import BaseAgent, load_chat_model from src.agents.common import BaseAgent, load_chat_model
from src.agents.common.mcp import MCP_SERVERS from src.agents.common.mcp import get_mcp_tools
from src.agents.common.middlewares import ( from src.agents.common.middlewares import (
DynamicToolMiddleware,
context_aware_prompt, context_aware_prompt,
context_based_model, context_based_model,
inject_attachment_context, inject_attachment_context,
) )
from src.agents.common.subagents import calc_agent_tool from src.agents.common.tools import get_kb_based_tools
from .context import Context from .context import Context
from .tools import get_tools from .tools import get_tools
@ -18,7 +17,7 @@ from .tools import get_tools
class ChatbotAgent(BaseAgent): class ChatbotAgent(BaseAgent):
name = "智能体助手" name = "智能体助手"
description = "基础的对话机器人,可以回答问题,默认不使用任何工具,可在配置中启用需要的工具。" description = "基础的对话机器人,可以回答问题,默认不使用任何工具,可在配置中启用需要的工具。"
capabilities = ["file_upload"] # 支持文件上传功能 capabilities = ["file_upload", "reload_graph"] # 支持文件上传功能和重载图
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
@ -26,34 +25,48 @@ class ChatbotAgent(BaseAgent):
self.checkpointer = None self.checkpointer = None
self.context_schema = Context self.context_schema = Context
def get_tools(self): async def get_tools(self, tools: list[str] = None, mcps=None, knowledges=None):
"""返回基本工具"""
base_tools = get_tools() # 1. 基础工具 (从 context.tools 中筛选)
base_tools.append(calc_agent_tool) all_basic_tools = get_tools()
return base_tools selected_tools = []
if tools:
# 创建工具映射表
tools_map = {t.name: t for t in all_basic_tools}
for tool_name in tools:
if tool_name in tools_map:
selected_tools.append(tools_map[tool_name])
# 2. 知识库工具
if knowledges:
kb_tools = get_kb_based_tools(db_names=knowledges)
selected_tools.extend(kb_tools)
# 3. MCP 工具
if mcps:
for server_name in mcps:
mcp_tools = await get_mcp_tools(server_name)
selected_tools.extend(mcp_tools)
return selected_tools
async def get_graph(self, **kwargs): async def get_graph(self, **kwargs):
"""构建图""" """构建图"""
if self.graph: if self.graph:
return self.graph return self.graph
# 创建动态工具中间件实例,并传入所有可用的 MCP 服务器列表 # 获取上下文配置
dynamic_tool_middleware = DynamicToolMiddleware( context = self.context_schema.from_file(module_name=self.module_name)
base_tools=self.get_tools(), mcp_servers=list(MCP_SERVERS.keys())
)
# 预加载所有 MCP 工具并注册到 middleware.tools # 使用 create_agent 创建智能体
await dynamic_tool_middleware.initialize_mcp_tools()
# 使用 create_agent 创建智能体,并传入 middleware
graph = create_agent( graph = create_agent(
model=load_chat_model("siliconflow/Qwen/Qwen3-235B-A22B-Instruct-2507"), # 默认模型,会被 middleware 覆盖 model=load_chat_model(context.model), # 使用 context 中的模型配置
tools=get_tools(), # 注册基础工具 tools=await self.get_tools(context.tools, context.mcps, context.knowledges),
middleware=[ middleware=[
context_aware_prompt, # 动态系统提示词 context_aware_prompt, # 动态系统提示词
inject_attachment_context, # 附件上下文注入LangChain 标准中间件) inject_attachment_context, # 附件上下文注入
context_based_model, # 动态模型选择 context_based_model, # 动态模型选择
dynamic_tool_middleware, # 动态工具选择(支持 MCP 工具注册)
ModelRetryMiddleware(), # 模型重试中间件 ModelRetryMiddleware(), # 模型重试中间件
], ],
checkpointer=await self._get_checkpointer(), checkpointer=await self._get_checkpointer(),
@ -69,4 +82,4 @@ def main():
if __name__ == "__main__": if __name__ == "__main__":
main() main()
# asyncio.run(main()) # asyncio.run(main())

View File

@ -6,6 +6,7 @@ import requests
from langchain.tools import tool from langchain.tools import tool
from src.agents.common import get_buildin_tools from src.agents.common import get_buildin_tools
from src.agents.common.subagents import calc_agent_tool
from src.storage.minio import aupload_file_to_minio from src.storage.minio import aupload_file_to_minio
from src.utils import logger from src.utils import logger
@ -51,4 +52,5 @@ def get_tools() -> list[Any]:
"""获取所有可运行的工具(给大模型使用)""" """获取所有可运行的工具(给大模型使用)"""
tools = get_buildin_tools() tools = get_buildin_tools()
tools.append(text_to_img_demo) tools.append(text_to_img_demo)
tools.append(calc_agent_tool)
return tools return tools

View File

@ -46,7 +46,11 @@ class BaseContext:
model: Annotated[str, {"__template_metadata__": {"kind": "llm"}}] = field( model: Annotated[str, {"__template_metadata__": {"kind": "llm"}}] = field(
default=sys_config.default_model, default=sys_config.default_model,
metadata={"name": "智能体模型", "options": [], "description": "智能体的驱动模型"}, metadata={
"name": "智能体模型",
"options": [],
"description": "智能体的驱动模型,建议选择 Agent 能力较强的模型,不建议使用小参数模型。"
},
) )
@classmethod @classmethod

View File

@ -11,7 +11,7 @@ from pydantic import BaseModel, Field
from src import config, graph_base, knowledge_base from src import config, graph_base, knowledge_base
from src.utils import logger from src.utils import logger
search = TavilySearch(max_results=10) search = TavilySearch()
search.metadata = {"name": "Tavily 网页搜索"} search.metadata = {"name": "Tavily 网页搜索"}
@ -122,11 +122,12 @@ class KnowledgeRetrieverModel(BaseModel):
) )
def get_kb_based_tools() -> list: def get_kb_based_tools(db_names: list[str] | None = None) -> list:
"""获取所有知识库基于的工具""" """获取所有知识库基于的工具"""
# 获取所有知识库 # 获取所有知识库
kb_tools = [] kb_tools = []
retrievers = knowledge_base.get_retrievers() retrievers = knowledge_base.get_retrievers()
db_ids = [kb_id for kb_id, kb in retrievers.items() if kb["name"] in db_names] or None
def _create_retriever_wrapper(db_id: str, retriever_info: dict[str, Any]): def _create_retriever_wrapper(db_id: str, retriever_info: dict[str, Any]):
"""创建检索器包装函数的工厂函数,避免闭包变量捕获问题""" """创建检索器包装函数的工厂函数,避免闭包变量捕获问题"""
@ -185,6 +186,9 @@ def get_kb_based_tools() -> list:
return async_retriever_wrapper return async_retriever_wrapper
for db_id, retrieve_info in retrievers.items(): for db_id, retrieve_info in retrievers.items():
if db_ids is not None and db_id not in db_ids:
continue
try: try:
# 构建工具描述 # 构建工具描述
description = ( description = (
@ -227,8 +231,6 @@ def get_buildin_tools() -> list:
tools = [] tools = []
try: try:
# 获取所有知识库基于的工具
tools.extend(get_kb_based_tools())
tools.extend(get_static_tools()) tools.extend(get_static_tools())
from src.agents.common.toolkits.mysql.tools import get_mysql_tools from src.agents.common.toolkits.mysql.tools import get_mysql_tools

View File

@ -152,6 +152,7 @@
<a-button <a-button
type="link" type="link"
size="small" size="small"
class="clear-btn"
@click="clearSelection(key)" @click="clearSelection(key)"
v-if="getSelectedCount(key) > 0" v-if="getSelectedCount(key) > 0"
> >
@ -819,12 +820,6 @@ const resetConfig = async () => {
color: var(--gray-900); color: var(--gray-900);
font-weight: 500; font-weight: 500;
} }
.clear-btn {
padding: 0;
height: auto;
font-size: 12px;
}
} }
.select-tools-btn { .select-tools-btn {
@ -1133,6 +1128,19 @@ const resetConfig = async () => {
} }
} }
.clear-btn {
padding: 0;
height: auto;
font-size: 12px;
font-weight: 600;
color: var(--main-700);
&:hover {
color: var(--main-800);
}
}
// //
@media (max-width: 768px) { @media (max-width: 768px) {
.agent-config-sidebar.open { .agent-config-sidebar.open {

View File

@ -35,6 +35,7 @@
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import BaseToolCall from './BaseToolCall.vue'; import BaseToolCall from './BaseToolCall.vue';
import { useAgentStore } from '@/stores/agent'; import { useAgentStore } from '@/stores/agent';
import { useDatabaseStore } from '@/stores/database';
import WebSearchTool from './tools/WebSearchTool.vue'; import WebSearchTool from './tools/WebSearchTool.vue';
import KnowledgeBaseTool from './tools/KnowledgeBaseTool.vue'; import KnowledgeBaseTool from './tools/KnowledgeBaseTool.vue';
@ -53,13 +54,18 @@ const props = defineProps({
}); });
const agentStore = useAgentStore(); const agentStore = useAgentStore();
const databaseStore = useDatabaseStore();
const toolName = computed(() => props.toolCall.name || props.toolCall.function?.name || ''); const toolName = computed(() => props.toolCall.name || props.toolCall.function?.name || '');
const tool = computed(() => { const tool = computed(() => {
const toolsList = agentStore?.availableTools ? Object.values(agentStore.availableTools) : []; const toolsList = agentStore?.availableTools ? Object.values(agentStore.availableTools) : [];
return toolsList.find(t => t.name === toolName.value) || null; const tool = toolsList.find(t => t.name === toolName.value)
return tool || null;
}); });
const databases = computed(() => databaseStore.databases || []);
const parseData = (content) => { const parseData = (content) => {
if (typeof content === 'string') { if (typeof content === 'string') {
try { try {
@ -90,17 +96,9 @@ const isTaskResult = computed(() => {
}); });
const isKnowledgeBaseResult = computed(() => { const isKnowledgeBaseResult = computed(() => {
const currentTool = tool.value; const databaseInfo = databases.value.find(db => db.name === toolName.value);
if (databaseInfo && databaseInfo.kb_type !== 'lightrag') {
if (currentTool && currentTool.metadata) { return true
const metadata = currentTool.metadata;
const hasKnowledgebaseTag = metadata.tag && metadata.tag.includes('knowledgebase');
const isNotLightrag = metadata.kb_type !== 'lightrag';
if (hasKnowledgebaseTag && isNotLightrag) {
// const data = parseData(props.toolCall.tool_call_result?.content);
// return Array.isArray(data) && data.length > 0;
return true
}
} }
return false; return false;
}); });

View File

@ -1,9 +1,7 @@
<script setup> <script setup>
import { ref, reactive, onMounted, useTemplateRef, computed, provide } from 'vue' import { ref, reactive, onMounted, useTemplateRef, computed, provide } from 'vue'
import { RouterLink, RouterView, useRoute } from 'vue-router' import { RouterLink, RouterView, useRoute } from 'vue-router'
import { import { GithubOutlined } from '@ant-design/icons-vue'
GithubOutlined,
} from '@ant-design/icons-vue'
import { Bot, Waypoints, LibraryBig, BarChart3, CircleCheck } from 'lucide-vue-next'; import { Bot, Waypoints, LibraryBig, BarChart3, CircleCheck } from 'lucide-vue-next';
import { onLongPress } from '@vueuse/core' import { onLongPress } from '@vueuse/core'
@ -69,7 +67,7 @@ const getRemoteConfig = () => {
} }
const getRemoteDatabase = () => { const getRemoteDatabase = () => {
databaseStore.getDatabaseInfo(undefined, false) // Explicitly load query params for remote database databaseStore.loadDatabases()
} }
// Fetch GitHub stars count // Fetch GitHub stars count

View File

@ -5,21 +5,25 @@ import { message, Modal } from 'ant-design-vue';
import { databaseApi, documentApi, queryApi } from '@/apis/knowledge_api'; import { databaseApi, documentApi, queryApi } from '@/apis/knowledge_api';
import { useTaskerStore } from '@/stores/tasker'; import { useTaskerStore } from '@/stores/tasker';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { parseToShanghai } from '@/utils/time';
export const useDatabaseStore = defineStore('database', () => { export const useDatabaseStore = defineStore('database', () => {
const router = useRouter(); const router = useRouter();
const taskerStore = useTaskerStore(); const taskerStore = useTaskerStore();
// State // State
const databases = ref([]);
const database = ref({}); const database = ref({});
const databaseId = ref(null); const databaseId = ref(null);
const selectedFile = ref(null); const selectedFile = ref(null);
const queryParams = ref([]); const queryParams = ref([]);
const meta = reactive({}); const meta = reactive({});
const selectedRowKeys = ref([]); const selectedRowKeys = ref([]);
const state = reactive({ const state = reactive({
listLoading: false,
creating: false,
databaseLoading: false, databaseLoading: false,
refrashing: false, refrashing: false,
searchLoading: false, searchLoading: false,
@ -38,6 +42,64 @@ export const useDatabaseStore = defineStore('database', () => {
let autoRefreshManualOverride = false; // Indicates user explicitly disabled auto-refresh let autoRefreshManualOverride = false; // Indicates user explicitly disabled auto-refresh
// Actions // Actions
async function loadDatabases() {
state.listLoading = true;
try {
const data = await databaseApi.getDatabases();
databases.value = data.databases.sort((a, b) => {
const timeA = parseToShanghai(a.created_at);
const timeB = parseToShanghai(b.created_at);
if (!timeA && !timeB) return 0;
if (!timeA) return 1;
if (!timeB) return -1;
return timeB.valueOf() - timeA.valueOf(); // 降序排列,最新的在前面
});
} catch (error) {
console.error('加载数据库列表失败:', error);
if (error.message.includes('权限')) {
message.error('需要管理员权限访问知识库');
}
throw error;
} finally {
state.listLoading = false;
}
}
async function createDatabase(formData) {
// 验证
if (!formData.database_name?.trim()) {
message.error('数据库名称不能为空');
return false;
}
if (!formData.kb_type) {
message.error('请选择知识库类型');
return false;
}
// 向量数据库的重排序模型验证
if (['chroma', 'milvus'].includes(formData.kb_type)) {
if (formData.reranker_config?.enabled && !formData.reranker_config?.model) {
message.error('请选择重排序模型');
return false;
}
}
state.creating = true;
try {
const data = await databaseApi.createDatabase(formData);
message.success('创建成功');
await loadDatabases(); // 刷新列表
return data;
} catch (error) {
console.error('创建数据库失败:', error);
message.error(error.message || '创建失败');
throw error;
} finally {
state.creating = false;
}
}
async function getDatabaseInfo(id, skipQueryParams = false) { async function getDatabaseInfo(id, skipQueryParams = false) {
const db_id = id || databaseId.value; const db_id = id || databaseId.value;
if (!db_id) return; if (!db_id) return;
@ -404,6 +466,7 @@ export const useDatabaseStore = defineStore('database', () => {
} }
return { return {
databases,
database, database,
databaseId, databaseId,
selectedFile, selectedFile,
@ -411,6 +474,8 @@ export const useDatabaseStore = defineStore('database', () => {
meta, meta,
selectedRowKeys, selectedRowKeys,
state, state,
loadDatabases,
createDatabase,
getDatabaseInfo, getDatabaseInfo,
updateDatabaseInfo, updateDatabaseInfo,
deleteDatabase, deleteDatabase,

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="database-container layout-container"> <div class="database-container layout-container">
<HeaderComponent title="文档知识库" :loading="state.loading"> <HeaderComponent title="文档知识库" :loading="dbState.listLoading">
<template #actions> <template #actions>
<a-button type="primary" @click="state.openNewDatabaseModel=true"> <a-button type="primary" @click="state.openNewDatabaseModel=true">
新建知识库 新建知识库
@ -8,7 +8,7 @@
</template> </template>
</HeaderComponent> </HeaderComponent>
<a-modal :open="state.openNewDatabaseModel" title="新建知识库" @ok="createDatabase" @cancel="cancelCreateDatabase" class="new-database-modal" width="800px"> <a-modal :open="state.openNewDatabaseModel" title="新建知识库" @ok="handleCreateDatabase" @cancel="cancelCreateDatabase" class="new-database-modal" width="800px">
<!-- 知识库类型选择 --> <!-- 知识库类型选择 -->
<h3>知识库类型<span style="color: var(--color-error-500)">*</span></h3> <h3>知识库类型<span style="color: var(--color-error-500)">*</span></h3>
@ -162,12 +162,12 @@
</div> </div>
<template #footer> <template #footer>
<a-button key="back" @click="cancelCreateDatabase">取消</a-button> <a-button key="back" @click="cancelCreateDatabase">取消</a-button>
<a-button key="submit" type="primary" :loading="state.creating" @click="createDatabase">创建</a-button> <a-button key="submit" type="primary" :loading="dbState.creating" @click="handleCreateDatabase">创建</a-button>
</template> </template>
</a-modal> </a-modal>
<!-- 加载状态 --> <!-- 加载状态 -->
<div v-if="state.loading" class="loading-container"> <div v-if="dbState.listLoading" class="loading-container">
<a-spin size="large" /> <a-spin size="large" />
<p>正在加载知识库...</p> <p>正在加载知识库...</p>
</div> </div>
@ -235,11 +235,12 @@
<script setup> <script setup>
import { ref, onMounted, reactive, watch, computed } from 'vue' import { ref, onMounted, reactive, watch, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { storeToRefs } from 'pinia';
import { useConfigStore } from '@/stores/config'; import { useConfigStore } from '@/stores/config';
import { message } from 'ant-design-vue' import { useDatabaseStore } from '@/stores/database';
import { Database, Zap, FileDigit, Waypoints, Building2 } from 'lucide-vue-next'; import { Database, FileDigit, Waypoints, Building2 } from 'lucide-vue-next';
import { LockOutlined, InfoCircleOutlined, QuestionCircleOutlined, PlusOutlined } from '@ant-design/icons-vue'; import { LockOutlined, InfoCircleOutlined, QuestionCircleOutlined, PlusOutlined } from '@ant-design/icons-vue';
import { databaseApi, typeApi } from '@/apis/knowledge_api'; import { typeApi } from '@/apis/knowledge_api';
import HeaderComponent from '@/components/HeaderComponent.vue'; import HeaderComponent from '@/components/HeaderComponent.vue';
import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue'; import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue';
import EmbeddingModelSelector from '@/components/EmbeddingModelSelector.vue'; import EmbeddingModelSelector from '@/components/EmbeddingModelSelector.vue';
@ -248,12 +249,13 @@ import AiTextarea from '@/components/AiTextarea.vue';
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const databases = ref([])
const configStore = useConfigStore() const configStore = useConfigStore()
const databaseStore = useDatabaseStore()
// 使 store
const { databases, state: dbState } = storeToRefs(databaseStore)
const state = reactive({ const state = reactive({
loading: false,
creating: false,
openNewDatabaseModel: false, openNewDatabaseModel: false,
}) })
@ -357,32 +359,6 @@ const loadSupportedKbTypes = async () => {
// configStore.config.reranker_names // configStore.config.reranker_names
const loadDatabases = () => {
state.loading = true
// loadGraph()
databaseApi.getDatabases()
.then(data => {
console.log(data)
//
databases.value = data.databases.sort((a, b) => {
const timeA = parseToShanghai(a.created_at)
const timeB = parseToShanghai(b.created_at)
if (!timeA && !timeB) return 0
if (!timeA) return 1
if (!timeB) return -1
return timeB.valueOf() - timeA.valueOf() //
})
state.loading = false
})
.catch(error => {
console.error('加载数据库列表失败:', error);
if (error.message.includes('权限')) {
message.error('需要管理员权限访问知识库')
}
state.loading = false
})
}
const resetNewDatabase = () => { const resetNewDatabase = () => {
Object.assign(newDatabase, createEmptyDatabaseForm()) Object.assign(newDatabase, createEmptyDatabaseForm())
} }
@ -473,19 +449,8 @@ const handleLLMSelect = (spec) => {
newDatabase.llm_info.model_name = modelName newDatabase.llm_info.model_name = modelName
} }
const createDatabase = () => { //
if (!newDatabase.name?.trim()) { const buildRequestData = () => {
message.error('数据库名称不能为空')
return
}
if (!newDatabase.kb_type) {
message.error('请选择知识库类型')
return
}
state.creating = true
const requestData = { const requestData = {
database_name: newDatabase.name.trim(), database_name: newDatabase.name.trim(),
description: newDatabase.description?.trim() || '', description: newDatabase.description?.trim() || '',
@ -496,18 +461,12 @@ const createDatabase = () => {
} }
} }
// //
if (newDatabase.kb_type === 'chroma' || newDatabase.kb_type === 'milvus') { if (['chroma', 'milvus'].includes(newDatabase.kb_type)) {
if (newDatabase.storage) { if (newDatabase.storage) {
requestData.additional_params.storage = newDatabase.storage requestData.additional_params.storage = newDatabase.storage
} }
if (newDatabase.reranker.enabled) { if (newDatabase.reranker.enabled) {
if (!newDatabase.reranker.model) {
message.error('请选择重排序模型')
state.creating = false
return
}
requestData.additional_params.reranker_config = { requestData.additional_params.reranker_config = {
enabled: true, enabled: true,
model: newDatabase.reranker.model, model: newDatabase.reranker.model,
@ -519,7 +478,6 @@ const createDatabase = () => {
if (newDatabase.kb_type === 'lightrag') { if (newDatabase.kb_type === 'lightrag') {
requestData.additional_params.language = newDatabase.language || 'English' requestData.additional_params.language = newDatabase.language || 'English'
// LLM
if (newDatabase.llm_info.provider && newDatabase.llm_info.model_name) { if (newDatabase.llm_info.provider && newDatabase.llm_info.model_name) {
requestData.llm_info = { requestData.llm_info = {
provider: newDatabase.llm_info.provider, provider: newDatabase.llm_info.provider,
@ -528,21 +486,19 @@ const createDatabase = () => {
} }
} }
databaseApi.createDatabase(requestData) return requestData
.then(data => { }
console.log('创建成功:', data)
loadDatabases() //
resetNewDatabase() const handleCreateDatabase = async () => {
message.success('创建成功') const requestData = buildRequestData()
}) try {
.catch(error => { await databaseStore.createDatabase(requestData)
console.error('创建数据库失败:', error) resetNewDatabase()
message.error(error.message || '创建失败') state.openNewDatabaseModel = false
}) } catch (error) {
.finally(() => { // store
state.creating = false }
state.openNewDatabaseModel = false
})
} }
const navigateToDatabase = (databaseId) => { const navigateToDatabase = (databaseId) => {
@ -585,15 +541,15 @@ watch(
} }
) )
watch(() => route.path, (newPath, oldPath) => { watch(() => route.path, (newPath) => {
if (newPath === '/database') { if (newPath === '/database') {
loadDatabases(); databaseStore.loadDatabases();
} }
}); });
onMounted(() => { onMounted(() => {
loadSupportedKbTypes() loadSupportedKbTypes()
loadDatabases() databaseStore.loadDatabases()
// configStore // configStore
}) })