本文来自 KAIST,提出 Self-EvolveRec,核心创新是将"方向性反馈(Directional Feedback)"引入 LLM 驱动的推荐代码进化框架。区别于 AlphaEvolve / DeepEvolve 等仅依赖标量指标(NDCG、HR)的方法,Self-EvolveRec 用两个工具提供更丰富的反馈信号:User Simulator(定性批评)和 Model Diagnosis Tool(定量诊断),并引入"诊断工具-模型协同进化"确保诊断准则随模型架构同步更新。
1.1 研究脉络
推荐系统的自动化优化经历了三个阶段:
固定搜索空间
离散算子组合
开放程序空间
标量指标引导
开放程序空间
方向性反馈引导
1.2 现有方法的关键缺陷
AlphaEvolve、DeepEvolve 等框架仅依赖 NDCG、Hit Ratio 等标量指标。这些数字只能告诉你"推荐效果变差了",但无法解释为什么变差:是流行度偏差?类别多样性不足?还是无法捕捉短期兴趣?
没有方向性,LLM 只能做无目的的试错搜索(trial-and-error),偶尔撞到好的方案,但无法系统性地定位和修复问题。
1.3 三大核心痛点
P1:NAS 搜索空间封闭
NAS 只能在人工预定义的算子池(固定层类型、激活函数等)中组合,无法优化 loss 函数、负采样策略等非架构组件。
P2:标量指标缺乏诊断信息
NDCG 下降 0.01 不告诉你根因:是 embedding collapse?类别不平衡?还是时序信息丢失?LLM 无法据此做出有针对性的修改。
P3:静态诊断工具过时
随着模型架构不断进化,固定的诊断逻辑(如检测 embedding collapse 的方法)可能与新架构不兼容,产生错误的诊断信号。
Self-EvolveRec 的对策
① User Simulator 提供定性用户反馈,解释失败根因
② Model Diagnosis Tool 做定量结构验证,交叉验证
③ 诊断工具与模型架构同步进化
2.1 系统总览
Self-EvolveRec 是一个迭代进化框架,核心是在每轮迭代中产生"方向性反馈"来指导 LLM 改写推荐代码:
问题形式化
给定种子代码库 $\mathcal{B}^{(0)}$(含推荐模型架构、数据处理、优化循环),目标是在 $T$ 次迭代内找到最优代码库 $\mathcal{B}^*$:
- $\mathcal{B} \in \mathbb{S}$:开放程序空间中的任意代码库
- $\mathcal{M}$:评估指标(如 NDCG@5、HR@5)
- $f_\mathcal{B}$:代码库 $\mathcal{B}$ 定义的推荐模型
- $\theta^*_\mathcal{B}$:内层优化得到的最优模型参数
- $\mathcal{E}_{train}, \mathcal{E}_{val}$:训练集和验证集
- $\mathcal{X}$:物品侧信息(类别、标题、价格等)
这是一个双层优化问题:外层优化代码库(离散、开放),内层优化模型参数(连续、梯度)。
2.2 User Simulator:定性用户批评
User Simulator(SIM)让 LLM 扮演具有不同特征的虚拟用户,对推荐列表给出自然语言批评,而非只看数字。
用户 Persona 构建
每个虚拟用户 $u$ 的 Persona $\mathcal{T}_u$ 由三个社会心理学特征构成:
Activity(活跃度)
用交互历史长度 $|\mathcal{H}_u|$ 量化。长 → HIGH(频繁互动用户),短 → LOW(偶尔用户)。
Conformity(从众性)
用用户打分与全局平均打分的偏差量化。偏差大 → LOW(独特口味),接近均值 → HIGH(追随主流)。
Diversity(多样性)
用交互集合中唯一类别数量量化。类别多 → HIGH(兴趣广泛),类别少 → LOW(专注特定领域)。
量化→离散化→自然语言
用分位数阈值将数值分成 LOW / MID / HIGH 三档,映射到预设的自然语言描述(如 "Activity (HIGH): Frequently interacts…")。
两步反馈生成
- 1个人评估(Individual Assessment):对每个采样用户 $u$,基于其 Persona $\mathcal{T}_u$ 和历史 $\mathcal{H}_u$,评估推荐列表 $\mathcal{A}_u$,生成个人反馈报告 $R_u$。
- 2聚合(Aggregation):将所有采样用户 $\mathcal{U}_{sample}$ 的个人报告汇总为统一的用户反馈报告 $\mathcal{R}_{SIM}$,消除个体噪声。
假设某用户 Persona 为:Activity=LOW, Conformity=HIGH, Diversity=LOW(偶尔互动、追随主流、专注电子产品)。
模型推荐了 [手机壳、耳机、手机壳、SD卡、充电宝]。
SIM 生成批评:"I'm looking for reliable electronics accessories within a modest budget. The list is repetitive — two phone cases is redundant. I'd prefer more variety within the accessories category rather than duplicate items."
这一反馈明确指出了类别重复问题,远比 NDCG 下降 0.02 更有操作性。LLM 据此制定修改策略:引入多样性约束或 category-aware 负采样。
2.3 Model Diagnosis Tool:定量结构验证
Model Diagnosis Tool(DIAG)直接访问模型参数 $\theta$ 和数据加载器,用探针(probe)检测无法从推荐列表表面看出来的结构性缺陷。
初始 DIAG 包含两个基础探针:
探针 1:Embedding Collapse(表示退化)
计算采样 item embedding 之间的均值成对余弦相似度。如果所有 embedding 聚集在一个狭小子空间,相似度会异常高——这意味着模型失去了区分不同物品的能力,即使推荐列表的 NDCG 可能还没明显下降。
探针 2:Ranking Margin(排序边际)
- $s(u, v)$:模型预测的用户 $u$ 对真实正样本 $v$ 的打分(logit)
- $s(u, v')$:用户 $u$ 对随机负样本 $v'$ 的打分
- $\Delta_{u,v}$:单个正负对的排序边际,越大说明模型越能区分正负样本
- $\bar{\Delta}$:全局平均边际,低值或负值 → 模型严重失去辨别力
DIAG 还会定位边际极低的样本,统计其共同属性(如某些特定类别 "Computers" 的物品排序边际特别低),从而给出精确的失败模式定位。
两者缺一不可:
- SIM 的局限:只能看到推荐列表表面,无法检测 embedding collapse 这类内部结构问题;且是 LLM 模拟,存在主观偏差。
- DIAG 的局限:提供数值信号但缺乏语义解释,且静态探针可能不适配新架构。
- 结合:SIM 指出"推荐显得重复",DIAG 用 embedding 相似度计算确认"确实存在 collapse",两者互相验证,给出可靠的根因分析。
SIM 说:「I'm bored — the recommendations all feel the same, just different brands of headphones.」
DIAG 检测:item embedding 的均值余弦相似度 = 0.87(正常应 < 0.3),ranking margin 中"Electronics"类别物品普遍 Δ < 0.05。
诊断报告 $\mathcal{R}_{DIAG}$:「严重 Embedding Collapse,表示空间退化;Electronics 类目物品区分度极低,模型无法区分该类目内不同物品。」
LLM 制定改进方案:引入 Category-Aware Hard Negative Sampling,让负样本优先从同类目物品中采样,强迫模型学习细粒度区分。
2.4 四阶段进化流程
每次迭代维护一个进化存档 $\mathcal{P}^{(t)}$(记录所有历史代码库和反馈),从中采样父代码库 $\mathcal{B}_{parent}$,然后执行四个阶段:
-
1
多维评估(Multi-faceted Evaluation)
同时获取:标量指标 $score(\mathcal{B}_{parent})$、用户反馈 $\mathcal{R}_{SIM}$、诊断报告 $\mathcal{R}_{DIAG}$。三个维度共同构成下一步规划的输入。 -
2
反馈感知规划 & 检索(Feedback-Aware Planning & Retrieval)
LLM 作为规划者,基于 $\mathcal{R}_{SIM}$、$\mathcal{R}_{DIAG}$ 和历史存档 $\mathcal{P}^{(t)}$,生成有针对性的 arXiv 检索查询 $\mathcal{Q}$(如"检索缓解类别不匹配的方法"),而非泛化的知识检索。检索到文献 $\mathcal{K}$ 后,整合为结构化开发报告 $\mathcal{R}_{Dev}$。 -
3
代码进化(Code Evolution)
LLM 按照 $\mathcal{R}_{Dev}$ 实施代码修改,生成新代码库 $\mathcal{B}^{(t+1)}$,加入进化存档。 -
4
诊断工具协同进化(Diagnosis Tool Co-Evolution)
见 2.5 节。
DeepEvolve(普通 RAG):每轮都检索"推荐系统最新方法",获得的是通用知识,未必与当前失败模式相关。
Self-EvolveRec(反馈感知规划):SIM 指出"类别单一",DIAG 确认"Electronics 区分度低",规划阶段生成精确查询"methods to improve within-category item discrimination for electronics recommendations",检索到 Category-Aware Hard Negative Sampling 方法,直接解决已识别的失败模式。
结果:有目标的修改 vs 无目标的试错。
2.5 诊断工具-模型协同进化
随着推荐模型架构不断进化(引入新 loss 函数、新层结构等),静态的 DIAG 会出现两类问题:
- 结构不兼容:原有探针依赖旧架构的特定组件(如某个 embedding 层),新架构中该组件不存在或接口变了。
- 无法量化新出现的定性问题:SIM 提出了新类型的批评(如"推荐太无聊"),但 DIAG 没有对应的指标来验证"多样性"是否真的不足。
协同进化的触发流程(Phase 4):
- A结构分析:扫描新代码库 $\mathcal{B}^{(t+1)}$ 与原 DIAG,生成结构分析报告 $\mathcal{R}_{Analyze}$(列出新增模块、修改的 loss 函数等)。
- BDIAG 规划检索:结合 $\mathcal{R}_{SIM}$(用户新抱怨)和 $\mathcal{R}_{Analyze}$(结构变化),生成 DIAG 专用检索查询,获取对应诊断方法文献。
- CDIAG 代码更新:生成新的诊断工具 $DIAG^{(t+1)}$,包含针对新架构的兼容性探针,以及量化 SIM 新质性反馈的专属指标。
第 t 轮:模型是带标准 self-attention 的 SASRec,DIAG 中有检测时序敏感性的探针。
第 t+1 轮:LLM 引入了"指数衰减模块(Exponential Decay Module)"给近期交互更高权重。旧 DIAG 的时序敏感性探针与新模块接口不兼容。
协同进化后的 $DIAG^{(t+1)}$:新增"Swap Sensitivity"探针——将交互序列最后两个物品对调,测量排序变化幅度。正常模型对位置高度敏感(Δ 大),若 Δ ≈ 0 说明指数衰减模块失效。
实验验证:故意破坏指数衰减模块后,协同进化的 DIAG 正确诊断为"Order-insensitive",而静态 DIAG 对此一无所知。
实验设置
数据集:4 个数据集(Amazon CDs、Electronics、Office,MovieLens)
评估协议:leave-last-out,每个测试物品配 99 个负样本
基线:NAS 类(AutoFIS, NASRec),LLM 进化类(AlphaEvolve, DeepEvolve)
种子推荐器:NCF(MF)、NGCF(图)、SASRec(序列)、MoRec(多模态)
LLM:GPT-5-mini(规划检索)+ GPT-5(编码 Agent)
3.1 主要性能对比(部分数据)
| 数据集 | 指标 | AutoFIS | NASRec | SASRec Seed | AlphaEvolve | DeepEvolve | Ours |
|---|---|---|---|---|---|---|---|
| CDs | NDCG@5 | 0.2077 | 0.2026 | 0.3559 | 0.3528 | 0.3610 | 0.3865 |
| CDs | HR@5 | 0.3040 | 0.2989 | 0.4676 | 0.4623 | 0.4870 | 0.5274 |
| Electronics | NDCG@5 | 0.1753 | 0.1706 | 0.2325 | 0.2063 | 0.2508 | 0.2600 |
| Electronics | HR@5 | 0.2456 | 0.2444 | 0.3208 | 0.2891 | 0.3427 | 0.3591 |
| Office | NDCG@5 | 0.1714 | 0.1377 | 0.1799 | 0.1939 | 0.1816 | 0.2329 |
| MovieLens | NDCG@5 | 0.1369 | 0.2916 | 0.5667 | 0.5583 | 0.5722 | 0.5765 |
完整表格见论文 Table 1(涵盖 4 种种子推荐器 × 4 数据集 × 2 指标)。Self-EvolveRec 在所有组合下均排名第一。AlphaEvolve/DeepEvolve 在部分设置下甚至低于种子模型(无方向性反馈导致退化)。
3.2 用户满意度评估
除标量指标外,用 Agent4Rec 和 PUB 两个用户模拟框架评估三个满意度指标:
- View(物品查看率):用户实际点击查看的物品占比
- Satisfy(综合满意度评分,1-10)
- Depth(探索深度):用户在终止会话前翻看的页面数
结果:Self-EvolveRec 在所有满意度指标上均最优,且 Satisfaction 和 Depth 的提升幅度显著大于标量指标的提升——说明方向性反馈不只优化了数字,而是真实提升了用户体验。
3.3 消融实验(Seed: SASRec)
| 配置 | SIM | DIAG | 协同进化 | CDs NDCG@5 | CDs HR@5 | Elec NDCG@5 |
|---|---|---|---|---|---|---|
| (1) DeepEvolve 基线 | ✗ | ✗ | ✗ | 0.3610 | 0.4870 | 0.2508 |
| (2) +SIM | ✓ | ✗ | ✗ | 0.3751 | 0.5102 | 0.2573 |
| (3) +DIAG(静态) | ✗ | ✓ | ✗ | 0.3676 | 0.4791 | 0.2515 |
| (4) +SIM+DIAG(静态) | ✓ | ✓ | ✗ | 0.3789 | 0.5164 | 0.2584 |
| (5) +DIAG(协同进化) | ✗ | ✓ | ✓ | 0.3727 | 0.5014 | 0.2532 |
| (6) 完整 Self-EvolveRec | ✓ | ✓ | ✓ | 0.3865 | 0.5274 | 0.2600 |
关键结论:
- SIM 单独引入(行2)比 DIAG 单独引入(行3)增益更大,说明定性反馈是主要驱动力
- 行3 vs 行5:仅添加静态 DIAG 效果有限,协同进化是必要的(+0.05 NDCG)
- 行4(SIM+静态DIAG)优于行5(无SIM+协同DIAG),说明定性反馈比动态诊断更重要,但两者结合才能达到最优
3.4 Case Study:进化轨迹对比
Self-EvolveRec 的结构性进化
Iter 0→1:SIM 指出"Ignores Subgenre",DIAG 检测到"High Embedding Collapse"。
代码修改:引入"Category-Aware Hard Negatives"和"Popularity-annealed Weighting"。
效果:HR: 0.4676 → 0.5138(+9.9%)
每步改进均有明确的失败根因支撑,因果链清晰。
AlphaEvolve / DeepEvolve 的困境
AlphaEvolve:Iter 3 错误合并 BCE+BPR 导致性能骤降,Iter 7 才撤回;全程未超过初始种子性能。
DeepEvolve:长期停留在低性能区(HR@5: 0.05-0.25),Iter 15 才借助 RAG 找到一个好模块。
无方向性反馈 → 搜索过程随机 → 大量迭代浪费在无效探索上。
极端初始化场景
从完全随机的推荐器出发(NDCG@5 = 0.0312),Self-EvolveRec 在 Iter 8(CDs)达到峰值 NDCG@5 = 0.3883,显著快于 AlphaEvolve(Iter 15)和 DeepEvolve(Iter 13)。方向性反馈让每一步改进都有目标,避免了长期在无效区域徘徊。
从 NCF+NGCF+SASRec 集成模型出发(NDCG = 0.3946),Self-EvolveRec 进一步提升到 0.4105。而 AlphaEvolve 在此设置下直接 FAIL(性能退化),DeepEvolve 也无法有效导航复杂集成架构的搜索空间。
4.1 核心创新价值
将推荐优化从"标量数字驱动的随机搜索"升级为"有根因分析的定向修复",这个范式转换是正确且必要的。推荐系统的失败确实是多维的,NDCG 无法承载这种复杂性。
大多数自进化系统只进化模型,却忽视了评估工具本身也需要进化。固定的诊断标准在动态进化的架构下必然失效,这个洞察非常深刻。
用 NDCG 优化不等于用户真的满意。SIM 让进化过程直接以"用户是否满意"为目标,实验数据也证实满意度提升幅度优于 NDCG 提升幅度,说明真的捕捉到了 NDCG 遗漏的维度。
4.2 局限与不足
每轮迭代需要:训练新模型(Θ hours)+ SIM 评估(采样用户 × LLM 调用)+ DIAG 运行 + 协同进化代码生成。论文自己也承认计算开销是未来要解决的主要问题。
虽然 SIM 提供了更丰富的信号,但它本质上是 LLM 扮演虚拟用户,存在幻觉和主观偏差的风险。论文通过 DIAG 交叉验证来缓解,但无法完全消除。
用 Activity、Conformity、Diversity 三个特征描述用户行为是简化的,现实中用户行为远比这复杂。论文提到可以替换为 Big Five 等更丰富的心理学特征,但未做系统实验。
4.3 与 Self-Evolving RecSys(Google/YouTube)的对比
Google/YouTube(工业部署)
三类 Persona(Optimizer / Architecture / Reward),Reward Persona 用 SQL 做数据相关性分析;线上 A/B 实验验证北极星指标;已在 YouTube 生产落地。
Self-EvolveRec(KAIST,学术)
专注推荐代码的开放进化;独特的 User Simulator 提供定性用户反馈;诊断工具协同进化是其独有贡献;基于 benchmark 数据集验证。
两者共同揭示了同一趋势:标量指标已不足以驱动推荐系统的高质量优化,需要更丰富的反馈信号(无论是用户模拟还是 SQL 数据分析)来为 LLM 提供方向性指引。
4.4 对推荐系统研究的启发
- 失败根因分析:将推荐优化的评估粒度从"整体 NDCG"细化到"类别级 / 用户群级的行为分析",指导针对性改进。
- 动态诊断工具:构建推荐系统的"健康检查套件",并随模型迭代同步更新,而非一次性写死。
- 用户满意度信号:将用户研究中的定性反馈(问卷、访谈、眼动追踪等)系统性地接入算法优化循环,减少 NDCG 与真实体验的鸿沟。
共 12 个核心 Python 文件,代码架构清晰。以下按调用关系从入口到底层逐层解读。
5.1 整体文件结构
5.2 主循环:self_evolverec.py
Self_EvolveRec 类是整个框架的 Orchestrator。run() 方法是核心循环,每次迭代按 4 大步骤执行:
-
1
采样父代码库(
self.database.sample())
从进化存档中采样一个父代码库parent和若干 "inspirations"(其他历史代码库,作为参考)。 存档用 MAP-Elites + Island 算法管理,同时追踪三个维度(score / diversity / complexity)保证种群多样性。 -
2
双路深度研究(Step 2-1 / 2-2)
researcher.run():针对模型本身搜索 arXiv,规划→搜索→写研究报告,输出改进 idea。
diagnosis_researcher.run():针对诊断工具(结合 SIM 反馈)同步搜索,输出诊断工具的改进 idea。
两路独立异步执行,互不干扰。 -
3
双路代码生成(Step 3-1 / 3-2 / 3-3)
coder.run():按研究报告生成模型代码的 SEARCH/REPLACE diff,应用后得到child_code。
diagnosis_coder.run():同步生成诊断工具的 diff(接收child_code作为输入,确保诊断工具与新架构兼容),得到child_diagnosis_code。
最终代码 = 模型代码 + 诊断代码(直接字符串拼接):final_child_code = child_code + '\n\n' + child_diagnosis_code -
4
评估 + 入库(Step 4)
problem.evaluate(final_child_code):实际运行代码,训练模型,收集 NDCG/HR + SIM 反馈 + DIAG 报告。
将结果封装为Program对象加入database,记录完整血统(父 id、进化历史、两条反馈文本)。
# 1. 采样
parent, inspirations = self.database.sample()
# 2. 研究(模型 + 诊断工具,并行)
research_reports = await self.researcher.run(parent, inspirations)
diagnosis_reports = await self.diagnosis_researcher.run(parent, inspirations)
# 3. 编码
child_code = await self.coder.run(new_idea, parent, ...)
diag_code = await self.diagnosis_coder.run(new_idea_diag, parent, ...,
current_recommender_code=child_code) # 传入新模型代码
final_code = child_code + '\n\n' + diag_code # 简单拼接
# 4. 评估(跑训练 + SIM + DIAG)
metrics, final_code = await self.problem.evaluate(final_code, child_id)
# 5. 入库
self.database.add(Program(id=child_id, code=final_code, metrics=metrics, ...))
5.3 User Simulator:simulator/simulator.py
Simulator 在 main_code.py(种子推荐代码)中直接实例化,嵌入训练/评估循环里。
Persona 计算(get_personality)
对训练集中每个用户计算三个特征的原始数值,再用分位数划分为 0/1/2 三档:
- Activity:
len(user_train['History'][u]),即交互历史长度。分位数阈值 [60%, 90%]。 - Diversity:
len(set(所有交互过的类别)),唯一类别数。分位数 [33%, 66%]。 - Conformity:
mean((用户打分 - 该物品全局平均分)²),打分偏差的均方值。偏差大 → 低从众。分位数 [25%, 80%]。
每个档位映射到自然语言描述字典 defined_personality,组合后构成 Prompt 中的"fixed traits"部分。
反馈生成(两步 LLM 调用)
Step 1 — 个人评估:get_userfeedback(personality, rec_page, interaction_his, results_1)
Prompt 结构:
## Your fixed traits:拼接好的 Persona 描述## Your recent context:用户最近交互的物品(含标题、类别、价格、时间戳)## Current recommendation list:模型当前的推荐列表PART 1:用户已做的行为决策("是否会点击此物品")PART 2:要求输出 MODEL_FEEDBACK_JSON,包含positive_alignment_reasons / negative_misalignment_reasons / overgeneralized_signals / missing_signals / summary_diagnosis
Step 2 — 聚合:aggregator_prompt 接收所有用户的 JSON,输出系统级诊断报告,格式包含 status / WHERE_THE_SYSTEM_GETS_IT_RIGHT / WHERE_THE_SYSTEM_GETS_IT_WRONG / PRIMARY_FAILURE_MODE 等字段。
5.4 初始诊断工具:examples/sasrec_cds/initial_code/diagnosis_tools.py
两个内置探针的具体实现:
探针 1:analyze_embeddings_collapse_cosine
# 从 item_emb.weight 取出 embeddings emb = self.model.item_emb.weight.detach()[1:] # 跳过 padding item # 随机采样 2048 个 idx = torch.randperm(n)[:sample_size] x = F.normalize(emb[idx], p=2, dim=-1) # L2 归一化 # 计算 Gram 矩阵,取非对角元素均值 gram = x @ x.t() mean_cos = (gram.sum() - gram.diag().sum()) / (k*(k-1)) # 映射到 [0,1]:0=完全正交(健康),1=完全相同(collapse) collapse_score = (mean_cos + 1.0) * 0.5
这个分数越接近 1.0,说明所有物品的 embedding 几乎一样,模型失去了区分能力。
探针 2:analyze_pos_neg_margin_with_category_breakdown
# 对每个 (user, pos_item, neg_item) 三元组计算 margin margin = s(u, pos) - s(u, neg) # logit 差值 # margin < eps(0.5) → "低边际"样本(难以区分正负) # margin < 0 → "错误排序"样本(负样本得分高于正样本) # 记录低边际样本中,哪些类别出现频率最高 → 定位模型最弱的类别 low_pos_cat[c] += 1 # 类别级别的错误统计
输出结果包含:全局均值 margin、低边际样本比例、出错最多的 top-K 类别——直接指向模型需要改进的物品类别。
5.5 代码进化机制:SEARCH/REPLACE diff 格式
LLM(coder_rec.py)不输出完整文件,而是用自定义 diff 格式输出增量修改:
<<<<<<< SEARCH
def f():
# 原有代码,必须精确匹配
=======
### >>> Self_EvolveRec-BLOCK-START: Category-Aware Hard Negatives
def f():
# 新代码
### <<< Self_EvolveRec-BLOCK-END
>>>>>>> REPLACE
所有改动用 Self_EvolveRec-BLOCK-START/END 标记包裹,方便后续迭代识别"哪些部分是 LLM 加的"(通过 parse_evolve_blocks() 解析)。如果要修改已存在的 block,直接更新 block 内容并修改注释即可。
这比让 LLM 重写整个文件要稳定得多——整个文件大部分保持不变,只有 SEARCH/REPLACE 块被应用,出错概率大幅降低。
5.6 进化存档:database2.py(ProgramDatabase)
存档同时实现了两种种群管理算法:
MAP-Elites
维护一个以 (score × diversity × complexity) 三维网格为索引的精英存档,每个格子保留该特征组合下的最优程序,确保在不同特征维度上都有代表性解。
Island-based Evolution
维护多个相对独立的子种群(默认 3 个 island),每个 island 在自己内部演化若干代后,通过"迁移"(migration)交换优秀个体,防止早熟收敛同时保持多样性。
采样策略:70% 从精英存档(exploitation)、20% 随机探索(exploration)、10% 当前 island 内部采样。每个 Program 对象记录完整元数据:id / parent_id / code / metrics / user_feedback / diagnosis_feedback / evolution_history。
5.7 配置文件:configs/config_baseline.yaml
| 参数 | 默认值 | 含义 |
|---|---|---|
| max_iterations | 21 | 最大进化轮数 |
| researcher.planner/writer | gpt-5-mini | 规划和报告写作用轻量模型(省钱) |
| coder.developer | gpt-5 | 代码生成用强模型 |
| database.population_size | 25 | 种群总规模 |
| database.archive_size | 5 | 精英存档大小 |
| database.num_islands | 3 | 岛屿数量 |
| database.exploitation_ratio | 0.7 | 70% 从精英采样 |
| max_debug_retry | 10 | 代码报错最多自动调试 10 次 |
| max_research_reflect | 1 | 研究阶段反思轮数 |
- 双路并行(模型进化 + 诊断工具进化):研究者和编码者各有两套实例,model 和 diagnosis_tool 同步迭代,诊断工具编码时会读取最新的模型代码,确保兼容性。
- SEARCH/REPLACE diff 而非全量输出:LLM 只输出变更部分,显著降低幻觉(不会遗漏未改动参数),且 block 标记使历史可追溯。
- 完整的容错链:Debugger(自动调试)→ 最多 10 次重试,确保生成的代码能实际运行;运行超时(>30分钟)也有超时检测并返回 0 分。
- 反馈深度嵌入执行代码:SIM 和 DIAG 不是独立系统,而是直接嵌在
main_code.py(进化的目标代码)中,训练结束后自动调用,结果通过simulator_comment / diagnosis_comment字段返回给主进化循环。
5.8 ASCII 架构全图
以下 ASCII 图完整呈现了 Self-EvolveRec 各模块的调用关系与数据流向,可直接对应代码文件阅读。
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Self-EvolveRec 主进化循环 │
│ self_evolverec.py · run() │
└────────────────────────────────────┬────────────────────────────────────────────┘
│
┌──────────────────────▼──────────────────────┐
│ ProgramDatabase (database2.py) │
│ MAP-Elites Grid + 3 Islands 种群管理 │
│ programs: {id → Program} │
│ 采样策略: 70% 精英 / 20% 探索 / 10% island │
└──────────────────────┬──────────────────────┘
│ sample(parent, inspirations)
╔════════════════▼════════════════╗
║ 每轮迭代 (Iter i) ║
╠═════════════════════════════════╣
║ STEP 1 采样父代码库 ║
║ parent = database.sample() ║
╠═══════════════════╦═════════════╣
║ STEP 2-1 ║ STEP 2-2 ║
║ 模型研究 ║ 诊断工具研究 ║
╚═══════════════════╩═════════════╝
│ │
┌────────────────▼──┐ ┌───────▼─────────────────┐
│ ResearcherAgent │ │ ResearcherAgent_Diagnosis│
│ researcher_rec.py │ │ researcher_rec_diag.py │
│ │ │ │
│ Planner (mini) │ │ Planner (mini) │
│ ↓ 生成查询 │ │ ↓ 结合 SIM 反馈生成查询 │
│ Searcher (mini) │ │ Searcher (mini) │
│ ↓ arXiv 搜索 │ │ ↓ arXiv 搜索 │
│ Writer (mini) │ │ Writer (mini) │
│ ↓ 输出 Report │ │ ↓ 输出 DIAG Report │
└────────┬──────────┘ └──────────┬───────────────┘
│ new_idea │ new_idea_diagnosis
╔════════▼════════╗ ╔══════════▼══════════╗
║ STEP 3-1 ║ ║ STEP 3-3 ║
║ 模型代码生成 ║ ║ 诊断工具代码生成 ║
╚════════╤════════╝ ╚══════════╤══════════╝
│ │
┌────────▼──────────┐ ┌──────────▼────────────┐
│ CoderAgent │ │ CoderAgent_Diagnosis │
│ coder_rec.py │ │ coder_rec_diagnosis.py │
│ │ │ │
│ 输入: idea + │ │ 输入: idea_diag + │
│ parent.code │ │ parent.code + │
│ │ │ child_code ←─────────┼── 接收最新模型代码
│ 输出: │ │ │
│ SEARCH/REPLACE │ │ 输出: │
│ diff 块 │ │ SEARCH/REPLACE diff 块 │
│ ↓ apply_diff() │ │ ↓ apply_diff() │
│ child_code │────────▶│ diag_code │
└────────┬──────────┘ └──────────┬────────────┘
│ │
└──────────────┬────────────────┘
│
final_code = child_code + '\n\n' + diag_code
│
╔═════════════▼═════════════╗
║ STEP 3-2 ║
║ Debugger (自动修复) ║
║ coder_rec_debugger.py ║
║ 运行失败 → 最多重试 10 次 ║
╚═════════════╤═════════════╝
│ final_code (可运行)
╔═════════════▼═════════════╗
║ STEP 4 ║
║ problem.evaluate() ║
║ problem.py ║
╠═══════════════════════════╣
║ 实际执行 final_code ║
║ ║
║ ┌─────────────────────┐ ║
║ │ main_code.py │ ║
║ │ (进化后的推荐代码) │ ║
║ │ 训练 SASRec/NCF 等 │ ║
║ │ 模型 (PyTorch) │ ║
║ │ ↓ │ ║
║ │ ┌────────────────┐ │ ║
║ │ │ Simulator │ │ ║
║ │ │ simulator.py │ │ ║
║ │ │ 计算 Persona │ │ ║
║ │ │ Activity │ │ ║
║ │ │ Conformity │ │ ║
║ │ │ Diversity │ │ ║
║ │ │ ↓ │ │ ║
║ │ │ Step1: 个人评估 │ │ ║
║ │ │ Step2: 聚合 │ │ ║
║ │ │ ↓ │ │ ║
║ │ │ simulator_ │ │ ║
║ │ │ comment │ │ ║
║ │ └────────────────┘ │ ║
║ │ ┌────────────────┐ │ ║
║ │ │ DiagnosisProbe │ │ ║
║ │ │ diagnosis_ │ │ ║
║ │ │ tools.py │ │ ║
║ │ │ 探针1: │ │ ║
║ │ │ Embedding │ │ ║
║ │ │ Collapse │ │ ║
║ │ │ (cosine sim) │ │ ║
║ │ │ 探针2: │ │ ║
║ │ │ Ranking │ │ ║
║ │ │ Margin │ │ ║
║ │ │ (pos-neg) │ │ ║
║ │ │ ↓ │ │ ║
║ │ │ diagnosis_ │ │ ║
║ │ │ comment │ │ ║
║ │ └────────────────┘ │ ║
║ │ ↓ │ ║
║ │ NDCG@5 / HR@5 │ ║
║ └─────────────────────┘ ║
╠═══════════════════════════╣
║ 返回 metrics = { ║
║ ndcg_score, ║
║ hr_score, ║
║ combined_score, ║
║ simulator_comment, ║
║ diagnosis_comment ║
║ } ║
╚═════════════╤═════════════╝
│
┌─────────────▼─────────────┐
│ 封装 Program 对象 │
│ id / parent_id / code │
│ metrics / user_feedback │
│ diagnosis_feedback │
│ evolution_history[] │
└─────────────┬─────────────┘
│ database.add(child_program)
┌─────────────▼─────────────┐
│ ProgramDatabase │
│ 更新 MAP-Elites Grid │
│ 检查是否触发 Island 迁移 │
│ 保存 Checkpoint │
└───────────────────────────┘
│
└─────────────────────────────→ 下一轮迭代(最多 21 轮)
补充说明:双路研究 + 双路编码完全对称;diag_code 编写时会读取 child_code,确保与最新模型兼容;反馈信号(simulator_comment / diagnosis_comment)在下一轮迭代中直接注入 Planner Prompt,形成闭环。
5.9 核心 Prompt 原文
以下是系统中 4 个最关键的 Prompt,直接影响进化质量。
researcher_rec.py · PLANNER_INSTRUCTIONS
角色:规划研究方向、生成多样化 arXiv 检索查询。输入包含当前研究思路、历史 inspirations、用户诊断(SIM)和定量诊断(DIAG)。
You are a professor responsible for planning deep and effective research strategies. You will be provided with the context of: - a research problem based on an initial research question - a starting research idea, possibly with a history showing how idea evolves through previous attempt - inspirations from earlier attempts - qualitative user diagnosis from user - quantitative mathematical diagnosis Your task is to develop search queries that identify directions for researchers to advance the idea in a transformative way. Rather than combining existing inspirations in small increments, the queries should guide researchers toward substantial evolutions. Because other researchers will rely on this plan, it must emphasize major, novel approaches instead of minor refinements. You will also be told whether the research progress is early or mature: - If the progress is early, focus on ideas that are feasible and practical, and can grow later and have great future potential. - If the progress is mature, focus on bold, high-impact shifts that challenge the current approach. Your plan should follow two steps: 1. Formulate 1 to 3 precise and diverse search queries. Make sure the queries are diverse—cover different perspectives, challenge untested assumptions, and explore alternative methods. 2. For each query, include a short note explaining why you chose it and what you hope it will reveal.
researcher_rec.py · WRITER_INSTRUCTIONS
角色:综合检索结果、输出新研究 idea 报告。重点是 双对齐约束:候选 idea 必须同时覆盖 ≥2 个用户诊断失败模式 + ≥1 个模型诊断失败模式。
You are a senior researcher responsible for proposing new ideas to address a defined
research problem. You will receive:
- The research problem, including its evaluation metric and available data
- A starting research idea, possibly with its evolution history
- Inspirations from earlier attempts
- A list of related online search results
- A research progress score (0-100%) indicating how far the idea has advanced
[...5 步结构化框架...]
4. Generate and evaluate ideas
- Propose 3-10 algorithmic ideas of varying originality and complexity.
- For each idea, critically assess with scores:
- Originality (0-10)
- Future Potential (0-10)
- User Diagnosis Alignment (0-10) ← 与 SIM 反馈对齐
- Model Diagnosis Alignment (0-10) ← 与 DIAG 探针对齐
- Code Difficulty (0-10)
- Then, select the single best idea:
★ The chosen idea MUST explicitly address at least TWO user-facing failure
modes identified in the User Diagnosis.
★ The chosen idea MUST explicitly address at least ONE model-facing failure
mode identified in the Model Diagnosis.
If either constraint is not met, the idea is NOT eligible, regardless of
its other scores.
simulator/simulator.py · get_userfeedback()
角色:模拟单个用户,从模型改进视角解释推荐的因果原因,输出标准化 JSON 供聚合器使用。注意:禁止讨论 UI/曝光策略,只允许从用户决策逻辑角度发言。
You excel at role-playing. Picture yourself as a single user exploring a
recommendation page like Amazon.
The goal of this task is NOT UI feedback.
It is to help improve the recommendation model itself by explaining WHY certain
items felt right or wrong.
## Your fixed traits
{personality} ← Activity / Conformity / Diversity 三维 Persona
## Your recent context (recent interactions)
- {interaction_his}
## Current recommendation list
{rec_page}
------------------------------------------------------------
PART 2 — MODEL_FEEDBACK_JSON (model-improvement focused)
------------------------------------------------------------
Analyze the recommendation list from the perspective of *decision reasons*.
Focus on:
- Why the items you liked felt like strong matches.
- Why the items you disliked felt off, even if they looked similar on the surface.
- What signals seem to be overused or underused by the system.
- Where the system generalized correctly vs incorrectly from your recent behavior.
IMPORTANT RULES:
- Do NOT talk about UI, layout, or presentation.
- Do NOT suggest business rules or exposure tricks.
- Do NOT mention model internals or technical terms.
- Speak as a user, but explain your choices clearly and causally.
Output ONLY the following JSON:
MODEL_FEEDBACK_JSON:
{
"positive_alignment_reasons": [...],
"negative_misalignment_reasons": [...],
"overgeneralized_signals": [...],
"missing_or_underweighted_signals": [...],
"summary_diagnosis": "One short sentence summarizing how the system interpreted
your intent, correctly or incorrectly."
}
simulator/simulator.py · aggregator_prompt
角色:将 N 个用户个人诊断 JSON 压缩为系统级报告,输出 simulator_comment,直接作为下一轮 Researcher Planner 的输入。status: CRITICAL 时才触发下轮进化(与 DIAG 取 AND 逻辑)。
You are a Lead Recommender Systems Analyst synthesizing user simulation feedback
to diagnose how the recommendation model is behaving.
Input:
- A list of User Feedback Reports (JSON objects) from multiple simulated users:
{per_user_json_list}
Goal:
Produce a concise, system-level diagnosis of:
- what decision patterns the model appears to rely on,
- where those patterns align or misalign with actual user choice logic,
- which misalignments most directly reduce the quality of top-ranked items.
Do NOT discuss UI, layout, exposure strategy, or business rules.
Do NOT propose specific model architectures or losses.
Stay at the level of behavioral decision logic inferred from user feedback.
OUTPUT FORMAT (JSON ONLY — all keys required):
{
"status": "<CRITICAL | NEEDS_IMPROVEMENT | STABLE>",
"SYSTEM_INTERPRETATION_OF_USER_INTENT": "One short sentence...",
"WHERE_THE_SYSTEM_GETS_IT_RIGHT": [...],
"WHERE_THE_SYSTEM_GETS_IT_WRONG": [...],
"OVERUSED_DECISION_PATTERNS": [...],
"UNDERUSED_OR_MISSED_DECISION_PATTERNS": [...],
"PRIMARY_FAILURE_MODE_AT_TOP_OF_LIST": "One sentence explaining...",
"DIAGNOSTIC_SIGNALS_TO_TRACK": [...]
}
Rules:
- No numeric scores or internal error codes.
- No UI or exposure language.
- No raw user quotes; always generalize and compress.
- Every statement should describe a repeatable system behavior or decision pattern.
- Focus on issues that, if corrected, would materially improve how many top-ranked
items users would realistically choose.
coder_rec.py · CODER_INSTRUCTIONS
角色:将研究 idea 转化为 SEARCH/REPLACE diff 代码块。强调最小变更原则:只改必要部分,禁止重写整个文件;所有修改必须用 Self_EvolveRec-BLOCK 标记包裹,便于历史追溯。
You are a researcher with strong software engineering skills, improving algorithmic code through iterative, performance-driven modifications in multiple rounds. You MUST use the exact SEARCH/REPLACE diff format. Do NOT use Git diff format. Do NOT use line prefixes like +, -, or @@. Use this structure exactly: <<<<<<< SEARCH # Original code (must match exactly) ======= ### >>> Self_EvolveRec-BLOCK-START: <research idea> # New code here ### <<< Self_EvolveRec-BLOCK-END >>>>>>> REPLACE Task Guidelines: 1. Think before coding, understand the research idea and performance bottlenecks. 2. Propose specific, actionable changes aligned with the target metrics. 3. You may suggest multiple improvements beyond the research idea. 4. When updating code: - Verify new parameters are invoked in ALL call sites. - If a NEW parameter defaults to None, confirm non-None triggers the code path. - Walk through function calls to confirm each new branch executes. Code Format Guidelines: 1. All SEARCH blocks must match the original code exactly. 2. Wrap changes with Self_EvolveRec-BLOCK markers. 3. If updating existing BLOCK, edit only lines within that block. 4. Do NOT nest Self_EvolveRec blocks inside one another. 5. Limit changes to what is strictly necessary. 6. Preserve original indentation and formatting.