feat(session): 会话存储体系实现 & Chat多Agent路由
- 新增诊断会话(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
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
package com.superbiz.agent.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Agent 决策步骤实体
|
||||
* 对应表: agent_step
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "agent_step", indexes = {
|
||||
@Index(name = "idx_session_step", columnList = "session_id, step_index"),
|
||||
@Index(name = "idx_agent_name", columnList = "agent_name")
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AgentStep {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "session_id", nullable = false, length = 64)
|
||||
private String sessionId;
|
||||
|
||||
@Column(name = "step_index", nullable = false)
|
||||
private Integer stepIndex;
|
||||
|
||||
@Column(name = "agent_name", nullable = false, length = 32)
|
||||
private String agentName;
|
||||
|
||||
@Column(name = "model_input", columnDefinition = "TEXT")
|
||||
private String modelInput;
|
||||
|
||||
@Column(name = "model_output", columnDefinition = "TEXT")
|
||||
private String modelOutput;
|
||||
|
||||
@Column(name = "thought", columnDefinition = "TEXT")
|
||||
private String thought;
|
||||
|
||||
@Column(name = "has_tool_call")
|
||||
private Boolean hasToolCall;
|
||||
|
||||
@Column(name = "duration_ms")
|
||||
private Integer durationMs;
|
||||
|
||||
@Column(name = "token_count")
|
||||
private Integer tokenCount;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
createdAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package com.superbiz.agent.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import com.superbiz.agent.domain.enums.DiagnosisStatus;
|
||||
import com.superbiz.agent.domain.enums.FaultCategory;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 诊断记录实体
|
||||
* 对应表: diagnosis_record
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "diagnosis_record", indexes = {
|
||||
@Index(name = "idx_business_id", columnList = "business_id"),
|
||||
@Index(name = "idx_trace_id", columnList = "trace_id"),
|
||||
@Index(name = "idx_session_id", columnList = "session_id"),
|
||||
@Index(name = "idx_fault_category", columnList = "fault_category"),
|
||||
@Index(name = "idx_error_code", columnList = "error_code"),
|
||||
@Index(name = "idx_created_at", columnList = "created_at"),
|
||||
@Index(name = "idx_status", columnList = "status")
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DiagnosisRecord {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "diagnosis_id", unique = true, nullable = false, length = 64)
|
||||
private String diagnosisId;
|
||||
|
||||
// 关联信息
|
||||
@Column(name = "session_id", length = 64)
|
||||
private String sessionId;
|
||||
|
||||
@Column(name = "business_id", length = 128)
|
||||
private String businessId;
|
||||
|
||||
@Column(name = "trace_id", length = 64)
|
||||
private String traceId;
|
||||
|
||||
// 故障分类
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "fault_category", length = 32, columnDefinition = "VARCHAR(32)")
|
||||
private FaultCategory faultCategory;
|
||||
|
||||
@Column(name = "fault_source", length = 128)
|
||||
private String faultSource;
|
||||
|
||||
@Column(name = "fault_target", length = 256)
|
||||
private String faultTarget;
|
||||
|
||||
// 错误信息
|
||||
@Column(name = "error_code", length = 64)
|
||||
private String errorCode;
|
||||
|
||||
@Column(name = "error_message", columnDefinition = "TEXT")
|
||||
private String errorMessage;
|
||||
|
||||
@Column(name = "stack_trace", columnDefinition = "TEXT")
|
||||
private String stackTrace;
|
||||
|
||||
// 诊断结果
|
||||
@Column(name = "problem_type", length = 32)
|
||||
private String problemType;
|
||||
|
||||
@Column(name = "root_cause", columnDefinition = "TEXT")
|
||||
private String rootCause;
|
||||
|
||||
@Column(name = "solution", columnDefinition = "TEXT")
|
||||
private String solution;
|
||||
|
||||
@Column(name = "report_markdown", columnDefinition = "TEXT")
|
||||
private String reportMarkdown;
|
||||
|
||||
// 评估指标
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "status", length = 16, columnDefinition = "VARCHAR(16)")
|
||||
private DiagnosisStatus status = DiagnosisStatus.PENDING;
|
||||
|
||||
@Column(name = "confidence")
|
||||
private Integer confidence;
|
||||
|
||||
@Column(name = "duration")
|
||||
private Integer duration;
|
||||
|
||||
// 用户反馈
|
||||
@Column(name = "feedback", length = 16)
|
||||
private String feedback;
|
||||
|
||||
// 调试字段 - JSON 类型
|
||||
@JdbcTypeCode(SqlTypes.JSON)
|
||||
@Column(name = "tool_calls", columnDefinition = "JSON")
|
||||
private List<Map<String, Object>> toolCalls;
|
||||
|
||||
// 元数据
|
||||
@Column(name = "created_by", length = 64)
|
||||
private String createdBy;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
createdAt = LocalDateTime.now();
|
||||
updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
protected void onUpdate() {
|
||||
updatedAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.superbiz.agent.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 诊断会话实体
|
||||
* 对应表: diagnosis_session
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "diagnosis_session", indexes = {
|
||||
@Index(name = "idx_created_at", columnList = "created_at"),
|
||||
@Index(name = "idx_status", columnList = "status"),
|
||||
@Index(name = "idx_agent_flow", columnList = "agent_flow")
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DiagnosisSession {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "session_id", unique = true, nullable = false, length = 64)
|
||||
private String sessionId;
|
||||
|
||||
@Column(name = "query", nullable = false, columnDefinition = "TEXT")
|
||||
private String query;
|
||||
|
||||
@Column(name = "status", length = 16)
|
||||
private String status = "PENDING";
|
||||
|
||||
@Column(name = "agent_flow", length = 32)
|
||||
private String agentFlow;
|
||||
|
||||
@Column(name = "total_duration_ms")
|
||||
private Integer totalDurationMs;
|
||||
|
||||
@Column(name = "total_token_count")
|
||||
private Integer totalTokenCount;
|
||||
|
||||
@Column(name = "step_count")
|
||||
private Integer stepCount;
|
||||
|
||||
@Column(name = "tool_call_count")
|
||||
private Integer toolCallCount;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.JSON)
|
||||
@Column(name = "self_evaluation", columnDefinition = "JSON")
|
||||
private String selfEvaluation;
|
||||
|
||||
@Column(name = "feedback", length = 16)
|
||||
private String feedback;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
createdAt = LocalDateTime.now();
|
||||
updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
protected void onUpdate() {
|
||||
updatedAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.superbiz.agent.domain.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 工具调用明细实体
|
||||
* 对应表: tool_invocation
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "tool_invocation", indexes = {
|
||||
@Index(name = "idx_session_id", columnList = "session_id"),
|
||||
@Index(name = "idx_tool_name", columnList = "tool_name"),
|
||||
@Index(name = "idx_retrieval_layer", columnList = "retrieval_layer")
|
||||
})
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ToolInvocation {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "session_id", nullable = false, length = 64)
|
||||
private String sessionId;
|
||||
|
||||
@Column(name = "step_id")
|
||||
private Long stepId;
|
||||
|
||||
@Column(name = "tool_name", nullable = false, length = 64)
|
||||
private String toolName;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.JSON)
|
||||
@Column(name = "input_params", nullable = false, columnDefinition = "JSON")
|
||||
private String inputParams;
|
||||
|
||||
@Column(name = "output_preview", columnDefinition = "TEXT")
|
||||
private String outputPreview;
|
||||
|
||||
@Column(name = "output_length")
|
||||
private Integer outputLength;
|
||||
|
||||
@Column(name = "retrieval_layer", length = 8)
|
||||
private String retrievalLayer;
|
||||
|
||||
@Column(name = "l0_match_count")
|
||||
private Integer l0MatchCount;
|
||||
|
||||
@Column(name = "l1_match_count")
|
||||
private Integer l1MatchCount;
|
||||
|
||||
@Column(name = "is_truncated")
|
||||
private Boolean isTruncated;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.JSON)
|
||||
@Column(name = "retrieval_details", columnDefinition = "JSON")
|
||||
private String retrievalDetails;
|
||||
|
||||
@Column(name = "duration_ms")
|
||||
private Integer durationMs;
|
||||
|
||||
@Column(name = "success")
|
||||
private Boolean success;
|
||||
|
||||
@Column(name = "error_message", columnDefinition = "TEXT")
|
||||
private String errorMessage;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
createdAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.superbiz.agent.domain.enums;
|
||||
|
||||
/**
|
||||
* 诊断状态枚举
|
||||
*/
|
||||
public enum DiagnosisStatus {
|
||||
PENDING("待处理"),
|
||||
RUNNING("诊断中"),
|
||||
SUCCESS("成功"),
|
||||
FAILED("失败");
|
||||
|
||||
private final String description;
|
||||
|
||||
DiagnosisStatus(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user