跳到正文

AntOmniEvo

把系统里可调的那部分抽象成一个文件目录,然后让 coding agent 反复改写它。框架负责调度、预算、选择与淘汰:父子候选跑在同一条训练批次上打分,只有越过阈值的改进才会拿到验证集上复评并留下。

Screenshot of AntOmniEvo
编辑截图, 1 Oct 2026AntOmniEvo ↗

这是什么

AntOmniEvo 是一个把「优化」当成改文件的 Python 框架。你先一次给出五样东西——跑被测系统的 System、给输出打 0–1 分且其打分标准就是目标的 Evaluator、训练与验证样本、声明哪些文件可改的 schema、以及起点文件;随后由 coding agent 读失败轨迹,把那些文件改成一个新候选,再由框架裁决它留不留。基因组是一个真实目录,所以一次变异可以是一条 Markdown 规则、一段节点脚本,或某个检索 DAG 的 pipeline.json;被优化的系统里不必有模型,但提出修改的必须是 coding agent。每一轮把父候选与变异出的子候选放在同一条训练批次上跑,只有当分数增量越过阈值或拿到满分时才在验证集上复评,再按 Pareto 支配加 top-N 兜底裁剪种群。被淘汰的候选不会丢掉,而是在同一轮里被有界地反复精修。每一个候选、运行、分析与 changelog 都落进一个可以续跑的工作区,另有一个 React 加 Flask 的可视化器把这次运行渲染出来。它从未打过 release:两个包的 0.1.1 版只发到内部源。

谁做的Ant Research 是一个组织账号而不是某个人:45 个公开仓库、368 个关注者、2022-12-17 注册,资料里挂着 antresearch.com。这个仓库的每一次提交都来自同一个成员账号 jacklv111——2022-09-20 注册、13 个公开仓库、5 个关注者——它是 21 次提交里 9 次的作者名、全部 21 次的关联账号,也是贡献者列表里唯一的一条。README 引的那篇论文列了六位作者,第一作者是 Yubin Lyu;仓库的内部发布流水线点名了两位批准人 lyuyubin.lyb 与 hanpu.mwx。哪个账号对应哪个名字,材料里没有写。

它是怎么搭起来的

组成 · 6

这套东西的组织想法是:优化就该是普通的文件编辑,所以被优化的对象被表示成一个目录,而决定谁活下来的机制是用户不必自己写的确定性代码。这个选择把智能集中到一处——一个读失败运行、动手改文件的 coding agent——同时把概率性的东西挡在循环之外:取批次、接受还是退场、验证集复评、修剪、预算,全都是计数、求和与比较。两个后果塑造了代码。因为只有分析和改文件这两步交给 LLM,它们被拆成两段,中间隔着一份结构化产物;反思路径只改这份产物,绝不动改文件的机制。又因为这套变异循环建立在一个不可靠的花钱者之上,它必须可审计,于是记忆就是文件系统:子候选继承父候选的追加式 changelog,运行记录与分析在错误短路之前先落盘,启动时把中断的候选翻回可选状态。同一批文档对自己的血统也很坦白:Pareto 选择借鉴自 GEPA,被当作自己东西的是同时跑多个候选、以及让被淘汰的候选继续活着。

