Version: 0.7.2.dev.260322

feat(schedule-plan):  重构智能排程链路并修复粗排双节对齐问题

-  新增“对话级排程状态持久化”能力:引入 `agent_schedule_states` 模型/DAO,并接入启动迁移
-  智能排程图升级:补齐小幅微调(quick refine)分支,完善预算/并发/状态字段流转
-  预览链路增强:完善排程预览服务读写与桥接逻辑,新增本地预览页 `infra/schedule_preview_viewer.html`
- ♻️ 缓存治理统一:将相关缓存处理收口到 DAO + `cache_deleter` 联动清理,移除旧散落逻辑
- 🐛 修复粗排核心 bug:禁止单节降级,强制双节并按 `1-2/3-4/...` 对齐;修复结束日扫描边界问题
-  新增粗排回归测试:覆盖孤立单节、偶数起点双节、Filler 对齐等关键场景
This commit is contained in:
Losita
2026-03-22 13:50:10 +08:00
parent f3f9902e93
commit e5b27df80d
20 changed files with 1961 additions and 166 deletions

View File

@@ -1,6 +1,7 @@
package scheduleplan
import (
"strings"
"time"
"github.com/LoveLosita/smartflow/backend/model"
@@ -38,6 +39,16 @@ const (
// 1. 周级输入规模通常比单天更大,默认并发度不宜过高,避免触发模型侧限流;
// 2. 可在运行时按请求状态覆盖。
schedulePlanDefaultWeeklyRefineConcurrency = 2
// schedulePlanAdjustmentScopeSmall 表示“小改动微调”。
// 语义:优先走快速路径,只做轻量周级调整。
schedulePlanAdjustmentScopeSmall = "small"
// schedulePlanAdjustmentScopeMedium 表示“中等改动微调”。
// 语义:跳过日内拆分,直接进入周级配平。
schedulePlanAdjustmentScopeMedium = "medium"
// schedulePlanAdjustmentScopeLarge 表示“大改动重排”。
// 语义:必要时重新走全量路径(日内并发 + 周级配平)。
schedulePlanAdjustmentScopeLarge = "large"
)
// DayGroup 是“按天拆分后”的最小优化单元。
@@ -168,6 +179,23 @@ type SchedulePlanState struct {
PreviousPlanJSON string
// IsAdjustment 标记本次是否为微调请求(而非全新排程)。
IsAdjustment bool
// RestartRequested 标记本轮是否要求“放弃历史快照并重新排程”。
//
// 语义:
// 1. true强制清空 Previous* 并走全新构建;
// 2. false允许按同会话历史快照做增量微调。
RestartRequested bool
// AdjustmentScope 表示本轮改动力度分级small/medium/large
//
// 分流语义:
// 1. small走快速微调节点再进入周级优化
// 2. medium跳过 daily直接周级优化
// 3. large优先走全量路径多任务类时会经过 daily 并发)。
AdjustmentScope string
// AdjustmentReason 是模型给出的力度判定理由,用于日志排障与 review。
AdjustmentReason string
// AdjustmentConfidence 是模型给出的力度判定置信度0-1
AdjustmentConfidence float64
// HasPreviousPreview 标记是否命中“同会话上一次排程预览快照”。
//
// 语义:
@@ -192,6 +220,12 @@ type SchedulePlanState struct {
// 1. 保持 final_check 的数量核对口径稳定;
// 2. return_preview 阶段可继续回填 embedded_time。
PreviousAllocatedItems []model.TaskClassItem
// PreviousCandidatePlans 是上一版预览保存的周视图结构化结果。
//
// 用途:
// 1. 连续微调时可直接复用,避免重复转换;
// 2. 兜底展示层(即使本轮未走全量粗排,仍可给前端稳定结构)。
PreviousCandidatePlans []model.UserWeekSchedule
// ── 最终输出 ──
@@ -215,6 +249,7 @@ func NewSchedulePlanState(traceID string, userID int, conversationID string) *Sc
TaskTagHintsByName: make(map[string]string),
DailyRefineConcurrency: schedulePlanDefaultDailyRefineConcurrency,
WeeklyRefineConcurrency: schedulePlanDefaultWeeklyRefineConcurrency,
AdjustmentScope: schedulePlanAdjustmentScopeLarge,
ReactMaxRound: 2,
WeeklyAdjustBudget: schedulePlanDefaultWeeklyAdjustBudget,
WeeklyTotalBudget: schedulePlanDefaultWeeklyTotalBudget,
@@ -234,3 +269,19 @@ func schedulePlanLocation() *time.Location {
func schedulePlanNowToMinute() time.Time {
return time.Now().In(schedulePlanLocation()).Truncate(time.Minute)
}
// normalizeAdjustmentScope 归一化排程微调力度字段。
//
// 兜底策略:
// 1. 只接受 small/medium/large
// 2. 任何未知值都回退为 large保证不会误走“过轻”路径。
func normalizeAdjustmentScope(raw string) string {
switch strings.ToLower(strings.TrimSpace(raw)) {
case schedulePlanAdjustmentScopeSmall:
return schedulePlanAdjustmentScopeSmall
case schedulePlanAdjustmentScopeMedium:
return schedulePlanAdjustmentScopeMedium
default:
return schedulePlanAdjustmentScopeLarge
}
}