Files
SuperBizAgent-java/openspec/changes/archive/2026-06-26-session-storage/specs/functional-spec.md
T
zhuyongxin e3f20b1f06 chore: 归档 session-storage change
- 创建 devflow 项目档案(brief/evidence/decisions/acceptance)
- 更新 devflow/index.md 索引
- 移动 OpenSpec 到 archive
2026-06-26 17:33:56 +08:00

154 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 会话存储 — 功能规格
## 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