feat(audit): 补齐摄取管道入口并沉淀完成度审计

This commit is contained in:
2026-06-01 06:04:30 +08:00
parent 1d401c6841
commit c8245ba0d6
10 changed files with 505 additions and 2 deletions

View File

@@ -1,14 +1,18 @@
package com.bruce.rag.controller; package com.bruce.rag.controller;
import com.bruce.common.domain.model.RequestResult; import com.bruce.common.domain.model.RequestResult;
import com.bruce.rag.dto.request.IngestionRunCreateRequest;
import com.bruce.rag.service.IIngestionRunService; import com.bruce.rag.service.IIngestionRunService;
import com.bruce.rag.vo.IngestionRunVO; import com.bruce.rag.vo.IngestionRunVO;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -25,6 +29,16 @@ public class IngestionRunController {
private final IIngestionRunService ingestionRunService; private final IIngestionRunService ingestionRunService;
@Operation(summary = "创建文件解析管道聚合视图")
@PostMapping
public RequestResult<IngestionRunVO> create(@Valid @RequestBody IngestionRunCreateRequest request) {
log.info("文件解析管道创建开始storeId={}, documentId={}", request.getStoreId(), request.getDocumentId());
IngestionRunVO view = ingestionRunService.createRun(request);
log.info("文件解析管道创建结束runId={}, storeId={}, documentId={}",
view.getRunId(), view.getStoreId(), view.getDocumentId());
return RequestResult.success(view);
}
@Operation(summary = "查询文件解析管道聚合视图") @Operation(summary = "查询文件解析管道聚合视图")
@GetMapping("/{runId}") @GetMapping("/{runId}")
public RequestResult<IngestionRunVO> detail(@PathVariable("runId") String runId, public RequestResult<IngestionRunVO> detail(@PathVariable("runId") String runId,

View File

@@ -0,0 +1,24 @@
package com.bruce.rag.dto.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* 文件解析管道创建请求。
* <p>
* 首轮实现不额外落摄取运行表,而是基于知识库与文档主数据生成可追踪的聚合 runId
* 让前端能够按统一入口进入管道详情页。
*/
@Data
@Schema(description = "文件解析管道创建请求")
public class IngestionRunCreateRequest {
@NotNull(message = "知识库ID不能为空")
@Schema(description = "知识库ID")
private Long storeId;
@NotNull(message = "文档ID不能为空")
@Schema(description = "文档ID")
private Long documentId;
}

View File

@@ -1,5 +1,6 @@
package com.bruce.rag.service; package com.bruce.rag.service;
import com.bruce.rag.dto.request.IngestionRunCreateRequest;
import com.bruce.rag.vo.IngestionRunVO; import com.bruce.rag.vo.IngestionRunVO;
/** /**
@@ -7,6 +8,11 @@ import com.bruce.rag.vo.IngestionRunVO;
*/ */
public interface IIngestionRunService { public interface IIngestionRunService {
/**
* 创建文件解析管道视图入口。
*/
IngestionRunVO createRun(IngestionRunCreateRequest request);
/** /**
* 按知识库和文档聚合摄取流水线视图。 * 按知识库和文档聚合摄取流水线视图。
*/ */

View File

@@ -3,6 +3,7 @@ package com.bruce.rag.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bruce.modelprovider.dto.response.RagStoreModelConfigResponse; import com.bruce.modelprovider.dto.response.RagStoreModelConfigResponse;
import com.bruce.modelprovider.service.IRagStoreModelConfigService; import com.bruce.modelprovider.service.IRagStoreModelConfigService;
import com.bruce.rag.dto.request.IngestionRunCreateRequest;
import com.bruce.rag.dto.response.RagDocumentResponse; import com.bruce.rag.dto.response.RagDocumentResponse;
import com.bruce.rag.dto.response.RagStoreResponse; import com.bruce.rag.dto.response.RagStoreResponse;
import com.bruce.rag.entity.RagChunk; import com.bruce.rag.entity.RagChunk;
@@ -53,6 +54,19 @@ public class IngestionRunServiceImpl implements IIngestionRunService {
private final IRagChunkEmbeddingService ragChunkEmbeddingService; private final IRagChunkEmbeddingService ragChunkEmbeddingService;
private final IRagStoreModelConfigService ragStoreModelConfigService; private final IRagStoreModelConfigService ragStoreModelConfigService;
@Override
public IngestionRunVO createRun(IngestionRunCreateRequest request) {
if (request == null) {
throw new IllegalArgumentException("文件解析管道创建请求不能为空");
}
log.info("文件解析管道创建聚合开始storeId={}, documentId={}", request.getStoreId(), request.getDocumentId());
IngestionRunVO view = getRun(request.getStoreId(), request.getDocumentId());
view.setRunId(buildRunId(request.getStoreId(), request.getDocumentId()));
log.info("文件解析管道创建聚合结束runId={}, storeId={}, documentId={}",
view.getRunId(), view.getStoreId(), view.getDocumentId());
return view;
}
@Override @Override
public IngestionRunVO getRun(Long storeId, Long documentId) { public IngestionRunVO getRun(Long storeId, Long documentId) {
log.info("文件解析管道聚合开始storeId={}, documentId={}", storeId, documentId); log.info("文件解析管道聚合开始storeId={}, documentId={}", storeId, documentId);
@@ -104,6 +118,10 @@ public class IngestionRunServiceImpl implements IIngestionRunService {
return view; return view;
} }
private String buildRunId(Long storeId, Long documentId) {
return "ingestion-" + safeNumber(storeId) + "-" + safeNumber(documentId);
}
private IngestionRunFileVO toFileVO(RagDocumentResponse document) { private IngestionRunFileVO toFileVO(RagDocumentResponse document) {
IngestionRunFileVO file = new IngestionRunFileVO(); IngestionRunFileVO file = new IngestionRunFileVO();
file.setDocumentId(document.getId()); file.setDocumentId(document.getId());

View File

@@ -0,0 +1,86 @@
package com.bruce.rag.controller;
import com.bruce.common.handler.GlobalExceptionHandler;
import com.bruce.rag.service.IIngestionRunService;
import com.bruce.rag.vo.IngestionRunVO;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* 验证文件解析管道聚合接口的请求绑定与响应结构。
*/
@ExtendWith(MockitoExtension.class)
class IngestionRunControllerTests {
private MockMvc mockMvc;
@Mock
private IIngestionRunService ingestionRunService;
@InjectMocks
private IngestionRunController ingestionRunController;
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(ingestionRunController)
.setControllerAdvice(new GlobalExceptionHandler())
.build();
}
@Test
void createShouldReturnStructuredRunView() throws Exception {
IngestionRunVO run = new IngestionRunVO();
run.setRunId("ingestion-1001-11");
run.setStoreId(1001L);
run.setDocumentId(11L);
when(ingestionRunService.createRun(any())).thenReturn(run);
mockMvc.perform(post("/api/knowledge/ingestion-runs")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"storeId": 1001,
"documentId": 11
}
"""))
.andExpect(status().isOk())
.andExpect(jsonPath("$.resultcode").value("0"))
.andExpect(jsonPath("$.data.runId").value("ingestion-1001-11"))
.andExpect(jsonPath("$.data.storeId").value("1001"))
.andExpect(jsonPath("$.data.documentId").value("11"));
}
@Test
void detailShouldReturnStructuredRunView() throws Exception {
IngestionRunVO run = new IngestionRunVO();
run.setRunId("run-20260601");
run.setStoreId(1001L);
run.setDocumentId(11L);
when(ingestionRunService.getRun(1001L, 11L)).thenReturn(run);
mockMvc.perform(get("/api/knowledge/ingestion-runs/run-20260601")
.param("storeId", "1001")
.param("documentId", "11"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.resultcode").value("0"))
.andExpect(jsonPath("$.data.runId").value("run-20260601"))
.andExpect(jsonPath("$.data.storeId").value("1001"))
.andExpect(jsonPath("$.data.documentId").value("11"));
}
}

View File

@@ -2,6 +2,7 @@ package com.bruce.rag.ingestion;
import com.bruce.modelprovider.dto.response.RagStoreModelConfigResponse; import com.bruce.modelprovider.dto.response.RagStoreModelConfigResponse;
import com.bruce.modelprovider.service.IRagStoreModelConfigService; import com.bruce.modelprovider.service.IRagStoreModelConfigService;
import com.bruce.rag.dto.request.IngestionRunCreateRequest;
import com.bruce.rag.dto.response.RagDocumentResponse; import com.bruce.rag.dto.response.RagDocumentResponse;
import com.bruce.rag.dto.response.RagStoreResponse; import com.bruce.rag.dto.response.RagStoreResponse;
import com.bruce.rag.entity.RagChunk; import com.bruce.rag.entity.RagChunk;
@@ -51,6 +52,43 @@ class IngestionRunServiceTests {
@InjectMocks @InjectMocks
private IngestionRunServiceImpl ingestionRunService; private IngestionRunServiceImpl ingestionRunService;
@Test
void createRunShouldGenerateStableRunId() {
RagStoreResponse store = new RagStoreResponse();
store.setId(1001L);
store.setStoreCode("PROD_DOC");
store.setStoreName("产品制度库");
RagDocumentResponse document = new RagDocumentResponse();
document.setId(11L);
document.setStoreId(1001L);
document.setDocumentTitle("售前方案模板.pdf");
document.setParseStatus("PARSED");
document.setIndexStatus("INDEXED");
document.setCreateTime(new Date(1748780000000L));
document.setUpdateTime(new Date(1748780300000L));
when(ragStoreService.getResponseById(1001L)).thenReturn(store);
when(ragDocumentService.getResponseById(11L)).thenReturn(document);
when(ragDocumentParseResultService.getByDocumentId(11L)).thenReturn(null);
when(ragChunkService.list(org.mockito.ArgumentMatchers.<com.baomidou.mybatisplus.core.conditions.Wrapper<RagChunk>>any()))
.thenReturn(List.of());
when(ragChunkEmbeddingService.list(org.mockito.ArgumentMatchers.<com.baomidou.mybatisplus.core.conditions.Wrapper<RagChunkEmbedding>>any()))
.thenReturn(List.of());
when(ragStoreModelConfigService.getByStoreId(1001L)).thenReturn(null);
IngestionRunCreateRequest request = new IngestionRunCreateRequest();
request.setStoreId(1001L);
request.setDocumentId(11L);
IngestionRunVO view = ingestionRunService.createRun(request);
assertNotNull(view);
assertEquals("ingestion-1001-11", view.getRunId());
assertEquals(1001L, view.getStoreId());
assertEquals(11L, view.getDocumentId());
}
@Test @Test
void getRunShouldAggregatePipelinePreviewAndLogs() { void getRunShouldAggregatePipelinePreviewAndLogs() {
RagStoreResponse store = new RagStoreResponse(); RagStoreResponse store = new RagStoreResponse();

View File

@@ -4,11 +4,19 @@ import com.bruce.common.domain.model.RequestResult;
import com.bruce.workflow.service.IWorkflowWorkspaceService; import com.bruce.workflow.service.IWorkflowWorkspaceService;
import com.bruce.workflow.vo.WorkflowWorkspaceVO; import com.bruce.workflow.vo.WorkflowWorkspaceVO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
/**
* Workflow 工作台聚合接口。
* <p>
* 该接口面向前端原型页面,负责把项目、流程、版本与最近运行记录收口成单一视图,
* 避免页面自行拼接多个底层管理接口。
*/
@Slf4j
@RestController @RestController
@RequestMapping("/api/workflow-workspace") @RequestMapping("/api/workflow-workspace")
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -19,6 +27,14 @@ public class WorkflowWorkspaceController {
@GetMapping("/detail") @GetMapping("/detail")
public RequestResult<WorkflowWorkspaceVO> detail(@RequestParam("projectId") Long projectId, public RequestResult<WorkflowWorkspaceVO> detail(@RequestParam("projectId") Long projectId,
@RequestParam(value = "workflowId", required = false) Long workflowId) { @RequestParam(value = "workflowId", required = false) Long workflowId) {
return RequestResult.success(workflowWorkspaceService.getWorkspace(projectId, workflowId)); log.info("Workflow工作台查询开始projectId={}, workflowId={}", projectId, workflowId);
WorkflowWorkspaceVO workspace = workflowWorkspaceService.getWorkspace(projectId, workflowId);
log.info("Workflow工作台查询结束projectId={}, workflowId={}, workflowCount={}, versionCount={}, recentRunCount={}",
projectId,
workflowId,
workspace.getWorkflows() == null ? 0 : workspace.getWorkflows().size(),
workspace.getVersions() == null ? 0 : workspace.getVersions().size(),
workspace.getRecentRuns() == null ? 0 : workspace.getRecentRuns().size());
return RequestResult.success(workspace);
} }
} }

View File

@@ -0,0 +1,275 @@
# Common Agent Studio 模块完成度审计
## 1. 审计范围
本次审计以当前仓库最新状态为准,核对以下资料与实现是否一致:
- `docs/需求分析/*`
- `docs/设计文档/*`
- `docs/数据库设计/*`
- `docs/后端实现文档/*`
- `docs/前端实现文档/*`
- `script/sql/*.sql`
审计目标不是重复设计方案,而是确认当前代码、接口、测试与文档约束之间的对应关系,并标记仍需持续关注的风险点。
## 2. 总体结论
- Maven 多模块单体骨架已落地,根 `pom.xml` 已拆分 `common-agent-boot``common-agent-common``common-agent-rag``common-agent-modelprovider``common-agent-agent``common-agent-workflow``common-agent-mcp``common-agent-skill``common-agent-observability`
- 后端已按业务域拆分模块,每个业务模块均已形成 `controller / service / service/impl / mapper / entity / dto / vo / factory` 主体结构。
- `sys_enum`、整型枚举协议、`PersistableSysEnumDefinition` 契约、`BaseEntity` 审计习惯均保持不变。
- 前端 Studio 九个工作台页面均已对接真实 APIAPI 层与页面单测已覆盖主要聚合接口。
- 旧管理接口继续兼容Studio 原型新增聚合接口用于支撑工作台页面,不替代低层 CRUD 接口。
## 3. 模块核对
### 3.1 common
已核对内容:
- 实体与 SQL 对应:
- `sys_enum` -> `common-agent-common/src/main/java/com/bruce/common/domain/entity/SysEnum.java`
- `sys_attachment` -> `common-agent-common/src/main/java/com/bruce/common/domain/entity/SysAttachment.java`
- 基础模型:
- `BaseEntity``RequestResult<T>`、全局异常、审计配置均位于 `com.bruce.common`
- 接口:
- `POST /api/sys-enum/list`
- `POST /api/sys-enum/query`
- `POST /api/sys-enum/queryForManagement`
- `GET /api/sys-enum/detail`
- `POST /api/sys-enum/save`
- `POST /api/sys-enum/batchSave`
- `POST /api/sys-enum/delete`
- `POST /api/attachments/upload`
- 文档解析:
- `document/parse``document/parse/impl` 已提供解析抽象和解析器工厂
证据:
- 代码:`common-agent-common/src/main/java/com/bruce/common/controller/*`
- 测试:
- `common-agent-common/src/test/java/com/bruce/common/controller/SysEnumControllerTests.java`
- `common-agent-common/src/test/java/com/bruce/common/factory/*`
- `common-agent-common/src/test/java/com/bruce/common/document/parse/*`
- `common-agent-common/src/test/java/com/bruce/common/handler/GlobalExceptionHandlerTests.java`
### 3.2 rag
已核对内容:
- 实体已覆盖:
- `rag_store`
- `rag_document`
- `rag_document_parse_result`
- `rag_chunk`
- `rag_chunk_embedding`
- 旧接口保持兼容:
- `/api/rag/store/*`
- `/api/rag/documents/*`
- 聚合接口已提供:
- `GET /api/knowledge/workspaces/{storeId}`
- `POST /api/knowledge/ingestion-runs`
- `GET /api/knowledge/ingestion-runs/{runId}`
- 受控最小运行链路已落地:
- 批量上传
- 手动解析
- 手动切片
- 向量化记录聚合查询
本轮补充:
- 新增 `POST /api/knowledge/ingestion-runs`,与前端实现文档草案保持一致。
证据:
- 代码:
- `common-agent-rag/src/main/java/com/bruce/rag/controller/*`
- `common-agent-rag/src/main/java/com/bruce/rag/service/impl/IngestionRunServiceImpl.java`
- 测试:
- `common-agent-rag/src/test/java/com/bruce/rag/controller/IngestionRunControllerTests.java`
- `common-agent-rag/src/test/java/com/bruce/rag/ingestion/IngestionRunServiceTests.java`
- `common-agent-rag/src/test/java/com/bruce/rag/workspace/KnowledgeWorkspaceServiceTests.java`
- 其余 `Rag*Tests`
### 3.3 modelprovider
已核对内容:
- 实体已覆盖:
- `model_provider`
- `model_config`
- `model_route_rule`
- `rag_store_model_config`
- `model_call_log`
- 控制器已覆盖:
- `ModelProviderController`
- `ModelConfigController`
- `ModelRouteRuleController`
- `RagStoreModelConfigController`
- `ModelCallLogController`
- `ModelWorkspaceController`
- 网关抽象已位于 `gateway`
证据:
- 代码:`common-agent-modelprovider/src/main/java/com/bruce/modelprovider/**/*`
- 测试:
- `common-agent-modelprovider/src/test/java/com/bruce/modelprovider/controller/ModelWorkspaceControllerTests.java`
- `common-agent-modelprovider/src/test/java/com/bruce/modelprovider/workspace/ModelWorkspaceServiceTests.java`
- `common-agent-modelprovider/src/test/java/com/bruce/modelprovider/factory/ModelProviderFactoryTests.java`
### 3.4 agent
已核对内容:
- 实体已覆盖:
- `agent_definition`
- `agent_session`
- `agent_message`
- `agent_capability_binding`
- 兼容接口与会话接口并存:
- Agent 定义管理
- `/api/agents/{agentId}/chat`
- `/api/agent-sessions/*`
- 工作台聚合接口
证据:
- 代码:`common-agent-agent/src/main/java/com/bruce/agent/**/*`
- 测试:
- `common-agent-agent/src/test/java/com/bruce/agent/controller/AgentSessionControllerTests.java`
- `common-agent-agent/src/test/java/com/bruce/agent/session/AgentSessionServiceTests.java`
- `common-agent-agent/src/test/java/com/bruce/agent/workspace/AgentWorkspaceServiceTests.java`
### 3.5 workflow
已核对内容:
- 实体已覆盖:
- `studio_project`
- `workflow_definition`
- `workflow_version`
- `workflow_run`
- `workflow_run_step`
- 控制器已覆盖:
- `ProjectController`
- `WorkflowDefinitionController`
- `WorkflowVersionController`
- `WorkflowRunController`
- `WorkflowWorkspaceController`
- 前端工作台聚合使用 `GET /api/workflow-workspace/detail`
旧管理接口继续承担定义、版本与运行管理能力。
说明:
- 前端实现文档中的 REST 草案与当前聚合接口命名不完全一致,但职责已由 `WorkflowWorkspaceController` 承接,且不影响旧接口兼容。
证据:
- 代码:`common-agent-workflow/src/main/java/com/bruce/workflow/**/*`
- 测试:
- `common-agent-workflow/src/test/java/com/bruce/workflow/controller/WorkflowWorkspaceControllerTests.java`
- `common-agent-workflow/src/test/java/com/bruce/workflow/workspace/WorkflowWorkspaceServiceTests.java`
- `common-agent-workflow/src/test/java/com/bruce/workflow/version/WorkflowVersionServiceTests.java`
- `common-agent-workflow/src/test/java/com/bruce/workflow/WorkflowComponentStructureTests.java`
### 3.6 mcp
已核对内容:
- 实体已覆盖:
- `mcp_server`
- `mcp_capability`
- 接口已覆盖:
- `POST /api/mcp/import`
- `GET /api/mcp/servers`
- `GET /api/mcp/servers/{serverId}/capabilities`
- `GET /api/mcp/servers/code/{serverCode}/capabilities`
- `POST /api/mcp/capabilities/save`
- `GET /api/mcp/workspace`
证据:
- 代码:`common-agent-mcp/src/main/java/com/bruce/mcp/**/*`
- 测试:
- `common-agent-mcp/src/test/java/com/bruce/mcp/controller/McpImportControllerTests.java`
- `common-agent-mcp/src/test/java/com/bruce/mcp/importing/McpImportServiceTests.java`
- `common-agent-mcp/src/test/java/com/bruce/mcp/workspace/McpWorkspaceServiceTests.java`
### 3.7 skill
已核对内容:
- 实体已覆盖:
- `skill_definition`
- `skill_version`
- 工作台接口已覆盖:
- `GET /api/skills/{skillCode}`
- `POST /api/skills/{skillCode}/draft`
- `POST /api/skills/{skillCode}/test`
- `POST /api/skills/{skillCode}/publish`
- `POST /api/skills/{skillCode}/archive`
证据:
- 代码:`common-agent-skill/src/main/java/com/bruce/skill/**/*`
- 测试:
- `common-agent-skill/src/test/java/com/bruce/skill/controller/SkillWorkspaceControllerTests.java`
- `common-agent-skill/src/test/java/com/bruce/skill/version/SkillVersionServiceTests.java`
- `common-agent-skill/src/test/java/com/bruce/skill/workspace/SkillWorkspaceServiceTests.java`
### 3.8 observability
已核对内容:
- 聚合来源已复用:
- `workflow_run`
- `workflow_run_step`
- `model_call_log`
- `agent_session`
- `agent_message`
- 接口已覆盖:
- `GET /api/observability/runs`
- `GET /api/observability/runs/{requestId}`
- `GET /api/observability/model-calls`
- `GET /api/observability/runs/{requestId}/export`
- 导出接口返回脱敏摘要对象
证据:
- 代码:`common-agent-observability/src/main/java/com/bruce/observability/**/*`
- 测试:
- `common-agent-observability/src/test/java/com/bruce/observability/controller/ObservabilityTraceControllerTests.java`
- `common-agent-observability/src/test/java/com/bruce/observability/trace/ObservabilityTraceServiceTests.java`
## 4. 前端对接核对
已核对内容:
- Studio 页面:
- `frontend/src/pages/studio/StudioDashboardPage.vue`
- `frontend/src/pages/studio/KnowledgeWorkspacePage.vue`
- `frontend/src/pages/studio/IngestionPipelinePage.vue`
- `frontend/src/pages/studio/ModelWorkspacePage.vue`
- `frontend/src/pages/studio/WorkflowBuilderPage.vue`
- `frontend/src/pages/studio/AgentWorkspacePage.vue`
- `frontend/src/pages/studio/McpImportPage.vue`
- `frontend/src/pages/studio/SkillWorkspacePage.vue`
- `frontend/src/pages/studio/ObservabilityPage.vue`
- API 封装已覆盖:
- `frontend/src/api/*.ts`
- 页面/API 单测已覆盖:
- `frontend/src/pages/studio/__tests__/*`
- `frontend/src/api/__tests__/*`
## 5. 当前仍需持续关注的风险
- 当前多数“mapper / repository 验证”仍以结构契约测试为主,真实数据库集成测试覆盖度有限。
- 部分前端实现文档中的接口命名是草案,当前实现更多采用“旧管理接口 + Studio 聚合接口”的双轨方式;职责已覆盖,但验收时需要按“能力是否已落地”而非“路径字面一致”判断。
- 现有运行链路以“主数据优先 + 最小可运行”实现为主,复杂分支调度、远程 MCP 实时执行编排、重型运行器能力仍适合后续继续增强。
## 6. 本次审计后的新增变更
- 新增 `POST /api/knowledge/ingestion-runs`,补齐前端实现文档中的摄取运行创建入口。
- 补充 `IngestionRunControllerTests` 与前端 `ingestion.spec.ts` 创建接口测试。
- 补充 `WorkflowWorkspaceController` 中文注释与标准化业务日志。

View File

@@ -1,14 +1,33 @@
import { afterEach, describe, expect, it, vi } from 'vitest'; import { afterEach, describe, expect, it, vi } from 'vitest';
const getMock = vi.fn(); const getMock = vi.fn();
const postMock = vi.fn();
vi.mock('../request', () => ({ vi.mock('../request', () => ({
get: getMock, get: getMock,
post: postMock,
})); }));
describe('ingestion api', () => { describe('ingestion api', () => {
afterEach(() => { afterEach(() => {
getMock.mockReset(); getMock.mockReset();
postMock.mockReset();
});
it('creates ingestion run aggregate with store and document payload', async () => {
postMock.mockResolvedValue({
resultcode: '0',
message: null,
data: { runId: 'ingestion-1001-11' },
});
const { createIngestionRun } = await import('../ingestion');
await createIngestionRun('1001', '11');
expect(postMock).toHaveBeenCalledWith('/knowledge/ingestion-runs', {
storeId: '1001',
documentId: '11',
});
}); });
it('requests ingestion run aggregate with store and document params', async () => { it('requests ingestion run aggregate with store and document params', async () => {

View File

@@ -1,4 +1,4 @@
import { get } from './request'; import { get, post } from './request';
export interface IngestionRunFile { export interface IngestionRunFile {
documentId: string; documentId: string;
@@ -39,6 +39,13 @@ export interface IngestionRun {
logs: IngestionRunLog[]; logs: IngestionRunLog[];
} }
export function createIngestionRun(storeId: string, documentId: string) {
return post<IngestionRun>('/knowledge/ingestion-runs', {
storeId,
documentId,
});
}
export function getIngestionRun(runId: string, storeId: string, documentId: string) { export function getIngestionRun(runId: string, storeId: string, documentId: string) {
return get<IngestionRun>(`/knowledge/ingestion-runs/${runId}`, { return get<IngestionRun>(`/knowledge/ingestion-runs/${runId}`, {
params: { params: {