From 1d89bc89feddf67387e7a57c57ba68b6232727e8 Mon Sep 17 00:00:00 2001 From: bruce Date: Sun, 31 May 2026 23:57:37 +0800 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20=E9=87=8D=E8=AE=BE=E8=AE=A1Co?= =?UTF-8?q?mmon=20Agent=20Studio=E5=8E=9F=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/STUDIO_PROTOTYPE_SCHEMA.sql | 228 ++++ frontend/src/data/studioMock.ts | 143 +++ frontend/src/layouts/AdminLayout.vue | 93 +- .../src/layouts/__tests__/AdminLayout.spec.ts | 13 +- frontend/src/pages/common/NotFoundPage.vue | 2 +- .../src/pages/studio/AgentWorkspacePage.vue | 69 ++ .../pages/studio/IngestionPipelinePage.vue | 71 ++ .../pages/studio/KnowledgeWorkspacePage.vue | 94 ++ frontend/src/pages/studio/McpImportPage.vue | 49 + .../src/pages/studio/ModelWorkspacePage.vue | 34 + .../src/pages/studio/ObservabilityPage.vue | 49 + .../src/pages/studio/SkillWorkspacePage.vue | 56 + .../src/pages/studio/StudioDashboardPage.vue | 95 ++ .../src/pages/studio/WorkflowBuilderPage.vue | 112 ++ frontend/src/router/__tests__/router.spec.ts | 20 +- frontend/src/router/index.ts | 157 +-- frontend/src/styles/global.css | 1070 ++++++++++++++++- 17 files changed, 2142 insertions(+), 213 deletions(-) create mode 100644 docs/STUDIO_PROTOTYPE_SCHEMA.sql create mode 100644 frontend/src/data/studioMock.ts create mode 100644 frontend/src/pages/studio/AgentWorkspacePage.vue create mode 100644 frontend/src/pages/studio/IngestionPipelinePage.vue create mode 100644 frontend/src/pages/studio/KnowledgeWorkspacePage.vue create mode 100644 frontend/src/pages/studio/McpImportPage.vue create mode 100644 frontend/src/pages/studio/ModelWorkspacePage.vue create mode 100644 frontend/src/pages/studio/ObservabilityPage.vue create mode 100644 frontend/src/pages/studio/SkillWorkspacePage.vue create mode 100644 frontend/src/pages/studio/StudioDashboardPage.vue create mode 100644 frontend/src/pages/studio/WorkflowBuilderPage.vue diff --git a/docs/STUDIO_PROTOTYPE_SCHEMA.sql b/docs/STUDIO_PROTOTYPE_SCHEMA.sql new file mode 100644 index 0000000..39b7235 --- /dev/null +++ b/docs/STUDIO_PROTOTYPE_SCHEMA.sql @@ -0,0 +1,228 @@ +-- Common Agent Studio prototype schema draft. +-- These tables extend the current RAG, model-provider and agent_definition data model +-- without replacing existing core entities. + +CREATE TABLE IF NOT EXISTS studio_project ( + id BIGSERIAL PRIMARY KEY, + project_code VARCHAR(100) NOT NULL, + project_name VARCHAR(200) NOT NULL, + environment VARCHAR(50) NOT NULL DEFAULT 'DEV', + publish_status VARCHAR(50) NOT NULL DEFAULT 'DRAFT', + current_version VARCHAR(50), + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT uk_studio_project_code UNIQUE (project_code) +); + +CREATE TABLE IF NOT EXISTS workflow_definition ( + id BIGSERIAL PRIMARY KEY, + project_id BIGINT, + workflow_code VARCHAR(100) NOT NULL, + workflow_name VARCHAR(200) NOT NULL, + description VARCHAR(1000), + bound_agent_id BIGINT, + status VARCHAR(50) NOT NULL DEFAULT 'DRAFT', + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT uk_workflow_definition_code UNIQUE (workflow_code), + CONSTRAINT fk_workflow_definition_project_id FOREIGN KEY (project_id) REFERENCES studio_project (id), + CONSTRAINT fk_workflow_definition_agent_id FOREIGN KEY (bound_agent_id) REFERENCES agent_definition (id) +); + +CREATE TABLE IF NOT EXISTS workflow_version ( + id BIGSERIAL PRIMARY KEY, + workflow_id BIGINT NOT NULL, + version_no INTEGER NOT NULL, + snapshot_name VARCHAR(100) NOT NULL, + graph_json JSONB NOT NULL DEFAULT '{}'::jsonb, + publish_status VARCHAR(50) NOT NULL DEFAULT 'DRAFT', + published_time TIMESTAMP, + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT uk_workflow_version_no UNIQUE (workflow_id, version_no), + CONSTRAINT fk_workflow_version_workflow_id FOREIGN KEY (workflow_id) REFERENCES workflow_definition (id) +); + +CREATE TABLE IF NOT EXISTS workflow_run ( + id BIGSERIAL PRIMARY KEY, + request_id VARCHAR(64) NOT NULL, + workflow_id BIGINT, + workflow_version_id BIGINT, + agent_id BIGINT, + run_source VARCHAR(50) NOT NULL, + status VARCHAR(50) NOT NULL, + input_json JSONB NOT NULL DEFAULT '{}'::jsonb, + output_json JSONB NOT NULL DEFAULT '{}'::jsonb, + duration_ms INTEGER, + estimated_cost NUMERIC(14, 8), + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT uk_workflow_run_request_id UNIQUE (request_id), + CONSTRAINT fk_workflow_run_workflow_id FOREIGN KEY (workflow_id) REFERENCES workflow_definition (id), + CONSTRAINT fk_workflow_run_version_id FOREIGN KEY (workflow_version_id) REFERENCES workflow_version (id), + CONSTRAINT fk_workflow_run_agent_id FOREIGN KEY (agent_id) REFERENCES agent_definition (id) +); + +CREATE TABLE IF NOT EXISTS workflow_run_step ( + id BIGSERIAL PRIMARY KEY, + run_id BIGINT NOT NULL, + node_id VARCHAR(100) NOT NULL, + node_type VARCHAR(50) NOT NULL, + node_name VARCHAR(200), + status VARCHAR(50) NOT NULL, + input_json JSONB NOT NULL DEFAULT '{}'::jsonb, + output_json JSONB NOT NULL DEFAULT '{}'::jsonb, + duration_ms INTEGER, + error_message VARCHAR(1000), + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT fk_workflow_run_step_run_id FOREIGN KEY (run_id) REFERENCES workflow_run (id) +); + +CREATE TABLE IF NOT EXISTS mcp_server ( + id BIGSERIAL PRIMARY KEY, + server_code VARCHAR(100) NOT NULL, + server_name VARCHAR(200) NOT NULL, + import_type VARCHAR(50) NOT NULL, + endpoint_url VARCHAR(500), + package_name VARCHAR(200), + manifest_json JSONB NOT NULL DEFAULT '{}'::jsonb, + auth_type VARCHAR(50), + secret_ref VARCHAR(200), + health_status VARCHAR(50) NOT NULL DEFAULT 'UNKNOWN', + enabled BOOLEAN NOT NULL DEFAULT TRUE, + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT uk_mcp_server_code UNIQUE (server_code) +); + +CREATE TABLE IF NOT EXISTS mcp_capability ( + id BIGSERIAL PRIMARY KEY, + server_id BIGINT NOT NULL, + capability_code VARCHAR(150) NOT NULL, + capability_name VARCHAR(200) NOT NULL, + capability_type VARCHAR(50) NOT NULL, + schema_json JSONB NOT NULL DEFAULT '{}'::jsonb, + enabled BOOLEAN NOT NULL DEFAULT TRUE, + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT uk_mcp_capability_code UNIQUE (server_id, capability_code), + CONSTRAINT fk_mcp_capability_server_id FOREIGN KEY (server_id) REFERENCES mcp_server (id) +); + +CREATE TABLE IF NOT EXISTS skill_definition ( + id BIGSERIAL PRIMARY KEY, + skill_code VARCHAR(100) NOT NULL, + skill_name VARCHAR(200) NOT NULL, + skill_type VARCHAR(50) NOT NULL, + description VARCHAR(1000), + status VARCHAR(50) NOT NULL DEFAULT 'DRAFT', + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT uk_skill_definition_code UNIQUE (skill_code) +); + +CREATE TABLE IF NOT EXISTS skill_version ( + id BIGSERIAL PRIMARY KEY, + skill_id BIGINT NOT NULL, + version_no INTEGER NOT NULL, + prompt_text TEXT, + code_text TEXT, + config_json JSONB NOT NULL DEFAULT '{}'::jsonb, + variable_schema_json JSONB NOT NULL DEFAULT '{}'::jsonb, + test_result_json JSONB NOT NULL DEFAULT '{}'::jsonb, + publish_status VARCHAR(50) NOT NULL DEFAULT 'DRAFT', + published_time TIMESTAMP, + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT uk_skill_version_no UNIQUE (skill_id, version_no), + CONSTRAINT fk_skill_version_skill_id FOREIGN KEY (skill_id) REFERENCES skill_definition (id) +); + +CREATE TABLE IF NOT EXISTS agent_session ( + id BIGSERIAL PRIMARY KEY, + session_code VARCHAR(100) NOT NULL, + agent_id BIGINT NOT NULL, + workflow_run_id BIGINT, + title VARCHAR(200), + status VARCHAR(50) NOT NULL DEFAULT 'ACTIVE', + metadata_json JSONB NOT NULL DEFAULT '{}'::jsonb, + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT uk_agent_session_code UNIQUE (session_code), + CONSTRAINT fk_agent_session_agent_id FOREIGN KEY (agent_id) REFERENCES agent_definition (id), + CONSTRAINT fk_agent_session_run_id FOREIGN KEY (workflow_run_id) REFERENCES workflow_run (id) +); + +CREATE TABLE IF NOT EXISTS agent_message ( + id BIGSERIAL PRIMARY KEY, + session_id BIGINT NOT NULL, + role VARCHAR(50) NOT NULL, + content TEXT NOT NULL, + citation_json JSONB NOT NULL DEFAULT '[]'::jsonb, + token_count INTEGER, + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT fk_agent_message_session_id FOREIGN KEY (session_id) REFERENCES agent_session (id) +); + +CREATE TABLE IF NOT EXISTS agent_capability_binding ( + id BIGSERIAL PRIMARY KEY, + owner_type VARCHAR(50) NOT NULL, + owner_id BIGINT NOT NULL, + capability_type VARCHAR(50) NOT NULL, + capability_id BIGINT NOT NULL, + enabled BOOLEAN NOT NULL DEFAULT TRUE, + config_json JSONB NOT NULL DEFAULT '{}'::jsonb, + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT uk_agent_capability_binding UNIQUE (owner_type, owner_id, capability_type, capability_id) +); diff --git a/frontend/src/data/studioMock.ts b/frontend/src/data/studioMock.ts new file mode 100644 index 0000000..c2a983d --- /dev/null +++ b/frontend/src/data/studioMock.ts @@ -0,0 +1,143 @@ +export type PipelineStatus = 'done' | 'running' | 'blocked' | 'idle'; + +export interface LifecycleStep { + name: string; + description: string; + status: PipelineStatus; +} + +export interface RecentRun { + id: string; + name: string; + type: string; + status: string; + latency: string; + cost: string; +} + +export interface KnowledgeDocument { + id: string; + name: string; + parseStatus: string; + indexStatus: string; + chunks: number; + updatedAt: string; +} + +export interface WorkflowNode { + id: string; + type: string; + label: string; + description: string; + x: number; + y: number; +} + +export interface WorkflowEdge { + from: string; + to: string; +} + +export interface TraceStep { + node: string; + status: string; + duration: string; + output: string; +} + +export const lifecycleSteps: LifecycleStep[] = [ + { name: '知识接入', description: '上传、解析、切片、向量化', status: 'done' }, + { name: '能力编排', description: 'Workflow 连接模型、工具与 Skill', status: 'running' }, + { name: '对话调试', description: '验证引用、成本、延迟与回答质量', status: 'running' }, + { name: '发布观测', description: '版本快照、运行追踪、异常排查', status: 'idle' }, +]; + +export const readinessChecklist = [ + { label: '知识库已绑定 Embedding 模型', done: true }, + { label: 'Workflow 草稿存在未发布节点变更', done: false }, + { label: 'Agent 已绑定默认知识库与 Skill', done: true }, + { label: '生产环境路由规则仍需压测', done: false }, +]; + +export const recentRuns: RecentRun[] = [ + { id: 'run-1842', name: '售前问答 Agent', type: 'Agent', status: '成功', latency: '1.42s', cost: '¥0.018' }, + { id: 'run-1841', name: '合同知识召回', type: 'Workflow', status: '成功', latency: '860ms', cost: '¥0.006' }, + { id: 'run-1840', name: 'MCP: jira.search', type: 'MCP', status: '重试', latency: '2.8s', cost: '¥0.000' }, +]; + +export const knowledgeStores = [ + { id: '1001', name: '产品制度库', docs: 128, health: 96, status: '可检索' }, + { id: '1002', name: '交付项目资料', docs: 64, health: 82, status: '索引中' }, + { id: '1003', name: '客服 FAQ', docs: 214, health: 91, status: '可检索' }, +]; + +export const knowledgeDocuments: KnowledgeDocument[] = [ + { id: 'doc-01', name: '售前方案模板.pdf', parseStatus: 'PARSED', indexStatus: 'INDEXED', chunks: 42, updatedAt: '10分钟前' }, + { id: 'doc-02', name: '项目实施手册.docx', parseStatus: 'PARSED', indexStatus: 'INDEXING', chunks: 88, updatedAt: '23分钟前' }, + { id: 'doc-03', name: '服务条款更新.md', parseStatus: 'FAILED', indexStatus: 'PENDING', chunks: 0, updatedAt: '今天 09:12' }, + { id: 'doc-04', name: '客服高频问题.xlsx', parseStatus: 'PARSED', indexStatus: 'INDEXED', chunks: 119, updatedAt: '昨天' }, +]; + +export const ingestionSteps: LifecycleStep[] = [ + { name: '上传', description: '4 个文件已入库 sys_attachment', status: 'done' }, + { name: '解析', description: 'Tika 抽取文本并保存快照', status: 'done' }, + { name: '切片', description: '固定长度 800 / overlap 120', status: 'running' }, + { name: '向量化', description: 'Qwen3 Embedding 1024 维', status: 'idle' }, + { name: '可检索', description: '等待索引任务完成', status: 'idle' }, +]; + +export const workflowNodes: WorkflowNode[] = [ + { id: 'start', type: 'START', label: 'Start', description: '接收用户问题', x: 4, y: 42 }, + { id: 'retrieve', type: 'KNOWLEDGE_RETRIEVAL', label: 'Knowledge Retrieval', description: 'TopK=6 / score>0.72', x: 25, y: 18 }, + { id: 'llm', type: 'LLM', label: 'LLM', description: 'RAG_ANSWER 路由', x: 47, y: 42 }, + { id: 'mcp', type: 'MCP_TOOL', label: 'MCP Tool', description: 'jira.search / docs.lookup', x: 47, y: 70 }, + { id: 'skill', type: 'SKILL', label: 'Skill', description: '答案审校与引用整理', x: 69, y: 42 }, + { id: 'answer', type: 'ANSWER', label: 'Answer', description: '返回回答与引用', x: 88, y: 42 }, +]; + +export const workflowEdges: WorkflowEdge[] = [ + { from: 'start', to: 'retrieve' }, + { from: 'retrieve', to: 'llm' }, + { from: 'llm', to: 'skill' }, + { from: 'mcp', to: 'skill' }, + { from: 'skill', to: 'answer' }, +]; + +export const traceSteps: TraceStep[] = [ + { node: 'Start', status: '完成', duration: '4ms', output: '用户问题已标准化' }, + { node: 'Knowledge Retrieval', status: '完成', duration: '218ms', output: '召回 6 个切片' }, + { node: 'LLM', status: '完成', duration: '1.12s', output: '生成 612 tokens' }, + { node: 'Skill', status: '完成', duration: '88ms', output: '引用格式已校验' }, +]; + +export const chatMessages = [ + { role: 'user', content: '如果客户要求私有化部署,售前方案里必须说明哪些内容?' }, + { + role: 'assistant', + content: '建议说明部署拓扑、模型服务商、知识库索引策略、权限边界、日志留存周期和故障恢复方式。当前回答引用了 3 个知识切片。', + }, +]; + +export const citations = [ + { title: '售前方案模板.pdf', score: '0.91', text: '私有化部署章节应覆盖基础设施、网络、安全与运维边界。' }, + { title: '项目实施手册.docx', score: '0.87', text: '交付计划需包含数据导入、索引重建与验收标准。' }, + { title: '服务条款更新.md', score: '0.82', text: '客户数据默认不出域,模型调用日志需保留审计字段。' }, +]; + +export const mcpCapabilities = [ + { name: 'jira.search', type: 'tool', status: '已启用', description: '按项目、状态、负责人检索任务' }, + { name: 'docs.lookup', type: 'resource', status: '已启用', description: '读取外部文档中心条目' }, + { name: 'deploy.trigger', type: 'tool', status: '待授权', description: '触发测试环境部署流水线' }, +]; + +export const skillVersions = [ + { version: 'v4', status: 'Draft', updatedAt: '刚刚', note: '增加引用一致性检查' }, + { version: 'v3', status: 'Published', updatedAt: '昨天', note: '生产环境当前版本' }, + { version: 'v2', status: 'Archived', updatedAt: '5天前', note: '旧版回答润色策略' }, +]; + +export const modelRoutes = [ + { task: 'RAG_ANSWER', primary: 'qwen-plus', fallback: 'deepseek-v3', latency: '1800ms', status: '启用' }, + { task: 'RAG_EMBEDDING', primary: 'Qwen3-Embedding', fallback: '无', latency: '900ms', status: '启用' }, + { task: 'AGENT_PLAN', primary: 'gpt-4.1', fallback: 'qwen-max', latency: '3200ms', status: '草稿' }, +]; diff --git a/frontend/src/layouts/AdminLayout.vue b/frontend/src/layouts/AdminLayout.vue index be658f7..c27b71c 100644 --- a/frontend/src/layouts/AdminLayout.vue +++ b/frontend/src/layouts/AdminLayout.vue @@ -1,64 +1,71 @@