当 Prompt 优化器在 6 个任务里 4 个原地踏步:MOCHA 用切比雪夫退火给 Agent 技能找出路

核心摘要

如果你最近在折腾 Claude 的 SKILL.md,或者在做任何"把一段 prompt 塞进有字符上限的字段里、让 Agent 自动调用"的事,这篇论文你大概率会有共鸣。

它讲了一件挺扎心的事:在 6 个 Agent 技能优化任务上,TextGrad、ProTeGi、GEPA 这三个目前业内常见的 prompt 优化器,有 4 个任务跑了 1000 次 rollout 之后,输出的还是初始的种子 prompt 一字未改——不是改坏了被回滚,是从头到尾根本就没动过。作者的解释也很直接:技能字段有硬性长度限制(description ≤ 1024 字符、body ≤ 5000 字符),改 prompt 想涨准确率,几乎注定要顶破这两个限制;而单目标优化器面对"涨了准确率但违反约束"的候选,会直接拒掉,于是一步都迈不出去。

MOCHA 用了一个老套但用得很对的工具——切比雪夫标量化(Chebyshev scalarization)+ 指数退火——把 prompt 优化建模成多目标搜索:前期靠超体积贡献(HVC)撑开帕累托前沿,后期慢慢退化到切比雪夫接受准则去精修。结果是平均准确率比最强基线相对提升 7.5%,FEVER 上拉了 14.9%,TheoremQA 上拉了 10.4%,还顺手发现 2 倍数量的非劣解。这篇文章不在于方法多新——多目标进化早就有切比雪夫——而在于把"Agent 技能字段是受平台约束的多字段产物"这个事实当回事,并且用对了工具。


论文信息

  • 标题:MOCHA: Multi-Objective Chebyshev Annealing for Agent Skill Optimization
  • 作者:Md Mehrab Tanjim, Jayakumar Subramanian, Xiang Chen, Branislav Kveton, Subhojyoti Mukherjee, Anlan Zhang, Sungchul Kim, Somdeb Sarkhel, Sunav Choudhury
  • arXiv2605.19330(v1, 2026-05-19)
  • 类别:cs.AI / cs.LG / cs.SE,预印本 25 页

一、问题是怎么来的:一个被忽视已久的细节

先说点背景。最近一年 Agent 圈出现一个新的工件叫 SKILL.md——Anthropic 在 Claude 的 Skills 体系里推的格式,简单讲就是"给 Agent 的可调用模块":YAML 头部(name、description、metadata、allowed-tools、compatibility 等)+ Markdown 正文(具体执行指令)。

这玩意儿和我们以前理解的"prompt"有几个本质区别:

  1. 多字段:description 和 body 是两个独立字段,各自有用
  2. 路由用 description:Agent 在选用哪个 skill 时只看 description,所以这个字段太长会被截断、影响检索
  3. 执行看 body:Agent 真正执行时把 body 注入上下文,太长会被压缩或挤占其他 skill 的位置
  4. 共驻:多个 skill 同时存在于一个有限的上下文窗口里,相互抢资源

平台对此有硬约束:description 不能超过 1024 字符,body 不能超过 5000 字符。Anthropic 这么设计是有道理的——你要让一个 Agent 同时挂几十个 skill,就必须给每个 skill 一个明确的"占地面积"上限。

那么问题就来了:当你想优化一个 skill 的准确率,几乎一定要往里加规则、加示例、加 step-by-step——而这些都会撑大 body 字段

我之前调过一段类似的东西,那种感觉很熟悉:你眼看着一个加了几条详细规则的版本准确率涨了 8 个点,但 body 从 4800 变成 6300,平台直接拒掉。回过头看 prompt 优化器,它根本不知道 body 被截了——它收到的反馈是"这个候选准确率涨了",于是开心地接受了;但部署一上线,body 被平台 truncate 到 5000 字符,最后那几条规则根本没进 context,准确率反而掉了。

这就是这篇论文要切入的痛点:skill 优化天然就是个多目标问题。准确率(correctness)、description 合规(≤1024)、body 合规(≤5000)—— 三个目标,互相拉扯。

图1:技能优化的多目标本质与 MOCHA 的两阶段思路。左侧展示种子技能 p₀ 经过迭代优化变成 p* 后准确率提升但合规性受损;右侧展示 MOCHA 的两阶段:探索阶段用 HVC 把帕累托前沿往各方向推开(绿色),开发阶段沿切比雪夫方向精修边角(紫色)。

