副题:代码实现在 crates/skilllite-evolution 模块;调度、统计、冷却与审计类型都和 SQLite 里的决策记录强绑定——这层,意味着不能把「没改文件」当成 bug,也不会把「开了进化」误解成「一定产出 diff」,最终还是由对话过程的数据质量以及模型能力决定。

写文章也是为了复盘和记录skilllite开发过程中的架构思路和思考。


一、为什么要把「进化」拆成数据问题,而不是 UI 开关问题

很多助手产品把「自动优化」做成黑盒:用户只知道「开了」。SkillLite 选择把学习样本落在本地 decisions里——每条对应一次任务型对话回合,带上工具次数、成败、可选的 tool_sequence_key、重规划次数、反馈等。
进化引擎读的是这张表在最近 N 天窗口里的统计,再决定本轮要不要提案、开哪几条进化的「臂」、写不写盘。

这样做的好处很朴素:

  1. 可解释:时间线、NoScope、SkippedBusy 都能对上「样本够不够 / 锁没占住」。
  2. 可回放evolution_log 记 scope、提案与结果,不等于替代 decisions,但能把「这轮发生了什么」串起来。
  3. 可治理:调阈值本质是调「统计量 → 行为」的映射,而不是调一句营销文案。

二、五句话跑通一整条链路(读完能给别人讲清楚)

  1. 聊天里每次任务在本地 DB 记一条 decisions
  2. 闹钟或「最近折腾够了」(A9 生长调度等)时,系统判断要不要 spawn skilllite evolution run
  3. 真正跑的时候:先看 「有没有值得做的提案」;没有就记 NoScope 结束。
  4. 有提案且允许执行:可能改 提示词 / 记忆 / 技能(Skill) 里你打开的那几臂。
  5. 新 Skill 往往先进 _evolved/_pending,需要你再确认——不是静默覆盖全仓库技能树

三、三臂各自改什么、吃什么数据(与实现对齐的心智模型)

一轮 run_evolution 里,prompts / memory / skills 可以并行开多臂,每一臂有自己的 learner 与落盘位置(以下为「典型」路径,具体以代码为准):

方面 常见产出 / 落盘 主要输入
规划提示(规则 + 示例) chat/prompts/rules.jsonchat/prompts/examples.json decisions 中成功/失败摘要、高工具样本,经 L1/L2/L3 类门禁后合并
记忆 memory/evolution/ 下按维度分卷(如 YYYY-MM.md 近期窗口内的决策抽取;偏可检索事实,与「何时做何事的规则句」分工
技能 chat/skills/_evolved/(含 _pending/ 重复成功模式、失败模式、轨迹等;还有更重校验,故常见「臂开了但本轮无落盘」

另外还有 可选第四臂:外源学习(默认关闭,需显式环境条件),避免与「本地 decisions 驱动」混谈。


四、Passive / Active / 协调器:谁在「拍板」

  • Passive(should_evolve_impl:看窗口内的 meaningful(够「有工具摩擦」的条数)failuresreplansrepeated_patterns(高成功率重复模式组数) 等;各臂独立判断是否该开。
  • Active:在「稳定成功」的未进化决策达到门槛后,用低风险提案在一维上推进;与 EvolutionMode 组合相关——若你读到 EvolutionMode::All 下优先只开 memory 的分支,以 scope.rs 为准
  • 协调器:在 Passive / Active 两条提案里选一条执行;force=true 可绕过被动侧冷却/阈值,但 learner 仍可能因无样本或门禁而不写文件

产品预期(避免误解):「开了多臂」≠「一定有 diff」。LLM 认为不必改、查询为空、测试未过,都会出现「本轮无新规则/技能」——助手侧文案会刻意弱化,避免用户以为系统在摸鱼。


五、审计类型:为什么要把「空跑」从 evolution_run 里拆出来

这是一个很关键的工程语义

  • evolution_run:本轮产生了至少一条 changelog 类变更(有「材料」)。它会推进被动冷却里「距上次有产出跑」的时钟,并参与 A9 里「多久没真正进化过」的判断。
  • evolution_run_noop:已进入 learner,但合并结果为空。它不应假装成「刚完成一次有产出进化」——因此不推进上述冷却时钟,但仍可计入每日上限(防止无意义子进程被刷爆)。
  • evolution_run_outcome未进入完整执行(NoScope、Busy 等)的调度结果;与「跑满一轮」的计数语义不同。

把 noop 拆清之后:时间线仍有记录冷却只认真有落盘的轮次,用户也不会被「明明没改文件却在冷却」误导。


六、一张总览图(把「表 → 调度 → learner → 落盘」串起来)

排队/拒绝

执行

聊天与工具执行

decisions 表

到点或信号够?

不 spawn 完整 run

run_evolution

有提案?

NoScope 记日志

协调器执行?

本轮结束

prompts / memory / skills

写 changelog 或 noop 审计


七、和 spec/capability-gap-evolution.md 不是一回事(防概念串台)

仓库里还有一份 spec/capability-gap-evolution.md:讲的是 contributor 在本 git 仓库里写小脚本、把重复劳动晋升到 scripts/ 或 Skill 的工程习惯不是产品运行时「自动进化引擎」的配置模型。
读进化机制时,把这两层分开,讨论会干净很多。


八、三件事

  1. 对照 crates/skilllite-evolution/src/scope.rsshould_evolve_impl:把 meaningful / repeated_patterns 的 SQL 语义和自己业务里的「什么叫重复」对齐。
  2. 看日志类型:区分 material / noop / outcome,再解释「为什么这轮没改文件」。
  3. 修改阈值:改阈值时同步想清楚——动的是「开不开臂」还是 skill_synth/query.rs 里「喂给 LLM 的模式列表」(二者查询并不完全相同)。

版权声明:本文描述的是 SkillLite 开源仓库在撰写时的实现思路;转载请注明项目与文档出处。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