后端: 1. execute 主链路重构为“上下文工具域 + 主动优化候选闭环”——移除 order_guard,粗排后默认进入主动微调,先诊断再从后端候选中选择 move/swap,避免 LLM 自由全局乱搜 2. 工具体系升级为动态注入协议——新增 context_tools_add / remove、工具域与二级包映射、主动优化白名单;schedule / taskclass / web 工具按域按包暴露,msg0 规则包与 execute 上下文同步重写 3. analyze_health 升级为主动优化唯一裁判入口——补齐 rhythm / tightness / profile / feasibility 指标、候选扫描与复诊打分、停滞信号、forced imperfection 判定,并把连续优化状态写回运行态 4. 任务类能力并入新 Agent 执行链——新增 upsert_task_class 写工具与启动注入事务写入;任务类模型补充学科画像与整天屏蔽配置,粗排支持 excluded_days_of_week,steady 策略改为基于目标位置/单日负载/分散度/缓冲的候选打分 5. 运行态与路由补齐优化模式语义——新增 active tool domain/packs、pending context hook、active optimize only、taskclass 写入回盘快照;区分 first_full / global_reopt / local_adjust,并完善首次粗排后默认 refine 的判定 前端: 6. 助手时间线渲染细化——推理内容改为独立 reasoning block,支持与工具/状态/正文按时序交错展示,自动收口折叠,修正 confirm reject 恢复动作 仓库: 7. newAgent 文档整体迁入 docs/backend,补充主动优化执行规划与顺序约束拆解文档,删除旧调试日志文件 PS:这次科研了2天,总算是有些进展了——LLM永远只适合做选择题、判断题,不适合做开放创新题。
204 lines
8.0 KiB
Go
204 lines
8.0 KiB
Go
package model
|
||
|
||
import (
|
||
"database/sql/driver"
|
||
"encoding/json"
|
||
"fmt"
|
||
"time"
|
||
)
|
||
|
||
// TaskClass 用于和数据库中的 task_classes 表进行映射
|
||
type TaskClass struct {
|
||
//section 1
|
||
ID int `gorm:"column:id;primaryKey;autoIncrement"`
|
||
UserID *int `gorm:"column:user_id;index:idx_task_classes_user_id"`
|
||
//section 2
|
||
Name *string `gorm:"column:name;size:255"`
|
||
Mode *string `gorm:"column:mode;type:enum('auto','manual')"`
|
||
StartDate *time.Time `gorm:"column:start_date"`
|
||
EndDate *time.Time `gorm:"column:end_date"`
|
||
SubjectType *string `gorm:"column:subject_type;size:32;comment:学科类型 quantitative|memory|reading|mixed"`
|
||
DifficultyLevel *string `gorm:"column:difficulty_level;size:16;comment:难度等级 low|medium|high"`
|
||
CognitiveIntensity *string `gorm:"column:cognitive_intensity;size:16;comment:认知强度 low|medium|high"`
|
||
//section 3
|
||
TotalSlots *int `gorm:"column:total_slots;comment:分配的总节数"`
|
||
AllowFillerCourse *bool `gorm:"column:allow_filler_course;default:true"`
|
||
Strategy *string `gorm:"column:strategy;type:enum('steady','rapid')"`
|
||
ExcludedSlots IntSlice `gorm:"column:excluded_slots;type:json;comment:不想要的时段切片"`
|
||
ExcludedDaysOfWeek IntSlice `gorm:"column:excluded_days_of_week;type:json;comment:不想要的星期几切片(1-7)"`
|
||
Items []TaskClassItem `gorm:"foreignKey:CategoryID;references:ID"` // 一对多关联:一个 TaskClass 有多个 TaskClassItem
|
||
}
|
||
|
||
// IntSlice 用于把 []int 以 JSON 形式存入/读出数据库 json 字段
|
||
type IntSlice []int
|
||
|
||
func (s IntSlice) Value() (driver.Value, error) {
|
||
// nil -> NULL;空切片 -> "[]"
|
||
if s == nil {
|
||
return nil, nil
|
||
}
|
||
return json.Marshal([]int(s))
|
||
}
|
||
|
||
func (s *IntSlice) Scan(value any) error {
|
||
if value == nil {
|
||
*s = nil
|
||
return nil
|
||
}
|
||
|
||
var data []byte
|
||
switch v := value.(type) {
|
||
case []byte:
|
||
data = v
|
||
case string:
|
||
data = []byte(v)
|
||
default:
|
||
return fmt.Errorf("IntSlice: 不支持的扫描类型: %T", value)
|
||
}
|
||
|
||
var out []int
|
||
if err := json.Unmarshal(data, &out); err != nil {
|
||
return err
|
||
}
|
||
*s = IntSlice(out)
|
||
return nil
|
||
}
|
||
|
||
// TaskClassItem 用于和数据库中的 task_items 表进行映射
|
||
type TaskClassItem struct {
|
||
//section 1
|
||
ID int `gorm:"column:id;primaryKey;autoIncrement"`
|
||
CategoryID *int `gorm:"column:category_id"` //对应 TaskClass 的 ID
|
||
//section 2
|
||
Order *int `gorm:"column:order"`
|
||
Content *string `gorm:"column:content;type:text"`
|
||
EmbeddedTime *TargetTime `gorm:"column:embedded_time;type:json;comment:目标时间{date,section_from,section_to}"`
|
||
Status *int `gorm:"column:status;comment:1:未安排, 2:已应用"`
|
||
}
|
||
|
||
// UserAddTaskClassRequest 用于处理用户添加任务类别的请求
|
||
type UserAddTaskClassRequest struct {
|
||
Name string `json:"name" binding:"required"`
|
||
StartDate string `json:"start_date" binding:"required"` // YYYY-MM-DD
|
||
EndDate string `json:"end_date" binding:"required"` // YYYY-MM-DD
|
||
Mode string `json:"mode" binding:"required,oneof=auto manual"`
|
||
SubjectType string `json:"subject_type,omitempty"`
|
||
DifficultyLevel string `json:"difficulty_level,omitempty"`
|
||
CognitiveIntensity string `json:"cognitive_intensity,omitempty"`
|
||
Config UserAddTaskClassConfig `json:"config" binding:"required"`
|
||
Items []UserAddTaskClassItemRequest `json:"items" binding:"required"`
|
||
}
|
||
|
||
// UserAddTaskClassConfig 用于处理用户添加任务类别时的配置部分
|
||
type UserAddTaskClassConfig struct {
|
||
TotalSlots int `json:"total_slots" binding:"required,min=1"`
|
||
AllowFillerCourse bool `json:"allow_filler_course"`
|
||
Strategy string `json:"strategy" binding:"required,oneof=steady rapid"`
|
||
ExcludedSlots []int `json:"excluded_slots"`
|
||
ExcludedDaysOfWeek []int `json:"excluded_days_of_week"`
|
||
}
|
||
|
||
// UserAddTaskClassItemRequest 用于处理用户添加任务类别时的任务块部分
|
||
type UserAddTaskClassItemRequest struct {
|
||
ID int `json:"id,omitempty"` // 任务块的数据库主键 ID(查询时返回,创建时可省略)
|
||
Order int `json:"order" binding:"required,min=1"`
|
||
Content string `json:"content" binding:"required"`
|
||
EmbeddedTime *TargetTime `json:"embedded_time"` // 例: 2025-12-22 1-2节; nil 表示未安排
|
||
}
|
||
|
||
// TargetTime 表示任务块的目标时间
|
||
type TargetTime struct {
|
||
Week int `json:"week"` // 周次
|
||
DayOfWeek int `json:"day_of_week"` // 星期几
|
||
SectionFrom int `json:"section_from"` // 起始节次
|
||
SectionTo int `json:"section_to"` // 结束节次
|
||
}
|
||
|
||
// UserGetTaskClassesResponse 用于返回用户的任务类列表,展示简要信息
|
||
type UserGetTaskClassesResponse struct {
|
||
TaskClasses []TaskClassSummary `json:"task_classes"`
|
||
}
|
||
|
||
// TaskClassSummary 提供任务类别的简要信息
|
||
type TaskClassSummary struct {
|
||
ID int `json:"id"`
|
||
Name string `json:"name"`
|
||
Mode string `json:"mode"`
|
||
Strategy string `json:"strategy"`
|
||
StartDate time.Time `json:"start_date"`
|
||
EndDate time.Time `json:"end_date"`
|
||
TotalSlots int `json:"total_slots"`
|
||
SubjectType string `json:"subject_type,omitempty"`
|
||
DifficultyLevel string `json:"difficulty_level,omitempty"`
|
||
CognitiveIntensity string `json:"cognitive_intensity,omitempty"`
|
||
}
|
||
|
||
type UserInsertTaskClassItemToScheduleRequest struct {
|
||
Week int `json:"week" binding:"required,min=1"`
|
||
DayOfWeek int `json:"day_of_week" binding:"required,min=1,max=7"`
|
||
StartSection int `json:"start_section" binding:"required,min=1"`
|
||
EndSection int `json:"end_section" binding:"required,min=1,gtefield=StartSection"`
|
||
EmbedCourseEventID int `json:"embed_course_event_id"` // 可选,嵌入的课程日程事件 ID
|
||
}
|
||
|
||
type UserInsertTaskClassItemToScheduleRequestBatch struct {
|
||
TaskClassID int `json:"task_class_id" binding:"required"`
|
||
Items []SingleTaskClassItem `json:"items" binding:"required,dive,required"`
|
||
}
|
||
|
||
type SingleTaskClassItem struct {
|
||
TaskItemID int `json:"task_item_id" binding:"required"`
|
||
Week int `json:"week" binding:"required,min=1"`
|
||
DayOfWeek int `json:"day_of_week" binding:"required,min=1,max=7"`
|
||
StartSection int `json:"start_section" binding:"required,min=1"`
|
||
EndSection int `json:"end_section" binding:"required,min=1,gtefield=StartSection"`
|
||
EmbedCourseEventID int `json:"embed_course_event_id"` // 可选,嵌入的课程日程事件 ID
|
||
}
|
||
|
||
// Value 实现 driver.Valuer 接口,负责将 TargetTime 转换为数据库存储的格式
|
||
func (t *TargetTime) Value() (driver.Value, error) {
|
||
if t == nil {
|
||
return nil, nil
|
||
}
|
||
// 💡 关键:调用 json.Marshal 将结构体转为 []byte
|
||
// 这样 GORM 就能把这一串 JSON 存进数据库的 text/json 字段了
|
||
return json.Marshal(t)
|
||
}
|
||
|
||
// Scan 实现 sql.Scanner 接口,负责将数据库中的值转换为 TargetTime 结构体
|
||
func (t *TargetTime) Scan(value any) error {
|
||
if value == nil {
|
||
// 如果数据库是 NULL,保持指针对应的对象为零值即可
|
||
// 或者在业务层判断 nil
|
||
return nil
|
||
}
|
||
|
||
var data []byte
|
||
switch v := value.(type) {
|
||
case []byte:
|
||
data = v
|
||
case string:
|
||
data = []byte(v)
|
||
default:
|
||
return fmt.Errorf("TargetTime: 不支持的扫描类型: %T", value)
|
||
}
|
||
|
||
return json.Unmarshal(data, t)
|
||
}
|
||
|
||
// TableName 指定 TaskClass 对应的数据库表名
|
||
func (TaskClass) TableName() string {
|
||
return "task_classes"
|
||
}
|
||
|
||
// TableName 指定 TaskClassItem 对应的数据库表名
|
||
func (TaskClassItem) TableName() string {
|
||
return "task_items"
|
||
}
|
||
|
||
// 任务块状态常量
|
||
const (
|
||
TaskItemStatusUnscheduled = 1 // 未安排
|
||
TaskItemStatusApplied = 2 // 已应用
|
||
)
|