图1:左图——种子技能 p₀ 一开始干干净净都满足约束,但准确率只有 0.72;优化后的 p 准确率涨了,但 body 长度爆掉、compliance 跌到 0.43。右图——MOCHA 把这个过程切成探索(推宽前沿)和开发(精修极值)两段,避免被单一方向卡住。*

二、为什么现有的 prompt 优化器在这个任务上不灵

这是论文最值得细看的部分。作者做了个非常严格的对照:所有方法用同一个 mutation 接口(同样的 SkillMdProposer)、同样的 LLM mutator(Claude Opus 4.6)、同样的 1000 rollout 预算、同样的逐目标文本反馈——也就是说所有优化器收到的"候选生成能力"和"候选反馈信号"都一样。

唯一不一样的就是接受/选择策略

来看主表:

Skill Seed TextGrad ProTeGi GEPA MOCHA
GPQA .592 .592 (无变化) .592 (无变化) .592 (无变化) .636
TheoremQA .534 .672 .690 .656 .762
HoVer .618 .618 (无变化) .618 (无变化) .618 (无变化) .660
HotpotQA .336 .592 .622 .602 .600
FEVER .632 .632 (无变化) .632 (无变化) .632 (无变化) .726
DebugBench .615 .615 (无变化) .615 (无变化) .615 (无变化) .666
Mean .554 .620 .628 .619 .675

注意标"无变化"的那 4 行——GPQA、HoVer、FEVER、DebugBench——三个基线方法跑 1000 次 rollout 之后,输出的就是种子 skill 一字未改。这不是说效果差,是根本没动

我看到这个表的第一反应是不太相信,但作者的解释挺有说服力:种子 skill 已经是"干净简短但能力一般"的状态——它满足所有合规约束(description 短,body 短),但准确率只是 baseline 水平。优化器收到反馈"准确率不够",mutation LLM 提出一个"加了详细规则的更长版本",这个版本准确率确实涨了,但 body 撑爆了——

  • TextGrad 是贪心的:只接受全面优于当前 best 的候选。准确率涨了但 compliance 跌了,这就不是 dominate,拒。
  • ProTeGi 用 UCB beam search:优化标量得分。如果它把 compliance 计入 score,那准确率涨 + compliance 跌可能 net 是负的。
  • GEPA 是 Pareto-aware 的,但它的 selection 是"在每个 validation 数据点上是否最优"——这个粒度还是单目标的,没法处理跨字段的合规张力。

三种策略殊途同归:只要候选在某个维度退步了,就被拒。问题是种子 skill 已经在合规边界附近,往任何"提升准确率"的方向走几乎都意味着合规性退步。于是优化卡死。

图2:六个任务上各方法的优化曲线(5个seed均值±1 std)。MOCHA 蓝线在每个任务上都明显爬出种子分数,而几条基线在 GPQA、HoVer、FEVER、DebugBench 上完全是水平的——0 到 35 次迭代之间没有任何上升。

图2:横轴是迭代数(一次迭代≈一次完整的 mutation+evaluation+commit),纵轴是测试集 correctness。FEVER 和 DebugBench 那两张图最直观:基线方法的曲线(橙色虚线、红色虚线)就是一根紧贴种子线(灰色虚线)的水平线,从头到尾没爬过种子。

这个图我盯了挺久,因为它揭示了一个特别有意思的事:问题不在 mutation——LLM 完全有能力提出更好的候选——问题在 acceptance。如果连一个"准确率 +8% 但 body +20%"的候选都接受不了,那再多的 rollout 也是浪费。

三、MOCHA 的核心:用切比雪夫"接受所有方向的进步"

理解了问题,方法就直观了。MOCHA 的两个核心组件:

3.1 切比雪夫标量化:先解决"哪些非凸最优解被线性方法漏掉"

多目标优化里一个非常本质的差别——线性标量化和切比雪夫标量化对非凸前沿的覆盖能力不同

线性标量化是大家最熟的:

\[s_w^{\mathrm{lin}}(p) = \sum_i w_i \cdot m_i(p)\]

这就是把多目标搞成加权求和。直觉上很合理,但有个理论结果:线性标量化只能找到帕累托前沿的凸包上的点。如果前沿是非凸的(比如中间凹下去一块),无论你怎么调权重 w,那块凹的最优解都摸不到。

切比雪夫不是这样:

\[s_w(p) = \max_{j} \left[ w_j \cdot |m_j(p) - z_j^*| \right]\]

它衡量的是"最坏维度上离理想点 \(z^* = (1,1,\ldots,1)\) 的加权距离"。这个 max 函数让它能"贴住"非凸区域——理论上对任何帕累托最优点 \(p^*\),都存在一个权重 \(w^*\) 使得 \(p^*\) 是切比雪夫最优解(Miettinen 1999 的经典结论)。

