chore: 归档 session-storage change

- 创建 devflow 项目档案(brief/evidence/decisions/acceptance)
- 更新 devflow/index.md 索引
- 移动 OpenSpec 到 archive
This commit is contained in:
zhuyongxin
2026-06-26 17:33:56 +08:00
parent 9b52afce07
commit e3f20b1f06
12 changed files with 95 additions and 0 deletions
@@ -0,0 +1,153 @@
# 会话存储 — 功能规格
## Requirement 1:三张新表的 DDL
**路径**:`src/main/resources/db/migration/V005__create_session_storage.sql`
**内容**:
- 创建 `diagnosis_session` 表(DDL 见 design.md)
- 创建 `agent_step` 表(DDL 见 design.md)
- 创建 `tool_invocation` 表(DDL 见 design.md)
- 三条 DDL 写在同一个迁移文件中
**验收标准**:
- [ ] Flyway migrate 后三张表均存在
- [ ] 表结构字段类型、索引与设计一致
- [ ] JSON 列使用 `JSON` 类型(MySQL 8+)
---
## Requirement 2:JPA Entity + Repository
### 2.1 实体类
**路径**:
- `src/main/java/com/superbiz/agent/domain/entity/DiagnosisSession.java`
- `src/main/java/com/superbiz/agent/domain/entity/AgentStep.java`
- `src/main/java/com/superbiz/agent/domain/entity/ToolInvocation.java`
**要求**:
- 使用 `@Entity` + `@Table(name = "...")` 映射
- JSON 字段使用 `@JdbcTypeCode(SqlTypes.JSON)`(同现有 `DiagnosisRecord.toolCalls`)
- `@PrePersist` 自动填充 `createdAt`
- 使用 Lombok `@Data @Builder @NoArgsConstructor @AllArgsConstructor`
### 2.2 Repository 接口
**路径**:
- `src/main/java/com/superbiz/agent/repository/DiagnosisSessionRepository.java`
- `src/main/java/com/superbiz/agent/repository/AgentStepRepository.java`
- `src/main/java/com/superbiz/agent/repository/ToolInvocationRepository.java`
**要求**:
- 继承 `JpaRepository`
- `DiagnosisSessionRepository`:`findBySessionId(String sessionId)`
- `AgentStepRepository`:`findBySessionIdOrderByStepIndex(String sessionId)`、`countBySessionId(String sessionId)`
- `ToolInvocationRepository`:`findBySessionId(String sessionId)`、`findByToolName(String toolName)`
**验收标准**:
- [ ] 3 个 Entity 编译通过
- [ ] 3 个 Repository 编译通过
- [ ] 自定义查询方法命名符合 Spring Data JPA 规范
---
## Requirement 3:AgentLoggingHook 改造为 Spring Bean
**路径**:`src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java`
**变更**:
- 类上加 `@Component` 注解
- 不再通过 new 创建实例
- 构造注入 `AgentStepRepository`
- beforeModel:创建 `AgentStep` 记录,设置 `modelInput`,记录开始时间到 `RunnableConfig`
- afterModel:更新对应 `AgentStep`,设置 `modelOutput`、`thought`、`hasToolCall`、`durationMs`、`tokenCount`
- `modelInput` 和 `modelOutput` 只存摘要(前 500 字符),不存完整消息体
**session_id 传递机制**:
- 调用方(ChatService/AiOpsService)通过 `RunnableConfig.metadata()` 传入 `sessionId`
- Hook 从 `config.getMetadata("sessionId")` 读取
**验收标准**:
- [ ] Hook 可注入 AgentStepRepository
- [ ] beforeModel 创建 agent_step 记录并写入 DB
- [ ] afterModel 更新对应 agent_step 记录
- [ ] model_input/output 摘要不超过 500 字符
- [ ] 从 RunnableConfig 正确读取 sessionId
- [ ] 原日志输出行为保持不变
---
## Requirement 4:ChatService 集成
**路径**:`src/main/java/com/superbiz/agent/service/ChatService.java`
**变更**:
- 注入 `DiagnosisSessionRepository`
- `executeChat()` 中:
- 执行前:创建 `DiagnosisSession`(status=RUNNING),生成 `sessionId`,生成 `agent_flow=CHAT`
- 通过 `RunnableConfig` 将 sessionId 传给 Hook
- 执行后:更新 `DiagnosisSession`(status=SUCCESS/FAILED,汇总 step_count、tool_call_count、total_duration_ms)
- 不再通过 `new AgentLoggingHook()` 创建 Hook,改为注入 Bean 的 Hook
**验收标准**:
- [ ] executeChat 执行前后分别创建和更新 diagnosis_session
- [ ] sessionId 通过 RunnableConfig 正确传递给 Hook
- [ ] 汇总指标(duration、step_count)正确写入
- [ ] 异常路径正确设置 status=FAILED
---
## Requirement 5:AiOpsService 集成
**路径**:`src/main/java/com/superbiz/agent/service/AiOpsService.java`
**变更**:
- 注入 `DiagnosisSessionRepository` 和 `AgentLoggingHook`
- `executeAiOpsAnalysis()` 中:
- 执行前:创建 `DiagnosisSession`(status=RUNNING, agent_flow=AI_OPS)
- 构建 Planner 和 Executor 时传入 `AgentLoggingHook` 实例(使用注入的 Bean)
- 通过 `RunnableConfig` 将 sessionId 传给 Hook
- 执行后:更新 `DiagnosisSession`(汇总指标)
- Supervisor 不加 Hook
**验收标准**:
- [ ] AiOpsService 执行前后分别创建和更新 diagnosis_session
- [ ] Planner 和 Executor 各带 AgentLoggingHook
- [ ] 两个 Hook 使用相同的 sessionId
- [ ] Supervisor 不产生 agent_step 记录
---
## Requirement 6:LookupKnowledgeTool 写入 tool_invocation
**路径**:`src/main/java/com/superbiz/agent/tool/LookupKnowledgeTool.java`
**变更**:
- 注入 `ToolInvocationRepository`
- `lookupKnowledge()` 执行后:
- 创建 `ToolInvocation` 记录
- 写入 `toolName=lookup_knowledge`、`inputParams`(query)、`outputPreview`(前 500 字符)
- 写入检索质量:`retrievalLayer`、`l0MatchCount`、`l1MatchCount`、`isTruncated`、`retrievalDetails`
- 写入 `durationMs`、`success`
- `sessionId` 和 `stepId` 如何获取需要方案设计(见开放问题)
**验收标准**:
- [ ] lookup_knowledge 每次调用后创建 tool_invocation 记录
- [ ] 检索质量字段(L0/L1 明细)正确写入
- [ ] 工具执行失败的场景正确记录
---
## Requirement 7:构造注入适配(无 @Async)
**路径**:所有涉及新增 Repository 注入的类
**要求**:
- 所有新注入使用构造注入(`@RequiredArgsConstructor` 或显式构造器)
- 不在 MV 阶段引入 @Async 异步基础设施
- Hook 中的 DB 写入是同步的,作为已知的技术债记录
**验收标准**:
- [ ] 没有使用 @Autowired 字段注入新 Repository(保持项目已有风格)
- [ ] 没有引入 @Async / @EnableAsync