antomnievo/optimizer/
optimizer.py 里 43,728 字节:主循环,以及按场景分的子类——text2sql、AppWorld、TerminalBench、adconfig 与 RAG 流水线。slot、批次游标、接受还是退场的裁决、反思链、验证步骤,以及子类绕不过去的那两个计数器都归它管。
antomnievo/proposer/
coding agent 这一侧:28,967 字节的 base_proposer.py 装着「先分析、后变异」的两段流水线,每个后端只写一个薄子类——驱动 claude 的 claude_code_proposer.py(6,054)和驱动 pi 的 pi_coding_agent_proposer.py(5,776);三个提示模板以 26,192 字节的 reflection_analysis_prompt.py 为首,另有 analysis_prompt.py(9,508)与 mutation_prompt.py(8,586);还有沙箱里的 agent 被要求去跑的几个脚本 validate_analysis.py、append_changelog.py、diff_dirs.py,前两个注册成命令行入口,好让它们在沙箱的 PATH 上找得到。
antomnievo/interface/, store/, evolution_algorithm/, model/
契约、记忆与选择:六个抽象接口(System、Evaluator、Proposer、EvolutionAlgorithm、CandidateStore、DataInst),30,684 字节的文件系统 store 旁边是 26,020 字节的接口,6,960 字节的 micro-pareto 算法,以及候选、预算、统计、轨迹与可调产物 schema 的 pydantic 模型——其中 tunable_artifact_defs/ 下有九个文件,最大的是 21,105 字节的 text2sql 与 17,431 字节的 RAG 流水线。
antomnievo/system/, evaluator/, dataset/, example/
四个参考目标及其脚手架:一个 LangGraph ReAct agent、跑 BIRD/DP/Spider2Snow 的 text2sql、AppWorld 与 TerminalBench 系统;各配一个评估器,AppWorld 与 TerminalBench 那两个分别是 9,511 与 8,793 字节;八个数据集加载目录;以及八个把各组件接起来的示例入口。它们每一个都依赖框架不会替你装的外部代码库。
visualizer/
第二个包 ant-omnievo-visualizer:一个 Flask 后端(server.py 11,616 字节、workspace_reader.py 10,785、manage.py 6,534),加一个 Vite 与 React 前端,其 39 个源文件里有 30,427 字节的 GymBackdrop.tsx、27,868 字节的 MaraChains.tsx 和一份 58,913 字节的样式表,public/ 下还有 40 个文件、32 MB,几乎全是精灵图。
docs/, skills/, .aci/
十六份文档,八份英文配八份中文,打头的是 13,706 字节的 system-design.md 与 12,517 字节的中文版;一份 74,597 字节的 SKILL.md 属于 eddy-antomnievo-experiment 技能,带九份配方参考,最长的一份 38,238 字节,是写给 Ant 内部用户看的;再加内部发布流水线的两个文件。

取舍,以及它替代了什么

  • 可调产物就是一个文件目录 替代 一组受限参数,或一门专用 DSL

    这是设计文档列的第一条:真实目录让框架能用上一个成熟的、直接改文件的 coding agent,也把表达能力变成「文件系统装得下什么就是什么」——一条 Markdown 规则、一份 Python 实现、一个校验脚本、一段运行期扩展。于是每一处改动都被逼进一条结构化记录里,必须引用它所回应的那条失败轨迹观察。

  • 把被淘汰的候选留着继续精修 替代 一旦没越过阈值就让它退场

    README 引的论文认为被丢掉的候选里含有后续提案需要的信息,丢掉它们会让下一次提案重走同样的失败路径。链的深度有固定上限,种群规模由 Pareto 过滤后的 top-N 兜底,所以多出来的尝试不会把预算带跑。

  • micro-pareto:支配关系修剪加 top-N 兜底 替代 纯粹的 Pareto 弱支配

    设计文档给的理由是:在带随机性的打分下纯 Pareto 会失效;它还说选择会按候选拿下多少个样本的第一名来加权,以保护全面型候选而不是偏科型候选。同一份文档把 Pareto 选择本身归功于 GEPA。

  • 在运行与分析之间插一层结构化分析 替代 让改文件的 agent 直接读原始运行记录

    第一阶段把一次失败运行变成一份 RunAnalysis:观察加处方,每条处方都要指名它解决的是哪一条轨迹观察,并做一次自检;第二阶段先跨样本去重、化解矛盾,再动手改文件,必须通过一条 changelog 命令记录 diff,且没有文件被改就算失败。原始运行永远到不了改文件那一步。

  • 把验证集隔离交给运行时强制,而不是写进提示里 替代 两个后端都用提示里声明的访问规则

    Pi 后端启动时挂了两个扩展,一个硬性拦住对验证运行的读取,一个拦住绕过 changelog 命令;Claude Code 后端则靠提示里声明的访问规则。设计文档把读者该得出的结论直接写了出来:Pi 这条路径更受控。

  • 预算触顶时先停止开新 slot,让在跑的跑完 替代 一到上限就把正在做的工作杀掉

    任何一项上限触顶就不再开新 slot,并让在飞的 slot 排空;特点文档把它和断点续跑配在一起讲:长跑既不会超支,也不会把已经花掉的钱丢掉。它管这叫软停止。

