自进化系统
传统 AI 应用发布后就固定了,除非开发者手动更新。Profy 的专家不同:它们从真实使用中提出改进,经过一道代码强制的评分门禁,再由创作者决定是否采纳。 这一页讲的是系统怎么运转。如果你是创作者、关心的是「我该怎么读一条建议」,请看 专家进化。先划边界:这不是 RSI
「递归自我改进」(RSI)指的是系统改进造模型的过程本身,从而递归地提升自身能力。Profy 做的不是这件事。
Profy 改的是「专家用什么方法做事」这份文档,不是「专家用什么大脑思考」。这个限制是设计选择而不是能力不足——它把改动限制在一个可以被完整审阅的对象上。
三层进化
系统里有三条独立的后台链路,名字容易混,实际管的事完全不同:
本页后续只讲第三层。
计数器的存储决策
三层用了两种不同的存储,原因值得说明:
进程内字典有
_COUNTER_CAP = 10,000 的上限,超出时淘汰最旧会话以限制内存。Redis 不可用时进化计数器降级到进程内字典——尽力而为,重启清零。
一次进化调用的完整链路
1
Core 侧筛选候选
调度器按冷却期(
EVOLUTION_COOLDOWN_HOURS,默认 24h)、失败退避(EVOLUTION_FAILURE_BACKOFF_HOURS,默认 6h)、批量上限(EVOLUTION_BATCH_SIZE,默认 10)筛出可进化的专家。2
积压检查
待处理建议数达到
EVOLUTION_PENDING_MAX(默认 5)的专家直接跳过,不发起调用。这是最常见的「为什么没有新建议」的原因。3
组装载荷
取最近
EVOLUTION_RECENT_SESSION_LIMIT(默认 5)个会话的 EVOLUTION_RECENT_MESSAGE_LIMIT(默认 40)条消息,加上专家的技能列表、persona / soul / agent 内容,以及 run_stats。技能列表里每一项的 scope 是必填的:runtime 的 inject_user_skills 会静默跳过 scope 不是 user / expert 的条目(只留一条警告日志)。4
内部调用 agent-runtime
POST /api/agent/evolution,X-Internal-Secret 鉴权,is_internal_invoke 恒为 true(调用方不可配置)。超时 EVOLUTION_TIMEOUT_SEC,默认 900 秒,由 asyncio.timeout 实际强制。5
进化模式运行
profy-evolution 插件被激活且 exclusive: true——其他插件全部不加载。只有三个工具可用。6
提交建议
模型调
evolution_log,通过双棘轮门禁后写入 expert_evolution_log,状态为待处理。每次调用最多一条。7
创作者决策
建议出现在 Studio 进化面板。采纳走事务,忽略只改状态。
900 秒超时不是随手定的
默认值对齐实测:Stage 4 的进化运行耗时 721–1003 秒。取 900 秒意味着大部分运行能跑完,而失控的会被切断。可配置范围 30–1800 秒。进化模式的隔离
这是安全边界的核心。进化跑在一个排他的内部调用里:exclusive: true 的效果是:进化模式下其他所有插件都不加载。这不是靠提示词请求模型「不要用别的工具」,而是那些工具根本不在工具列表里。
唯一写入点
evolution_log 是进化模式下唯一能改变外部状态的工具,而它能做的只有一件事:写一条待审核的建议。它不能直接改技能——改技能发生在创作者点「采纳」之后的 Core 侧事务里。
这个结构让「模型能做什么」和「什么会真的生效」被一道人工闸门彻底分开。
递归守卫
进化模式不产生任何面向用户的输出,也不会触发新的后台复盘——否则一次进化会引发下一次进化。is_internal_invoke 既是激活条件,也是这条守卫的判据。
双棘轮门禁
10 个维度分两组,质量组权重合计 0.70、效率组 0.30。 接受条件(必须同时成立):- 质量组加权分 不下降(after ≥ before)
- 效率组加权分 严格上升(after > before)
context_footprint 的打分曲线,完整写在 专家进化 页。这里只讲设计动机。
为什么不是「总分要涨」
单一加权总分的门禁存在结构性漏洞:任何一维都能被另一维买单。「质量 +15、效率 −10」这样的改动在总分口径下轻松通过,而这恰恰是最典型的退化形态——文档越写越厚越”全面”,每次运行更贵,但每项质量指标都在涨。 分组 + 双条件把这条路堵死。为什么必须有一维由代码算
如果 10 维全由模型自评,那么门禁的判据与被判据的对象同源,它想过就能过。context_footprint 从技能文档字符数直接算出(≤3,000 → 100,≥24,000 → 0,线性),模型传什么值都被丢弃。它是这条链上唯一模型无法自证的锚点。权重虽只有 0.08,但因为效率组只有三维且必须严格上升,文档大幅膨胀时这一维的下跌通常足以让整组无法上升。
阈值有实测依据:Stage 4 种子技能 429 字符,进化后 12,109 字符;24,000 约为其两倍。
这两条设计回应的是同一个问题:门禁的判据不能由它守护的对象提供。第一条防的是维度之间互相提供借口,第二条防的是模型给自己出成绩单。当前关于「如何设计不被 reward hacking 的评测」的讨论里,大多数方案在这两点上至少缺一条。
run_stats:实测成本作为地面真值
评分表本身仍然依赖模型判断(除context_footprint 外的 9 维)。为了让判断不悬空,进化提示词里会带一个 <run_stats> 块,列出过去最多 20 次运行的实测成本:token 数、LLM 轮次、工具调用次数、当时的技能文档长度、是否成功。
判定规则是硬性的:
- 技能变长后 token 涨了 → 上一轮方向错了,这一轮必须压缩
- token 降了且成功率保持 → 方向对,继续
- 永远不要拿理论反驳 run_stats
run_stats 是严格白名单 Pydantic 模型且逐字段有上界(total_tokens ≤ 10,000,000、tool_calls ≤ 500、skill_version_note ≤ 120 字符等),因为它会被逐字注入提示词——不校验的话既撑上下文,也给了夹带指令的口子。
采纳的事务性
创作者点「采纳」后,Core 侧:1
结构校验
validateSkillImprovementContent 不通过返回 400。2
归属校验
非创作者返回 403。
3
定位技能
按
expertIdentifier + 共享作用域 user id + 技能名查 expert_skill。找不到返回 404——说明建议生成后技能被删了。4
单事务三写
更新
skillMdContent → 标记建议 accepted → expert.evolutionCount + 1。三者同事务,杜绝「技能改了但计数没动」的半成品状态。skill_improvement 类型(如 knowledge_update)走「仅改状态 + 计数」路径,不写技能。
「忽略」只改建议状态,永远不碰 expert_skills。
与传统 ML 的对比
关键差别不在效果而在可审查性:你能读到将要生效的每一个字,并在它生效前否决。
相关页面
专家进化(创作者视角)
完整评分表、阈值表与怎么读一条建议
时态记忆
与进化正交的记忆管线
Agent Runtime
进化调用运行在什么之上
技能
技能三路归属:builtin / user / expert
核对日期 2026-08-11。来源:
services/agent-runtime/src/plugins/builtin/evolution/{plugin.json,tools/evolution_log.py,skills/evolution/SKILL.md,prompts/EVOLUTION.md,hooks/background_review.py}、services/agent-runtime/src/models/evolution.py、services/core/src/db/service/expert-evolution.ts、services/core/src/config/env.ts。
