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

@@ -51,17 +51,34 @@ func (s *AgentService) runSchedulePlanFlow(
// 2.1.2 先读可让本轮在内存中复用上轮 HybridEntries。
// 2.2 清理旧 key 仍然保留,避免前端在本轮进行中误读到旧结果。
var previousPreview *model.SchedulePlanPreviewCache
if s.agentCache != nil {
preview, getErr := s.agentCache.GetSchedulePlanPreview(ctx, userID, chatID)
if s.cacheDAO != nil {
preview, getErr := s.cacheDAO.GetSchedulePlanPreviewFromCache(ctx, userID, chatID)
if getErr != nil {
log.Printf("读取上一版排程预览失败 chat_id=%s: %v", chatID, getErr)
} else {
previousPreview = preview
}
if delErr := s.agentCache.DeleteSchedulePlanPreview(ctx, userID, chatID); delErr != nil {
if delErr := s.cacheDAO.DeleteSchedulePlanPreviewFromCache(ctx, userID, chatID); delErr != nil {
log.Printf("清理旧排程预览失败 chat_id=%s: %v", chatID, delErr)
}
}
// 2.3 Redis miss 时回落 MySQL 快照:
// 2.3.1 目的:即使 Redis TTL 过期,也能延续同会话微调语境;
// 2.3.2 回填:命中 DB 后尝试回填 Redis提高后续读取命中率
// 2.3.3 失败策略DB 读取异常只打日志,链路继续按“无历史快照”执行。
if previousPreview == nil && s.repo != nil {
snapshot, snapshotErr := s.repo.GetScheduleStateSnapshot(ctx, userID, chatID)
if snapshotErr != nil {
log.Printf("从 MySQL 读取排程快照失败 chat_id=%s: %v", chatID, snapshotErr)
} else if snapshot != nil {
previousPreview = snapshotToSchedulePlanPreviewCache(snapshot)
if s.cacheDAO != nil && previousPreview != nil {
if setErr := s.cacheDAO.SetSchedulePlanPreviewToCache(ctx, userID, chatID, previousPreview); setErr != nil {
log.Printf("回填排程预览缓存失败 chat_id=%s: %v", chatID, setErr)
}
}
}
}
// 3. 读取对话历史:先快后稳。
// 3.1 先查 Redis命中则避免回源 DB降低请求时延。
@@ -99,6 +116,7 @@ func (s *AgentService) runSchedulePlanFlow(
state.PreviousTaskClassIDs = append([]int(nil), previousPreview.TaskClassIDs...)
state.PreviousHybridEntries = cloneHybridEntries(previousPreview.HybridEntries)
state.PreviousAllocatedItems = cloneTaskClassItems(previousPreview.AllocatedItems)
state.PreviousCandidatePlans = cloneWeekSchedules(previousPreview.CandidatePlans)
}
finalState, runErr := scheduleplan.RunSchedulePlanGraph(ctx, scheduleplan.SchedulePlanGraphRunInput{
Model: selectedModel,