依据docs/system-design.md(13,706 字节)、docs/features.md、docs/extensibility.md、docs/when-to-use.md、docs/quickstart.md、docs/workspace-artifacts.md、docs/checkpoint-resume.md、docs/visualizer.md、README.md、两个包的 pyproject.toml、.aci/python/.aci.yml 及其 README,以及九个 pull request 的正文。

制作过程

6 个阶段
  1. 01

    十五天、21 次提交、九个 pull request,没有一个 release

    仓库创建于 2026-09-15,第一个提交 init 落在两小时十八分钟后;最新的一个是 2026-09-30 合并的 pull request 9。也就是说,十五天里 21 次提交,全部集中在九月,而它们背后只有一个账号:21 次全部关联到 jacklv111,其中 9 次的作者名是 jacklv111,另外 12 次用的是另一个中文作者名和一个 163 邮箱。其中 7 次带 Co-authored-by: Claude 尾注。同一段时间里开了九个 pull request,九个都由同一个账号关掉,且没有任何一条评论——正文是作者自己写的变更说明,而不是对话,下文大部分细节正来自这里。它从未建过 release,也没有 tag;版本只以两个 pyproject.toml 里的 0.1.1 存在,而把它们发出去的是内部流水线 .aci/python/.aci.yml:它的 README 写明有一道人工的「Verify & Confirm」闸门、必须设置 PIP_INDEX_URL(否则隔离构建会打到公共源)、以及两位具名批准人。周围是 866 个星、86 个 fork、35 个 watcher、0 个 open issue,仓库 45,613 KB。

  2. 02

    一个 slot,以及一个子候选要活下来必须满足什么

    框架把一次迭代叫做一个 slot,设计文档把它里面的每一步都写了出来。优化器从父候选自己的 (epoch, dataset_index) 游标取一批数据——尾部对齐、到头就绕到下一个 epoch,而且即使这次 rollout 失败游标也照样前进,于是数据顺序是一份快照,而不是对失败的应激反应。接着父候选与变异后的子候选跑在同一条批次上,而比较本身就是一次求和:增量等于子候选分数之和减去父候选分数之和。有两件事能过线:增量达到或超过 min_improvement_per_batch,或者拿到满分。过线的子候选会在验证集上重新打分、写下 summary.json,状态从 evolving 翻回 pending;没过线的,如果开了反思就走反思链,没开就直接 retire。每个 slot 结束后,父候选推进游标、eliminate 跑一次、iteration_records.jsonl 追加一行。快速开始里的数字是 batch_size=3、max_iterations=1000、num_proposals=1、max_reflection_iterations=2、min_improvement_per_batch=2.0、max_candidate_num=3。多个 slot 在同一个进程里并发跑,任何一项预算触顶就不再开新 slot,而在跑的跑完为止;「硬上限」在特点文档里是四条,在设计文档里是五条,多出来的那条 max_system_runs 把包括验证运行在内的每一次运行都算进去。

  3. 03

    被淘汰的候选不丢,而是被继续精修

    一批数据没过阈值时,框架不会停在一次自然语言反思上,而是启动一条 mara chain:反思提示里预装了整条链的上下文——chain id 路径、带 Δ 列的逐样本分数表、已归因的 changelog、链上每一环此前对这条样本的分析,以及各环的运行文件——然后要求分析 agent 跑五种方法的诊断、填一张 A–I 诊断表、优先 REMOVE 与 REPLACE 而不是新增、在 artifact_issue 里点名链上哪一环该负责,并去找「lost wins」。这样最多跑 max_reflection_iterations 轮;最终胜过原父候选的那一环被验证并留下,其余全部退场。第二阶段(真正改文件那一步)在反思路径上机械地不变——设计文档把整条链的学习都放在分析 JSON 这一层,而不是新增机制。特点文档明确写了什么是借来的、什么是自己的:Pareto 选择沿用自 GEPA,这里主张的增量是并发与 mara chain;README 引的那篇论文建立在同一个观察上——被丢掉的候选里往往有后续提案需要的信息,丢掉它只会让下一次提案再撞同一个坑。

  4. 04

    「optimizes anything」这句话的边界在哪

    仓库描述许诺的是一个能优化任何东西的框架,而边界被写在了一份文档里。要成立得满足两个条件:被优化的东西能表示成一个可调产物目录,且它的评估可重复、成本可控。在这两个条件之下,它说支持三种形态——AI agent 的 skill/harness/memory 目录;workflow,也就是配置加节点代码,比如某个检索 DAG 的 pipeline.json;以及单文件算法加它的描述——并两次强调被优化的系统里不必有模型。与目标不同,proposer 必须是一个 LLM coding agent。不适用的情况也写得很直白:根本没有可调产物(只有几个标量参数,它建议改用黑盒调参)、评估不可重复或极其昂贵、以及输出受严格合规约束——最后一条还提醒,proposer 是在沙箱里改文件的,沙箱权限得自己去审。另有两处限制不在宣传里而在代码里:框架不管被优化系统自己的运行时与打分工具链;分布式演化也不在范围内——云端存储要你自己写一个「本地加透明同步」的子类,文档还专门说明,这不是多个 worker 跨主机共用一个 store。第三个限制由示例本身印证:它们都跑不起来,各自依赖外部代码库,其中一个到今天还把作者自己家目录下的绝对路径当作工作区。

  5. 05

    十次「成功」,和一个空的成果目录

    仓库里最有用的一条 pull request 是一处修 bug,它的正文把根因、错误表现和修法都写了出来。在模型网关限流时,模型返回空的 assistant 消息;agent CLI 内部重试之后以 0 退出,于是什么都到不了 trajectory.errors。第一阶段把这种会话全都记成成功——日志写着「10 succeeded」——而分析结果目录始终是空的,第二阶段随后基于「(no analysis results available)」提案,什么也没改。这条 pull request 里的三处改动,材料写清了前两处:一是 find_degenerate_ending,把「尾部连续两个以上空模型片段」或「零工具调用且零文本」判为失败,抛 PiEmptyResponseError 进入 429 已经在用的同一条重试路径,用同样的退避,并走既有的重试钩子;二是第一阶段在会话干净退出后,断言分析结果文件确实在本轮开始之后被写过或被重写过,否则这条数据算失败而不是成功。第三处改动属于第二阶段,在现有摘录里被截断了。它值得记下来的地方在于失败的样子:一个计数器、一个指标和一行日志都一致地宣布活干完了,唯一不同意的是那个空目录。

  6. 06

    关于一次运行,记下了什么、又没记什么

    仓库里没有任何地方发布结果:README 和它旁边八份英文文档都没有基准表。真实运行留下的唯一证据是视觉的——可视化文档里嵌了六张截图:把候选画成龙虾、按分数分层的健身房,谱系树,最优分数曲线,一张标出所有候选都没答对的题目的覆盖网格,以及文件查看器。项目发布的是「自己怎么查一次运行」:比较 logs/statistics.json 里的 baseline_avg_score 与 best_avg_score,读 iteration_records.jsonl 看每个 slot 是否被接受、旧批次与新批次的分数和、以及 reflection_depth(大于 0 表示是反思救回来的),再顺着 parent_id 往上走到根,读 changelog.jsonl——工作区文档把那称作可调产物为什么长成现在这样的人类可读历史。它真正拿得出手的数字,在 README 于 2026-09-30 开始链接的那篇论文里:摘要声称在 AppWorld 上相对 GEPA、ACE、SkillOpt-Lite 最高提升 20.5%,达到目标分数所用 rollout 比 GEPA 少 65.5%,在 TerminalBench 2.1 上通过率比 AHE 和 Meta-Harness 分别高 20.2 与 22.5 个百分点,在 MuSiQue 上相对一份手写检索流程把 test nDCG@10 与 Recall@10 提升 0.104 与 0.131。这些是同一支团队写在摘要里的主张,本记录的材料里没有任何东西复现过它们。

相关档案

全部档案 →