工程上怎么用?MOCHA 在每次迭代随机抽一个权重向量 \(w \sim \mathrm{Dirichlet}(\mathbf{1})\)——也就是从单纯形上均匀采样——然后选 \(\arg\min_p s_w(p)\) 作为 parent 去 mutation。这相当于每一步都从前沿的某个随机方向去推。

我个人觉得这个设计的精髓在于:它把"权重该怎么设"这个最讨厌的问题甩给了均匀采样。你不需要事先决定"准确率比合规重要 70%"——每一轮都让随机权重决定,长程下覆盖整个前沿。

3.2 HVC 与退火:从"什么都接受"到"按方向精修"

只用切比雪夫还不够。论文做了实验,纯切比雪夫在有限预算下前沿很窄——因为你只在最近被采到的那个方向上推,其他方向的种子点根本没机会被改进。

所以 MOCHA 加了第二条机制:超体积贡献(Hypervolume Contribution,HVC)

简单说,HV 就是一个解集在目标空间里"罩住的体积"(以原点为参考点)。一个新点的 HVC 就是它新增的体积——只要它给前沿任何方向带来扩展,HVC 就为正。

HVC 的好处是方向无关:它不管 mutation 是冲哪个方向去的,只要对前沿有贡献就接受。

然后 MOCHA 把这两套接受准则用指数退火串起来:

\[\tau(b) = \tau_{\mathrm{end}} + (\tau_0 - \tau_{\mathrm{end}}) \cdot \exp(-\lambda \cdot b/B)\]

其中 \(b\) 是已消耗预算,\(B\) 是总预算。优化早期 \(\tau\) 大,接受准则是 HVC 大于 τ 才接受——只要候选给前沿带来增量就要;后期 \(\tau \to 0\),切换到 切比雪夫接受——候选必须在 parent 被采样时的同一方向 \(w\) 上严格变好才接受。

整个算法跑一遍是这样:

init: pool P = {seed}, buffer B = ∅
while budget remaining:
    w ~ Dirichlet(1)                          # 1. 随机权重
    parent ← argmin_p s_w(p)                  # 2. 切比雪夫选 parent
    candidate ← LLM_mutate(parent, feedback)  # 3. mutation
    τ ← exponential_anneal(b/B)               # 4. 退火阈值
    if τ > 0:                                 # 5. 探索期
        if HVC(candidate, P) > τ:
            commit candidate to P
    else:                                     # 6. 开发期
        if s_w(candidate) < s_w(parent):
            commit candidate to P

我特别喜欢这个设计的一点是它每一步只看一个 w——选 parent 用 w,开发期接受也要求在同一个 w 方向上变好。这种"一个 w 配一个完整决策"的设计让噪声不会乱窜:你在某个方向上选了 parent 又拒了 candidate,至少这个方向上是自洽的。

图3:TheoremQA 上 6 种方法的 2D 帕累托前沿(correctness × body compliance)。三条基线(灰色、橙色、红色)密集挤在 (0.65, 0.4) 附近——只有一两个解,几乎重合。MOCHA 三个变体(紫色 w/o HVC、绿色 w/o Annealing、蓝色 MOCHA)的解散布在 0.7~0.8 的 correctness 区间,覆盖了从合规优先到准确率优先的整条前沿。

图3:HV 数值印在图例里——MOCHA 是 0.563,跟 w/o HVC(0.554)和 w/o Annealing(0.585)形成明显的"探索-开发光谱"。w/o Annealing 因为一直在探索阶段,HV 最大但准确率被牺牲了;w/o HVC 一直在开发,准确率高但只剩两个解。MOCHA 居中——这就是退火设计想要的效果。

四、消融实验:把 MOCHA 拆开看每个零件值不值钱

消融实验是这篇论文我个人最喜欢的部分,因为它干脆把"MOCHA 是哪一部分起作用"这个问题摊开来讲清楚了。

Variant Correctness Δ vs ProTeGi HV #PF
Best Baseline (ProTeGi) .628 .514 1.6
w/o HVC(纯开发) .687 +.059 .530 3.4
MOCHA(平衡) .675 +.047 .531 3.6
w/o Annealing(纯探索) .671 +.043 .533 3.8

三件事很清楚:

1. 一条干净的探索-开发光谱:去掉 HVC(剩纯切比雪夫开发)准确率最高(.687),但前沿点最少(3.4);去掉退火(剩纯 HVC 探索)前沿最丰富(3.8 个 Pareto 点)但准确率被压到 .671;MOCHA 居中。这恰好就是设计意图——你把退火的"温度"从无穷高(纯探索)调到 0(纯开发),中间这条曲线就是 MOCHA。

2. 即使最弱的 MOCHA 变体也碾压最强基线。w/o Annealing 是 .671,仍比 ProTeGi 的 .628 高出 4.3 个百分点——而三个基线之间的差距才 0.9 个百分点(.619 到 .628)。这个观察特别值得注意:真正起作用的是"多目标 selection 框架"本身,而不是 HVC 或退火哪个具体组件。换言之,只要你不再用单目标接受准则,效果就上来了。

3. 用户可以选自己的工作点。如果你只关心 raw 准确率,把 HVC 关掉(纯开发);如果你做的是后续要选用变体的 pipeline,把退火关掉(纯探索拿到丰富前沿);想要平衡就用默认。这个模块化是真挺好用的。

图4:消融热力图——每个 MOCHA 变体在 6 个任务上相对 GEPA 的 Δ correctness。TheoremQA 和 FEVER 提升最猛(+0.094 ~ +0.122),HotpotQA 几乎没有提升(这是种子已经在低水平的"低冲突"任务)。HoVer 在 w/o Annealing 下还退步了 -0.004,提示纯探索在某些任务上会牺牲准确率。

图4:颜色越绿表示提升越大。TheoremQA、FEVER、DebugBench 这三列普遍是亮绿色——这些都是"objective conflict 强"的任务,MOCHA 的设计正好对症。HotpotQA 那行几乎是红的(接近 0 或负),但这个任务的种子分数只有 .336,所以任何方法都能涨——选择策略反而不重要。

五、看看到底优化出了什么样的 skill

我一开始以为这种优化最后产出的就是"加几条 rule"那种简单变种,但 MOCHA 的进化树暴露出来挺细致的搜索行为。

图5:6 个任务上的 prompt 进化树(每个任务展示一个 seed 的运行)。每个节点是一个被 commit 进 pool 的 skill 变体,节点上的百分比是测试集准确率,蓝色节点是最终最优解,蓝色边是从 root 到最优的路径。

图5:注意 root 节点的 C/D/B 标签——比如 GPQA root 是 C=0.61, D=0.90, B=0.98(合规很好但准确率低),最优蓝节点 4 是 C=0.67, D=0.72, B=0.26——准确率涨了 6 个点,但 body compliance 从 0.98 跌到 0.26(body 被撑长了)。这就是非凸前沿的真实样子:你想要准确率,就得在 compliance 上让步,没有"啥都好"的解。

每棵进化树都揭示了MOCHA 接受了"局部最优看起来不优"的中间变体作为 parent——比如 HotpotQA 的最优蓝节点 2 是从 root 直接长出来的,而它的子节点 4-8 准确率都在 53%-55%,比 parent 低,但仍被纳入 pool(只要在某个方向上有 HVC 贡献就行)。这就是探索阶段的特征:允许某个维度退步,只要扩展了前沿

而基线方法的等价"进化树"就是一根直线——root 自己(或者 root → 一个 commit 然后 stop)。

六、几个我想要表达的批判性观察

聊点这篇论文我觉得没那么完美的地方,免得读起来像吹捧。

第一点:基线"完全不动"这个现象需要再多一层解释。论文给出的理由是单目标优化器在合规约束附近被卡死。这个解释直观,但我有点怀疑实验里基线的实现是不是"过于贪心"了——比如 TextGrad 和 ProTeGi 在标准实现里一般会维护一个候选 buffer,至少 keep 几个 second-best 候选用于扰动。如果这些被工程实现简化掉了,那"卡死"现象部分是被"严格的接受准则"放大的。作者声称所有方法 share 同样的 mutation 接口,但是否 share 同样的"候选 buffer / 扰动"机制,论文里没写得特别清楚。这块如果能再做一组对照——基线带 buffer vs MOCHA——会更扎实。

第二点:1024/5000 这两个数字带来的张力是 Anthropic 平台特有的。论文 limitation 里也承认了这点——换一个 SKILL 规范(比如其他厂商规定 description ≤ 512),整个 trade-off 形态会变。这意味着论文得到的"基线 4/6 卡死"这个数字不是普适规律,是特定约束 × 特定模型 × 特定任务下的现象。但反过来说,Anthropic 这套 SKILL.md 体系已经被业内广泛跟进,FAR-AI 和 Voyager 类工作都在沿用,所以这个特定场景的覆盖面也不算小。

第三点:HotpotQA 这个反例值得多说两句。在这个任务上 MOCHA(.600)反而被 ProTeGi(.622)压了一头,差距在一个 std 之内。论文给的解释是"低冲突任务"——种子分数只有 .336,加个简单的格式 prompt 就能涨 66%(.336 → .560)。我觉得这个观察很诚实,但同时它也说明 MOCHA 的多目标机器不是免费的——在低冲突任务上,搜索预算被分摊到"维持前沿多样性"上,反而拖累了 raw 准确率。这给实践带来一个问题:怎么提前判断一个任务是高冲突还是低冲突?论文 limitation 里也承认这是 open question,目前只能跑一会儿看看。

第四点:切比雪夫 + 退火不是新发明。多目标进化算法(NSGA-II、MOEA/D 这些)几十年前就有切比雪夫分解,HVC 也是 1999 年的东西。这篇论文真正的工作不在算法设计,而是把这套成熟工具搬到了 LLM prompt 优化这个新场景,并且发现搬过来居然这么必要。这种工作我个人挺喜欢的——它不是炫技的"我发明了一个新算法",而是"我发现这个领域还在用错的工具、换正确的工具就能涨这么多"。

七、对工程实践的几点启发

回到 SKILL.md 这个具体场景,如果你正好在做相关的事:

启发 1:多目标 selection 的门槛比想象中低。MOCHA 的核心算法换算成代码大概 200 行——切比雪夫得分计算、HV 计算(3 维下 \(O(n^2 \log n)\))、Dirichlet 采样、指数退火。你不需要拿出 NSGA-II 整套,只要在现有 prompt 优化器的 acceptance 步骤上换一个准则即可。

启发 2:mutation 阶段必须感知约束。论文里这个细节很重要:mutation prompt 里明确告诉 LLM "body 当前 6412 字符,超过了 5000 限制"。这样 LLM 在生成下一版时会主动压缩。如果 mutation 不感知约束,selection 再聪明也无济于事——选来选去候选都是越界的。

启发 3:保留一个候选 buffer 是普遍有用的事。MOCHA 用了大小为 K=5 的 priority queue 缓存"HVC 为正但还没达到 commit 阈值"的候选——等到某个候选超阈值就把整个 buffer 里 HVC 最高的 commit。这个 trick 干的事其实是把廉价的 mutation 评估和昂贵的 validation 解耦,避免每个候选都做完整 validation。这个工程优化在很多 prompt 优化场景都用得上。

启发 4:如果你的任务"低冲突",MOCHA 其实没什么用。先跑两三轮看看种子准确率离合规约束有没有顶撞——如果加几句简单 prompt 就能涨而不撑爆字段,那就用最简单的贪心优化器。MOCHA 的开销(多维 HV 计算、buffer 维护)在低冲突任务上是纯成本。

启发 5:a-posteriori 思维值得借鉴到更广的 prompt 优化场景。MOCHA 不强求"返回一个最好的 skill"——它返回整个帕累托 pool,让用户选。这种"最终决策权交还人类"的设计在 production 里其实很重要——因为你的部署偏好(要更准确还是要更省 token)会随场景变,预先 hardcode 一个 trade-off 不灵活。

八、收尾

读完这篇论文的整体感受是:它揭示了一个被广泛忽视的事实——大部分现有 prompt 优化器在面对真实平台约束时是失能的。这个失能不体现在"性能略差",而体现在根本不动。 6 个任务里 4 个完全卡死,这不是 marginal 的差距,是 categorical 的差距。

而解决这个问题的工具——切比雪夫标量化、HVC、退火——并不新,新的是把它们用对地方。这是我特别愿意看到的论文:不靠堆模型、堆算力、堆数据,靠理解问题的真实结构找到杠杆点。

如果你正在调任何一个有"多个硬约束 + 主目标"结构的优化任务(不只是 SKILL.md,也包括代理调度、tool 选择、检索 ranker 等等),这篇论文给的思路是值得抄一下的。最简单的做法:在你的 acceptance 准则上加一条切比雪夫接受 + 一个 HVC-based exploration buffer。这两点改动,不需要改 mutation、不需要换基础模型,可能就能从"原地踏步"切到"持续改进"。

最后,这篇论文也让我对未来一个方向更乐观——Agent 技能库不是手工艺品,是可以自动进化的系统。SKILL.md 这种结构化产物,相比单体 prompt 提供了更明确的"参数空间",让自动优化变成有迹可循的搜索问题。MOCHA 是这条路上的一个清晰节点:它告诉我们工具应该是什么样的。下一步当然是和 skill discovery(怎么自动决定该有哪些 skill)、meta-harness optimization(怎么优化 pipeline 结构本身)这些方向打通,那就是 end-to-end 的 agent skill evolution 了。


觉得有启发的话,欢迎点赞、在看、转发。跟进最新AI前沿,关注我