From 44ab895149a3551f65a95bd38f16cf9d3c2733ff Mon Sep 17 00:00:00 2001 From: Nelson <1475262689@qq.com> Date: Mon, 13 Jul 2026 14:06:45 +0800 Subject: [PATCH] feat: add prompt history management --- .../apps/admin-web/src/App.vue | 219 +--------- .../src/components/AgentManagementView.vue | 388 ++++++++++++++++++ .../apps/admin-web/src/services/api.ts | 12 +- .../apps/admin-web/src/styles.css | 201 ++++++++- .../apps/admin-web/src/types/api.ts | 21 + .../0010_prompt_history_management.py | 29 ++ .../apps/backend/app/api/admin_settings.py | 129 +++++- .../apps/backend/app/models/ai_config.py | 9 +- .../apps/backend/tests/test_prompt_history.py | 98 +++++ 9 files changed, 876 insertions(+), 230 deletions(-) create mode 100644 ai_knowledge_base_v2/apps/admin-web/src/components/AgentManagementView.vue create mode 100644 ai_knowledge_base_v2/apps/backend/alembic/versions/0010_prompt_history_management.py create mode 100644 ai_knowledge_base_v2/apps/backend/tests/test_prompt_history.py diff --git a/ai_knowledge_base_v2/apps/admin-web/src/App.vue b/ai_knowledge_base_v2/apps/admin-web/src/App.vue index 1a16084..4e320c9 100644 --- a/ai_knowledge_base_v2/apps/admin-web/src/App.vue +++ b/ai_knowledge_base_v2/apps/admin-web/src/App.vue @@ -4,6 +4,7 @@ import { computed, onMounted, reactive, ref, watch } from "vue"; import AdminLoginView from "./components/AdminLoginView.vue"; import AdminPagination from "./components/AdminPagination.vue"; +import AgentManagementView from "./components/AgentManagementView.vue"; import KnowledgeManagementView from "./components/KnowledgeManagementView.vue"; import TableRowActions from "./components/TableRowActions.vue"; import { systemSettingDefinitions, systemSettingSections, type SystemSettingValue } from "./config/systemSettings"; @@ -11,7 +12,6 @@ import { api, clearToken, getToken, saveToken } from "./services/api"; import type { AdminProfile, AdminUser, - AgentDebugResult, AiLogRecord, ChatDetail, ChatRecord, @@ -40,7 +40,6 @@ const dashboardFilters = reactive({ }); const users = ref([]); const userKeyword = ref(""); -const knowledge = ref([]); const models = ref([]); const configs = ref([]); const chats = ref([]); @@ -50,7 +49,7 @@ const retrievalLogs = ref([]); const attentionRecords = ref([]); const selectedRetrievalLog = ref | null>(null); const retrievalDetailOpen = ref(false); -const promptContent = ref(""); +const previewKnowledgeId = ref(null); const chatDetail = ref(null); const chatDetailOpen = ref(false); const selectedAiLog = ref(null); @@ -68,11 +67,6 @@ const editingModelId = ref(null); const editingKnowledgeId = ref(null); const batchNodeToken = ref(""); const batchImporting = ref(false); -const agentDebugging = ref(false); -const agentDebugTrace = ref[]>([]); -const agentPreviewMessages = ref<{ role: "user" | "assistant" | "system"; content: string }[]>([ - { role: "assistant", content: "选择模型和知识库后,可以在这里调试 Agent 的真实问答效果。" }, -]); const studentForm = reactive({ phone: "", @@ -207,18 +201,6 @@ const chatFilters = reactive({ dateTo: "", }); -const agentForm = reactive({ - modelId: undefined as number | undefined, - knowledgeIds: [] as number[], - temperature: 0.2 as number | null, - topP: null as number | null, - topK: null as number | null, - presencePenalty: null as number | null, - frequencyPenalty: null as number | null, - maxToken: 1024 as number | null, - question: "", -}); - watch(recordTab, async (tab) => { if (activeMenu.value === "records") await loadRecordTab(tab); }); @@ -262,8 +244,8 @@ async function switchMenu(menu: string) { } async function previewKnowledge(knowledgeId: number) { + previewKnowledgeId.value = knowledgeId; await switchMenu("prompt"); - agentForm.knowledgeIds = [knowledgeId]; } async function loadDashboard() { @@ -282,16 +264,6 @@ async function loadCurrentMenu() { try { if (activeMenu.value === "dashboard") await loadDashboard(); if (activeMenu.value === "users") await loadUsers(pagers.users.page, pagers.users.pageSize); - if (activeMenu.value === "prompt") { - const [prompt, modelRows, knowledgeRows] = await Promise.all([api.prompt(), api.models(), api.knowledgeOptions()]); - promptContent.value = prompt.promptContent; - models.value = modelRows; - knowledge.value = knowledgeRows; - agentForm.knowledgeIds = knowledgeRows.filter((item) => item.status === 1 && item.lifecycleStatus === "active").map((item) => item.id); - if (!agentForm.modelId && modelRows.length) { - agentForm.modelId = modelRows.find((model) => model.enabled === 1)?.id ?? modelRows[0].id; - } - } if (activeMenu.value === "models") models.value = await api.models(); if (activeMenu.value === "configs") { configs.value = await api.configs(); @@ -478,18 +450,6 @@ async function batchImportKnowledge() { } } -async function savePrompt() { - const result = await api.savePrompt(promptContent.value); - promptContent.value = result.promptContent; - ElMessage.success("Prompt 已保存"); -} - -async function resetPrompt() { - const result = await api.resetPrompt(); - promptContent.value = result.promptContent; - ElMessage.success("Prompt 已恢复默认"); -} - async function saveModel() { if (!validateModelForm()) return; const payload = buildModelPayload(); @@ -743,66 +703,6 @@ function serializeSystemSettingValue(value: SystemSettingValue) { return String(value); } -function agentMessageParts(content: string) { - const matched = content.match(/([\s\S]*?)<\/think>/i); - if (!matched) return { reasoning: "", answer: content }; - const answer = content.replace(matched[0], "").trim(); - return { - reasoning: matched[1].trim(), - answer: answer || "模型未返回正式回答。", - }; -} - -async function debugAgent() { - if (!agentForm.modelId) { - ElMessage.error("请选择调试模型"); - return; - } - if (!agentForm.question.trim()) { - ElMessage.error("请输入调试问题"); - return; - } - const question = agentForm.question.trim(); - agentPreviewMessages.value.push({ role: "user", content: question }); - agentForm.question = ""; - agentDebugging.value = true; - try { - const result: AgentDebugResult = await api.debugAgent({ - promptContent: promptContent.value, - modelId: agentForm.modelId, - knowledgeIds: agentForm.knowledgeIds, - question, - temperature: agentForm.temperature, - topP: agentForm.topP, - topK: agentForm.topK, - presencePenalty: agentForm.presencePenalty, - frequencyPenalty: agentForm.frequencyPenalty, - maxToken: agentForm.maxToken, - }); - if (!result.ok) { - ElMessage.error(result.message); - agentPreviewMessages.value.push({ role: "assistant", content: result.message }); - return; - } - agentPreviewMessages.value.push({ role: "assistant", content: result.answer }); - agentDebugTrace.value = result.retrievalTrace || []; - ElMessage.success(result.message); - } catch (error) { - const message = error instanceof Error ? error.message : "Agent 调试失败"; - ElMessage.error(message); - agentPreviewMessages.value.push({ role: "assistant", content: message }); - } finally { - agentDebugging.value = false; - } -} - -function clearAgentPreview() { - agentPreviewMessages.value = [ - { role: "assistant", content: "预览已清空,可以继续发起新的 Agent 调试。" }, - ]; - agentDebugTrace.value = []; -} - async function openRetrievalDetail(row: RetrievalLogItem) { selectedRetrievalLog.value = await api.retrievalLogDetail(row.id); retrievalDetailOpen.value = true; @@ -1026,118 +926,7 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {