后端: 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永远只适合做选择题、判断题,不适合做开放创新题。
16 KiB
主动优化整套改造计划
1. 文档目的
本文档只回答一件事:这轮主动优化链路改完之后,整体会如何工作。
重点不放在实现细节,而放在以下 4 个问题:
- 哪些能力保留,哪些能力直接删除。
task_class、粗排、主动优化三者之间的职责如何重新划分。- 首次排程时,agent 的完整执行链路会变成什么样。
- 时间窗口过紧时,agent 应该如何自动放宽要求,避免陷入无意义重试。
2. 改造后的核心原则
2.1 LLM 只负责“语义认知优化”
这轮改造后的总原则是:
- 确定性算法负责“排得下、排得合法、排得别太离谱”。
- LLM 负责“学起来舒不舒服、搭配顺不顺、是否符合用户偏好”。
换句话说,LLM 不再负责:
- 全局负载均衡。
- 均匀铺开任务。
- 追逐空窗、碎片率、最大 gap 之类的统计指标。
- 为了把报表修漂亮而反复搬运任务。
LLM 保留的价值只有两类:
- 学科语义理解。
- 基于语义和偏好的认知微调。
2.2 主动优化从“统计修表”改成“认知微调”
改造完成后,主动优化不再问:
- 哪天更满。
- 哪天更空。
- 哪门课间隔是不是又多了 1 天。
- 空窗碎片率是不是还可以再低一点。
改造完成后,主动优化只问:
- 这一天切换是不是太碎。
- 两门课放在一起,认知上是不是太累。
- 连续学习块是不是太长。
- 当前安排是不是违背了用户偏好。
- 在当前时间窗口下,这个问题是不是值得继续修。
3. 工具去留
3.1 保留
3.1.1 analyze_health
保留,且继续作为主动优化的唯一总入口。
新职责:
- 汇总当前排程在认知节奏上的主要问题。
- 汇总当前排程和用户偏好的冲突。
- 判断当前是否还有足够可调整空间继续优化。
- 判断当前是否已经可以合理收口。
3.1.2 analyze_rhythm
保留,作为 analyze_health 的下钻工具。
新职责:
- 解释某一天为什么学起来别扭。
- 解释某几个任务为什么不适合连在一起。
- 解释当前切换多、连续块长、高强度相邻等问题落在哪些具体任务上。
3.1.3 现有点查工具
全部保留,尤其是:
query_rangequery_target_tasksquery_available_slotsget_task_info
原因很简单:
health/rhythm只负责指出问题和方向。- LLM 真正落到“挪哪个任务、往哪里挪”时,仍然必须依赖这些点查工具。
3.1.4 现有写工具
全部保留。
主动优化改的是“如何观察和决策”,不是“如何写入”。
但写工具在主动优化里的使用优先级要重排:
slack高时,允许move和swap一起参与小范围微调。slack低时,默认优先考虑swap,不优先考虑move。slack低时若使用swap,只允许交换属于不同task_class的任务。- 这样做的目的不是保守,而是用“跨类互换”天然保证类内顺序不被破坏。
3.2 删除
3.2.1 删除 analyze_load
原因:
- 负载均衡是确定性算法的职责。
- 它会强烈诱导 LLM 变成搬格子苦力。
- 它无法体现 LLM 真正有优势的学科语义判断。
3.2.2 删除 analyze_tolerance
原因:
- 容错本质上是粗排风格与窗口宽松度问题。
- 它不适合作为主动优化主链路的独立分析工具。
- 它容易继续把模型引向“留空窗/修空窗”的伪目标。
3.2.3 删除所有 gap/load/tolerance 驱动指标
以下指标全部退出主动优化链路:
max_gapavg_gapgap_std_devfragmentation_rateavg_gap_sizemax_gap_sizedays_without_bufferutilization_rateload_std_devload_rangebudget_progressdays_to_end
说明:
- 它们可以在未来作为统计观察数据重建。
- 但本轮改造后,它们不再参与主动优化决策,不再生成 issue,不再生成 next action。
4. task_class 改造后会怎样
4.1 新增 3 个语义字段
每个 task_class 新增以下字段:
subject_typedifficulty_levelcognitive_intensity
这 3 个字段只服务于一个目标:让后续排程和主动优化不再对着学科名裸猜。
4.2 写入时机
这 3 个字段不在排程时临时生成,而是在创建或更新 task_class 时就提前写好。
也就是说:
- 用户创建任务类。
- LLM 在任务类阶段补全这 3 个字段。
- 任务类一旦落库,后续粗排和主动优化都直接读取。
兜底策略:
- 老数据如果没有这 3 个字段,排程时允许临时现判一次。
- 现判完成后,应补写回
task_class,避免下次重复猜。
4.3 这 3 个字段后续如何被使用
粗排阶段:
- 可以作为轻量参考,但不是主驱动。
主动优化阶段:
analyze_health直接消费这 3 个字段。analyze_rhythm直接消费这 3 个字段。- LLM 在诊断“背靠背是否太累、连续块是否太长、某种切换是否合理”时,统一以这 3 个字段为事实基础。
5. 粗排算法改造后会怎样
5.1 粗排负责的事
改造后,粗排要提前吃掉原本不该交给 LLM 的工作。
粗排的职责固定为:
- 保证可行。
- 保证顺序合法。
- 保证基础分布别太离谱。
- 保证不要明显堆到少数几天。
- 保证不要把整段窗口排成毫无操作空间的死局。
5.2 粗排不负责的事
粗排不追求:
- 认知体验最优。
- 学科搭配最优。
- 用户偏好最优。
这些交给 LLM 后续做 1 到 2 轮小范围微调。
5.3 粗排后的预期结果
粗排完成后,产物应该是:
- 一个合法可执行的初稿。
- 一个从统计上看不难看,但未必最舒服的日程。
- 一个仍然留有少量可调整空间的底盘。
也就是说,粗排之后不需要“完美”,只需要“足够好,值得微调”。
6. analyze_health 改造后会怎样
6.1 定位
analyze_health 变成“认知健康总览”。
它不再是统计体检工具,而是 execute 阶段判断“要不要继续动、该往哪种认知方向动”的入口。
6.2 新职责
改造后它只看三件事:
- 当前认知节奏是否别扭。
- 当前安排是否违背用户偏好。
- 当前窗口是否还允许继续优化。
6.3 新输出口径
它输出的问题应该是这种风格:
- 某天高强度切换过多。
- 两门高强度课背靠背。
- 某天连续高强度学习块过长。
- 当前安排违背“早上别排硬课”之类的用户偏好。
- 当前可调整空间过低,剩余问题属于必要妥协。
它不再输出这种风格:
- 哪天负载更满。
- 最大空窗还有几天。
- 空窗碎片率还可以再压多少。
- 某一科是不是再均匀一点更漂亮。
6.4 新 can_close 含义
改造后,can_close 的语义要收紧为:
- 当前没有明显值得继续修的认知问题。
- 当前没有明显违背用户偏好的安排。
- 或者虽然还存在小问题,但当前
slack已低,继续优化收益不高。
也就是说,can_close 不再由统计指标主导,而由“是否还有高价值认知问题”主导。
7. analyze_rhythm 改造后会怎样
7.1 定位
analyze_rhythm 变成 analyze_health 的明细镜。
只有当 health 发现某类认知问题值得继续查时,才进一步调用 rhythm。
7.2 新职责
它要回答的不是“排得均不均”,而是:
- 哪一天切换太碎。
- 哪一段连续块太长。
- 哪几个任务挨在一起会特别累。
- 哪些切换虽然换科了,但其实仍属于同一种脑力模式。
7.3 新输出风格
它的输出重点应围绕:
- 日内切换次数。
- 连续学习块结构。
- 高强度相邻关系。
- 同类/异类学科切换关系。
- 某一天内部的认知压力分布。
它不再承担:
- 跨天 gap 追踪。
- 学科分散度统计优化。
- 预算推进告警。
8. 新增 slack 后会怎样
8.1 为什么必须加 slack
有些用户给的时间窗口非常紧。
这时“高强度背靠背”不一定是错误,而可能是当前窗口下的必要代价。
如果没有 slack 概念,agent 会误以为:
- 这是可修的问题。
- 我应该继续搬。
- 继续搬总能更好。
然后就进入无意义重试。
8.2 slack 的职责
slack 不负责决定“舒服不舒服”,只负责决定“还有没有优化余地”。
也就是说,它是健康分析里的第二层判断:
- 有问题,不代表值得继续修。
- 值得继续修,还要看当前有没有空间修。
8.3 slack 接入后的行为
改造后:
- 若
slack高,按正常标准检查认知问题。 - 若
slack中,允许小问题存在,但仍可做 1 次小范围微调。 - 若
slack低,自动放宽要求,允许必要的背靠背、较长连续块、略多切换。 - 若
slack低但仍存在明显可改善的认知问题,优先尝试一次低成本swap,而不是优先尝试move。 - 这个
swap必须限定为“只交换不同task_class的任务”,从而避免打乱任一类内部顺序。 - 若一次
swap后没有明显改善,则倾向收口,不进入连续搬运。
8.4 slack 带来的收口变化
改造后,agent 不会再因为下面这类场景反复挣扎:
- 时间太紧,不得不连着上两门硬课。
- 可动任务几乎都被前驱后继夹死。
- 当前再动只会拆东墙补西墙。
这时 analyze_health 应直接给出结论:
- 当前仍有认知妥协点。
- 但由于可调整空间有限,已属于合理结果。
- 可以收口,或只在用户明确要求时继续深挖。
9. 改造后的首次排程完整链路
这是你最关心的部分:改完以后,首次排程到底怎么跑。
9.1 第 0 步:任务类先带语义字段
在真正排程前,相关 task_class 已经具备:
subject_typedifficulty_levelcognitive_intensity
如果缺失,先补齐再进入完整主动优化链路。
9.2 第 1 步:确定性粗排先出底盘
系统先用确定性算法完成一版粗排。
这一步的结果要求是:
- 可排下。
- 顺序合法。
- 分布不难看。
- 还留有一点可调整空间。
9.3 第 2 步:进入 analyze_health
粗排完成后,不再先看 load,不再先看 gap,而是直接进入 analyze_health。
这一步会判断:
- 当前有哪些高价值认知问题。
- 当前是否存在用户偏好冲突。
- 当前
slack高不高。 - 当前是否值得继续动。
9.4 第 3 步:必要时下钻 analyze_rhythm
只有当 health 发现值得修的问题时,LLM 才进一步调用 analyze_rhythm。
这一步的作用是:
- 把问题定位到某一天、某几个任务、某种相邻关系。
- 给 LLM 读写工具调用提供更明确的认知方向。
9.5 第 4 步:LLM 用旧点查工具锁定目标
接下来 LLM 不会根据 health/rhythm 直接拍脑袋写入。
它仍然要走:
query_rangequery_target_tasksquery_available_slotsget_task_info
也就是说,新的分析工具负责“告诉它为什么动、朝哪动”,旧点查工具负责“告诉它具体怎么动”。
当 slack 低时,这一步的目标还会进一步收窄为:
- 先找有没有值得做的一次性交换机会。
- 优先找跨
task_class的互换对象。 - 只有在没有合适
swap,且单步move的收益明显高于风险时,才考虑move。
9.6 第 5 步:LLM 做 1 到 2 次小范围微调
改造后,主动优化默认只做小范围微调,不做全盘翻修。
默认目标是:
- 消除最明显的认知别扭点。
- 避免新问题比旧问题更重。
- 不为了报表漂亮而继续搬运。
这里再补一条强规则:
slack高时,可以正常比较move与swap。slack低时,优先考虑一次跨task_class的swap来调整不同科目间的相对顺序。slack低时,不鼓励进入多步move链路。swap的价值在于:它更像“整理现有坑位里的学科顺序”,而不是“重新开一轮搬家”。
9.7 第 6 步:再做一次 analyze_health
写操作后再次进入 analyze_health。
这一步不是看统计报表有没有更均匀,而是看:
- 主要认知问题是否缓解。
- 用户偏好冲突是否减少。
- 当前
slack是否已不支持继续动。 - 是否可以收口。
9.8 第 7 步:合理收口
最终存在三种收口方式:
- 问题已明显改善,可以正常收口。
- 还存在小问题,但
slack过低,按“合理妥协”收口。 - 用户明确还不满意,再继续下一轮。
其中第 2 种收口还要补一层判断:
- 不是一看到
slack低就立刻停手。 - 而是先看是否存在一次低成本、跨
task_class的swap机会。 - 若存在且收益明确,可先做这一次整理式调整。
- 若不存在,或做完后仍无明显改善,再按“合理妥协”收口。
10. 改造后的局部调整链路
改造后,不是所有用户请求都要走完整主动优化链路。
10.1 默认仍走旧链路
用户如果只是说:
- 把这个任务挪一下。
- 这节课换一天。
- 给我把这个排到周末。
这类请求默认继续走旧点查 + 旧写工具链路。
原因:
- 这是局部执行问题。
- 不值得每次都拉起
health/rhythm做一轮体检。
10.2 只有两类情况再启动主动优化分析
- 首次排程。
- 用户明确表达认知感受或结构性问题。
例如:
- “切换太多了,心累。”
- “这些硬课连着看着就难受。”
- “帮我整体调顺一点。”
11. 改造后的最终表现
改完以后,这条链路的预期表现应该是:
- 用户创建任务类时,学科语义先被沉淀下来。
- 粗排算法先给出一个合法且分布不难看的初稿。
- 主动优化不再围着负载、空窗、gap 打转。
analyze_health只关心认知体验、偏好冲突、可调整空间。analyze_rhythm只负责解释具体哪段学起来别扭。- LLM 只做 1 到 2 次高价值认知微调,不再做长链路苦力搬运。
- 时间窗口很紧时,agent 会承认“这是必要妥协”,而不是继续死磕。
一句话总结:
改造后,这套链路不再追求“把报表修漂亮”,而是追求“把这份日程修得更像人能学下去”。
12. 实施顺序
按以下顺序落地:
- 先改
task_class,补 3 个语义字段及写入链路。 - 再删
analyze_load、analyze_tolerance及相关主链路接入。 - 再重写
analyze_health的职责、指标和收口口径。 - 再重写
analyze_rhythm的职责和输出结构。 - 再补
slack及其自动放宽规则。 - 最后改 execute prompt 和链路收口逻辑。
这样做的原因是:
- 先有语义数据,分析工具才不至于空转。
- 先把旧统计驱动砍掉,execute 才不会继续被错误方向牵着跑。
- 最后再调 prompt,才不会变成给旧结构打补丁。
13. 本轮验收口径
如果改造成功,至少应满足以下表现:
- 首次排程时,agent 不再为了负载均匀或空窗漂亮反复搬任务。
- 日志中的主动优化理由,主要变成认知体验和偏好,而不是统计指标。
- 当时间很紧时,agent 会主动接受必要妥协,不再死循环。
- 当用户只是提局部挪动需求时,不会动辄拉起全局体检。
- 主动优化完成后的结果,解释口径更像“为什么这样学更顺”,而不是“哪些数字变好看了”。