Version: 0.9.45.dev.260427
后端: 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永远只适合做选择题、判断题,不适合做开放创新题。
This commit is contained in:
@@ -46,7 +46,8 @@ func (p *ScheduleProvider) LoadScheduleState(ctx context.Context, userID int) (*
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p.loadScheduleStateWithTaskClasses(ctx, userID, taskClasses)
|
||||
// 2. 全量读场景保留“当前周兜底”,兼容“只看本周课表/微调”类请求。
|
||||
return p.loadScheduleStateWithTaskClasses(ctx, userID, taskClasses, true)
|
||||
}
|
||||
|
||||
// LoadScheduleStateForTaskClasses 按“本轮请求的任务类范围”加载 ScheduleState。
|
||||
@@ -69,7 +70,9 @@ func (p *ScheduleProvider) LoadScheduleStateForTaskClasses(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p.loadScheduleStateWithTaskClasses(ctx, userID, taskClasses)
|
||||
// 1. 粗排/主动编排场景必须严格按任务类时间窗加载;
|
||||
// 2. 若任务类缺少起止日期,则返回错误,交给上层 ask_user 补齐,而不是静默退回当前周。
|
||||
return p.loadScheduleStateWithTaskClasses(ctx, userID, taskClasses, false)
|
||||
}
|
||||
|
||||
// loadScheduleStateWithTaskClasses 负责把“指定任务类集合”装配成可操作的 ScheduleState。
|
||||
@@ -82,10 +85,14 @@ func (p *ScheduleProvider) loadScheduleStateWithTaskClasses(
|
||||
ctx context.Context,
|
||||
userID int,
|
||||
taskClasses []model.TaskClass,
|
||||
allowCurrentWeekFallback bool,
|
||||
) (*schedule.ScheduleState, error) {
|
||||
// 1. 确定规划窗口:优先使用 task class 日期范围,降级到当前周。
|
||||
windowDays, weeks := buildWindowFromTaskClasses(taskClasses)
|
||||
if len(windowDays) == 0 {
|
||||
if !allowCurrentWeekFallback {
|
||||
return nil, fmt.Errorf("任务类缺少有效时间窗:请补充 start_date/end_date 后再进行智能编排")
|
||||
}
|
||||
var err error
|
||||
windowDays, weeks, err = buildCurrentWeekWindow()
|
||||
if err != nil {
|
||||
@@ -262,12 +269,24 @@ func (p *ScheduleProvider) LoadTaskClassMetas(ctx context.Context, userID int, t
|
||||
if tc.ExcludedSlots != nil {
|
||||
meta.ExcludedSlots = []int(tc.ExcludedSlots)
|
||||
}
|
||||
if tc.ExcludedDaysOfWeek != nil {
|
||||
meta.ExcludedDaysOfWeek = []int(tc.ExcludedDaysOfWeek)
|
||||
}
|
||||
if tc.StartDate != nil {
|
||||
meta.StartDate = tc.StartDate.Format("2006-01-02")
|
||||
}
|
||||
if tc.EndDate != nil {
|
||||
meta.EndDate = tc.EndDate.Format("2006-01-02")
|
||||
}
|
||||
if tc.SubjectType != nil {
|
||||
meta.SubjectType = *tc.SubjectType
|
||||
}
|
||||
if tc.DifficultyLevel != nil {
|
||||
meta.DifficultyLevel = *tc.DifficultyLevel
|
||||
}
|
||||
if tc.CognitiveIntensity != nil {
|
||||
meta.CognitiveIntensity = *tc.CognitiveIntensity
|
||||
}
|
||||
metas = append(metas, meta)
|
||||
}
|
||||
return metas, nil
|
||||
|
||||
@@ -49,6 +49,7 @@ func LoadScheduleState(
|
||||
// 2.1 先放 extraItemCategories(低优先级,兜底);
|
||||
// 2.2 再用 taskClasses 覆盖(高优先级,确保本轮排课分类准确)。
|
||||
itemCategoryLookup := make(map[int]string)
|
||||
itemOrderLookup := buildTaskItemOrderLookup(taskClasses)
|
||||
for id, name := range extraItemCategories {
|
||||
itemCategoryLookup[id] = name
|
||||
}
|
||||
@@ -222,6 +223,7 @@ func LoadScheduleState(
|
||||
Slots: hostSlots,
|
||||
CategoryID: tc.ID,
|
||||
TaskClassID: tc.ID,
|
||||
TaskOrder: itemOrderLookup[item.ID],
|
||||
})
|
||||
itemStateIDs[item.ID] = stateID
|
||||
nextStateID++
|
||||
@@ -240,6 +242,7 @@ func LoadScheduleState(
|
||||
Slots: slots,
|
||||
CategoryID: tc.ID,
|
||||
TaskClassID: tc.ID,
|
||||
TaskOrder: itemOrderLookup[item.ID],
|
||||
})
|
||||
itemStateIDs[item.ID] = stateID
|
||||
nextStateID++
|
||||
@@ -261,6 +264,7 @@ func LoadScheduleState(
|
||||
Duration: defaultDuration,
|
||||
CategoryID: tc.ID,
|
||||
TaskClassID: tc.ID,
|
||||
TaskOrder: itemOrderLookup[item.ID],
|
||||
})
|
||||
itemStateIDs[item.ID] = stateID
|
||||
nextStateID++
|
||||
@@ -285,12 +289,24 @@ func LoadScheduleState(
|
||||
if tc.ExcludedSlots != nil {
|
||||
meta.ExcludedSlots = []int(tc.ExcludedSlots)
|
||||
}
|
||||
if tc.ExcludedDaysOfWeek != nil {
|
||||
meta.ExcludedDaysOfWeek = []int(tc.ExcludedDaysOfWeek)
|
||||
}
|
||||
if tc.StartDate != nil {
|
||||
meta.StartDate = tc.StartDate.Format("2006-01-02")
|
||||
}
|
||||
if tc.EndDate != nil {
|
||||
meta.EndDate = tc.EndDate.Format("2006-01-02")
|
||||
}
|
||||
if tc.SubjectType != nil {
|
||||
meta.SubjectType = *tc.SubjectType
|
||||
}
|
||||
if tc.DifficultyLevel != nil {
|
||||
meta.DifficultyLevel = *tc.DifficultyLevel
|
||||
}
|
||||
if tc.CognitiveIntensity != nil {
|
||||
meta.CognitiveIntensity = *tc.CognitiveIntensity
|
||||
}
|
||||
state.TaskClasses = append(state.TaskClasses, meta)
|
||||
}
|
||||
}
|
||||
@@ -343,6 +359,7 @@ func LoadScheduleState(
|
||||
Slots: hostSlots,
|
||||
CategoryID: categoryID,
|
||||
TaskClassID: taskClassID,
|
||||
TaskOrder: itemOrderLookup[itemID],
|
||||
})
|
||||
itemStateIDs[itemID] = guestStateID
|
||||
nextStateID++
|
||||
@@ -385,6 +402,26 @@ func isTaskItemPending(item model.TaskClassItem) bool {
|
||||
return *item.Status == model.TaskItemStatusUnscheduled
|
||||
}
|
||||
|
||||
// buildTaskItemOrderLookup 为每个 task_item 构建稳定顺序号。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 优先使用数据库里的 item.Order,保持用户或上游生成的显式顺序;
|
||||
// 2. 若历史数据缺少 order,则退回 TaskClass.Items 当前顺序,保证写工具层仍有稳定边界;
|
||||
// 3. 只负责构建运行态映射,不回写数据库。
|
||||
func buildTaskItemOrderLookup(taskClasses []model.TaskClass) map[int]int {
|
||||
lookup := make(map[int]int)
|
||||
for _, tc := range taskClasses {
|
||||
for idx, item := range tc.Items {
|
||||
order := idx + 1
|
||||
if item.Order != nil && *item.Order > 0 {
|
||||
order = *item.Order
|
||||
}
|
||||
lookup[item.ID] = order
|
||||
}
|
||||
}
|
||||
return lookup
|
||||
}
|
||||
|
||||
// estimateTaskItemDuration 估算 pending 任务默认时长。
|
||||
//
|
||||
// 规则:若任务类声明了 total_slots,则按 total_slots / item_count 取整(最少 1);
|
||||
|
||||
Reference in New Issue
Block a user