- 新增诊断会话(diagnosis_session/agent_step/tool_invocation)三表 - AgentLoggingHook 持久化 agent_step,记录决策链和耗时 - LookupKnowledgeTool 写入 tool_invocation,记录L0/L1检索质量 - TokenTrackingChatModel 捕获真实token用量 - Chat接口支持意图路由:简单问题单Agent,复杂问题多Agent(Planner+Executor) - Prompt外置到 src/main/resources/prompts/ - 删除旧 diagnosis_record 表及相关文件 - 新增SessionContextHolder(ThreadLocal传递sessionId) - QuestionComplexity 复杂度判断工具 - 测试覆盖三张新表的Repository
154 lines
5.7 KiB
Markdown
154 lines
5.7 KiB
Markdown
# 会话存储 — 功能规格
|
||
|
||
## 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
|