在大模型评测领域长程推理Long-Horizon Reasoning一直是最难量化的一类能力。普通问答可以直接比较答案代码生成可以运行测试用例但多步规划、多智能体协作、复杂工具调用这类任务最终结果正确不代表推理过程合理过程合理也不代表模型真正掌握了每一步所需的能力。近期提出的 Skill Entropy技能熵概念正是试图从“模型内部的技能分化程度”这一角度重新设计基准测试和训练目标。本文围绕这一方向说明技能熵解决什么问题、如何计算、如何用于评测与训练并提供一份最小可复现的工程示例和落地排查清单。技能熵的核心观察是一个长程推理任务通常由多个子技能组成比如信息抽取、条件判断、数值计算、路径规划。如果模型在完成这些子任务时总是依赖同一种表层策略那么它的技能结构是“低熵”的如果模型能够在不同子任务上调用不同能力并且不同能力之间的概率分布足够分化那么它的技能结构是“高熵”的。传统评测只关心最终正确率技能熵则关心正确率背后的技能结构是否健康。{ task: long_horizon_reasoning, steps: [parse_requirement, extract_entities, apply_constraints, compute_result, verify_result] }1. 为什么长程推理评测需要技能熵1.1 只看最终答案的两个盲区长程推理任务和普通单步问答最大的区别在于答案正确性无法覆盖推理质量。一个模型可能通过记忆常见题型的最终结果在评测集上拿到高分另一个模型可能推理步骤完全正确却在最后一步算错导致最终结果不一致。如果评测指标只看 accuracy两个模型会被区分开但无法解释差异究竟来自哪个环节。更隐蔽的问题出现在训练过程里。当模型在某个长程任务上持续掉点工程师需要知道是数据出了问题还是模型能力不够又或者是训练目标不合理。传统 loss curve 只能反映全局损失无法定位到具体子技能。Skill Entropy 的价值就在这里它把“整体正确率”拆成“不同技能维度的分化程度”让评测和训练都有了更细粒度的观测窗口。1.2 从任务级指标到技能级指标任务级指标是“这个任务有没有做对”技能级指标是“模型做完这个任务时内部到底调用了哪些能力这些能力是否得到了充分训练”。两者不是替代关系而是互补关系。指标类型典型指标回答的问题局限性任务级正确率Accuracy, F1, PassK任务结果是否正确无法定位失败环节步骤级正确率Step Accuracy每一步是否正确需要人工标注步骤成本高技能级指标Skill Entropy模型的技能结构是否分化需要定义技能分组和分布过程级评估Process Reward Model推理过程质量评分依赖过程标注模型容易过拟合Skill Entropy 属于技能级指标它不直接回答“哪里错了”而是回答“模型的各个子能力之间是否形成了合理的差异化结构”。这个概念在训练场景里尤其有用如果某个任务集合上所有子技能的熵值都很低说明模型可能只是在套用同一类模式而不是真正掌握了任务所需的多种能力。1.3 长程推理任务的典型结构为了说明技能熵的适用场景先定义一种抽象的长程推理任务结构。一个任务 T 由若干步骤 S1, S2, ..., Sn 组成每个步骤需要依赖一种子技能 K(Si)。例如步骤“解析用户意图”依赖intent_parsing步骤“抽取实体”依赖entity_extraction步骤“执行约束检查”依赖constraint_satisfaction步骤“生成最终答案”依赖response_generation传统模型训练时所有步骤的梯度都会加权累计到同一个模型参数上模型并不会显式区分“我当前正在使用哪种子技能”。技能熵要度量的正是模型在这些子技能上的行为分布是否足够区分。2. Skill Entropy 的概念与计算思路2.1 通俗理解技能熵信息论里的熵表示一个系统的不确定性或混乱程度。Skill Entropy 把“技能”当作随机变量把“模型在某个技能上的成功概率”当作分布然后计算这个分布的信息熵。如果模型在任务里几乎只靠一种技能其他技能都用不上技能的分布非常集中熵值接近 0。如果模型在各种技能上的表现都比较均衡但存在明显差异熵值会处在一个适中位置。如果模型在所有技能上表现完全相同例如全部随机猜熵值接近最大值但这种情况不代表模型强反而说明模型没有形成专门技能。所以技能熵不能单独当作“越高越好”的指标必须配合技能正确率一起看。正确率高且熵值适中是比较理想的技能结构正确率低但熵值高可能是技能没有分化正确率高但熵值极低可能是模型在走捷径。2.2 技能分组与步骤映射计算技能熵之前需要先完成两件事定义技能集合并把任务步骤映射到技能上。技能集合的粒度直接影响熵的含义。粒度太粗例如只分“推理”“生成”“检索”熵值没有区分度粒度太细例如把每一步都当作独立技能熵值会退化成步骤级正确率的简单函数失去“技能结构”的意义。推荐的做法是先看训练数据里的动作类型再按“完成同一类认知目标”归类。比如检索类文本召回、数据库查询、文档定位推理类条件判断、多步推导、类比迁移计算类数值运算、单位换算、逻辑表达式求值生成类摘要、改写、结构化输出校验类自检、纠错、结果验证一个长程任务往往横跨多种技能这也是它“长程”的原因之一。如果某个任务只依赖一种技能它本质上不具备长程推理的难度技能熵也就失去了分析价值。2.3 一种可参考的熵值计算方式原始论文中 Skill Entropy 的具体公式需要以论文原文为准但工程上可以用一种通用思路来实现把“模型在不同技能上的成功概率”构成一个概率向量再计算该向量的熵。import math from collections import defaultdict def compute_skill_entropy(skill_success: dict) - float: skill_success: {skill_a: 0.85, skill_b: 0.62, skill_c: 0.91} 返回技能熵单位是 nat也可以用 log2 换成 bit。 skills list(skill_success.keys()) if not skills: return 0.0 total sum(skill_success.values()) if total 0: return 0.0 probs [skill_success[s] / total for s in skills] entropy -sum(p * math.log(p) for p in probs if p 0) return entropy这个实现的关键是把“成功率”归一化成“概率分布”再计算熵。如果三个技能的准确率分别是 0.9、0.9、0.9概率分布是均匀的熵会比较高如果准确率分别是 0.98、0.5、0.02概率分布非常集中熵会比较低。实际使用中要注意这个公式只反映“相对分布”不反映“绝对水平”。两个模型可能技能熵完全相同但其中一个所有技能都接近 100%另一个所有技能都接近 30%。所以报告技能熵时必须同时报告平均技能正确率否则容易误读。2.4 熵值区间怎么解读平均正确率技能熵解读推荐动作高高技能分布均匀且水平高结构健康可以继续扩展任务难度高低模型依赖少数技能可能存在捷径检查数据是否单一、是否泄漏低高技能没有分化模型在“均匀地瞎猜”检查任务标注、步骤拆分、训练目标低低技能集中但水平低模型只学会一种能力补充多样化数据重新平衡训练集这个表格可以当作评测报告里的固定输出模块。每次跑完评测不应该只贴一个总准确率而应该附上这张技能结构表。3. 搭建一个最小技能熵评测脚本3.1 准备一份带步骤标注的评测集技能熵评测依赖步骤级或技能级标注。数据格式可以设计成这样[ { task_id: task_001, prompt: 用户需要预订周五晚上8点、2人、靠窗的餐厅并要求距离公司不超过3公里, reference: 查询餐厅 - 筛选距离 - 检查靠窗座位 - 确认预订, skills: [entity_extraction, constraint_search, decision_making, response_generation] } ]这里每个任务的skills字段就是技能级标注。它描述的是“完成这个任务需要哪些技能”不是“模型实际用了哪些技能”。3.2 让模型逐步输出再按技能分组统计实际评测时可以设定模型在完成长程任务时输出中间步骤。不需要强制模型说出“我正在调用 entity_extraction”只需要把模型每一步的输出和人工标注的技能对应起来。def evaluate_skill_success(predictions, ground_truths): predictions: [{task_id: ..., step_results: [True, False, True]}] ground_truths: {task_001: {skills: [entity_extraction, constraint_search]}} skill_stats defaultdict(lambda: {correct: 0, total: 0}) for pred in predictions: task_id pred[task_id] skills ground_truths[task_id][skills] for idx, is_correct in enumerate(pred[step_results]): if idx len(skills): continue skill skills[idx] skill_stats[skill][total] 1 if is_correct: skill_stats[skill][correct] 1 skill_success { skill: stat[correct] / stat[total] if stat[total] 0 else 0.0 for skill, stat in skill_stats.items() } return skill_success这里用step_results表示每一步是否正确。判断每一步是否正确可以使用规则校验、单元测试、结构化字段对比也可以让一个独立的判别模型打分。3.3 整合成完整评测函数def run_skill_evaluation(predictions, ground_truths): skill_success evaluate_skill_success(predictions, ground_truths) avg_success sum(skill_success.values()) / len(skill_success) if skill_success else 0.0 entropy compute_skill_entropy(skill_success) print(Skill success:, skill_success) print(Average skill success:, round(avg_success, 4)) print(Skill entropy:, round(entropy, 4)) return { skill_success: skill_success, avg_success: avg_success, entropy: entropy }运行后可能的输出Skill success: {entity_extraction: 0.92, constraint_search: 0.78, decision_making: 0.55, response_generation: 0.88} Average skill success: 0.7825 Skill entropy: 1.3321这个输出说明模型在实体抽取和回复生成上表现不错但在决策环节明显掉点技能熵也反映出技能结构不够分化。如果只看总正确率很可能因为其他步骤得分高而掩盖决策环节的问题。3.4 这一套脚本能用在哪些场景这套最小评测脚本可以用在三个地方评测多个候选模型看哪个模型的技能结构更健康。评测同一个模型的不同 checkpoint观察训练过程中技能熵的变化。评测同一个模型在不同 prompt 策略下的表现判断 prompt 是否把模型引导到了正确的技能使用路径上。在常见项目中这种脚本可以直接接入 CI 或者离线评测平台每次模型发布前都输出一份技能熵报告。4. 用技能熵指导长程推理训练4.1 把技能熵作为训练信号的约束项技能熵不只是评测指标也可以进入训练目标。思路是在标准语言建模损失之外加一个技能熵正则项引导模型在训练时不要把所有任务都压到同一种技能模式上。# 伪代码示例示意训练损失如何组合 loss lm_loss lambda * skill_entropy_regularizer这个约束项可以理解成当模型在同一个 batch 里表现出不同子技能时鼓励它继续保持这种分化当模型把所有样本都用同一种模式处理时增加惩罚。实际实现时最难的部分是“如何在训练过程中实时估计技能概率”。常见做法是给训练样本打技能标签然后在一个滑动窗口内统计模型对不同技能样本的损失差异。如果模型对某类技能样本的 loss 显著低于其他技能说明它已经过度拟合这类技能需要通过重采样或正则项拉回来。def skill_entropy_regularizer(loss_by_skill: dict) - float: loss_by_skill: {skill_a: 1.21, skill_b: 2.05, skill_c: 0.98} 返回值越小表示各技能上的损失越均衡。 values list(loss_by_skill.values()) mean sum(values) / len(values) variance sum((v - mean) ** 2 for v in values) / len(values) return math.sqrt(variance)这里用标准差作为正则项目标是让模型在不同技能上的损失不要差距过大。这样训练出来的模型不太容易“偏科”。4.2 用技能熵做课程学习课程学习Curriculum Learning的核心是给样本排序先学容易的再学难的。技能熵可以提供一个新的排序维度优先训练那些“技能熵较高”的样本让模型尽早接触多样化技能组合或者反过来先训练技能单一的样本等基础能力稳定后再训练多技能组合样本。def curriculum_sort(samples, keyskill_entropy, reverseFalse): return sorted(samples, keylambda x: x[key], reversereverse)关键点在于给样本预先计算技能熵。可以基于标注的技能数量、技能交叉程度、步骤数量计算一个近似值。技能种类越多、交叉越复杂通常技能熵越高。4.3 用技能熵做数据过滤数据过滤场景里技能熵可以识别“无效重复数据”。如果一批训练数据的技能熵都接近 0说明这批数据虽然在文本上不完全相同但认知结构非常单一。海量这样的数据只会让模型在少数技能上过拟合不能提升长程推理能力。过滤策略可以这样设计对全部训练数据做一次技能标注。按技能组合分组计算每组数据的占比。对占比过高且技能熵过低的组做降采样。对技能熵较高但数量不足的组做合成或补充。场景技能熵的作用典型用法评测对比判断模型技能结构是否健康每轮评测输出技能熵表训练正则防止模型偏科加入技能损失标准差正则课程学习控制训练顺序按样本技能熵排序数据过滤降低无效重复数据对低技能熵分组降采样checkpoint 选择决定保留哪个模型选正确率和技能熵综合最优的模型4.4 一个训练中技能熵变化的案例假设某模型训练了 10 个 epoch评测显示技能熵变化如下epoch 1 avg_success0.41 entropy0.95 epoch 3 avg_success0.63 entropy1.05 epoch 5 avg_success0.74 entropy0.98 epoch 7 avg_success0.80 entropy0.78 epoch 10 avg_success0.81 entropy0.71这里出现了一个典型现象正确率还在涨但技能熵开始下降。说明模型后段训练主要是在强化已经掌握的技能没有继续分化出新的技能结构。如果目标是拓展长程推理能力应该在技能熵开始下降时引入新的技能组合数据而不是继续训练同样的数据。5. 常见问题与排查路径5.1 步骤怎么拆才算合理步骤拆分最怕“每一步都拆成一句话级别”最后得到几百个步骤技能标签完全没法收敛。建议按“可独立验证”的粒度拆分。一个步骤应该对应一个可以单独判断正确或错误的子结果。例如“查询餐厅信息”是一个步骤“返回餐厅名称字段等于 xx”是另一个步骤。前者偏向行为描述后者偏向结果校验。如果拆完发现某个技能在所有任务里出现次数过多或过少就要回看数据分布。通常长程推理评测集的技能分布应该接近长尾少量核心技能高频出现大量辅助技能低频出现。5.2 技能熵一直趋近于 1 或一直趋近于 0问题现象常见原因检查方式处理建议熵值一直接近 0技能标签太粗所有步骤都归到同一个技能打印 skill_success 分布细化技能分组熵值一直接近最大值模型在大多数步骤上都是随机水平检查平均正确率是否偏低确认任务难度和数据质量不同 checkpoint 熵值波动大评估集样本量太小查看每个技能统计的样本总数增加评测样本或做多次采样熵值变化和正确率变化方向相反模型在走捷径或技能退化对比 bad case 的子技能分布补充针对性训练数据5.3 评测结果和人工判断不一致人工看一个长程推理输出时通常会综合“过程是否合理”和“结果是否正确”。技能熵只看按技能聚合后的统计概率两者天然存在差异。如果出现不一致先检查步骤是否正确。常见原因是模型输出步骤和人工标注步骤顺序不同导致步骤映射错位。解决办法是让模型输出结构化 JSON每步带step_id和description再由标注系统按step_id关联技能标签。{ task_id: task_001, steps: [ {step_id: 1, output: 公司附近3公里内共有5家餐厅}, {step_id: 2, output: 其中2家有靠窗座位}, {step_id: 3, output: 周五晚8点可预订的只有1家}, {step_id: 4, output: 推荐餐厅A已生成预订链接} ] }5.4 训练时加了技能熵正则但不收敛正则项权重 lambda 需要调。lambda 太大会压制正常语言建模损失导致文本质量下降lambda 太小约束效果不明显。建议先固定训练步数在 0.001、0.01、0.1 三个量级上各跑一组小实验观察技能熵变化和验证集 loss。另一个常见问题是技能标签噪声。训练时标签是从训练数据里推理出来的如果标签错误正则项实际上在惩罚正确的技能分化。建议在训练前抽 200 条样本人工校验技能标签准确率低于 90% 就先修正标注。5.5 技能熵在测试集上高但新任务泛化差这可能是因为评测集和训练集存在隐藏的任务结构相似性。技能熵高只是说明模型在已知技能分布上分化良好不代表它能泛化到没见过的新技能组合。验证方法是构造一个“新技能组合集”技能种类不在训练集中出现过的新任务。如果模型在新组合集上正确率明显下降说明技能熵指标还是停留在分布内评估需要进一步扩大评测集覆盖面。6. 最佳实践与工程落地清单6.1 学习环境与生产环境的差异学习环境下可以用小规模开源数据集和单人标注跑通技能熵流程。重点是理解“技能拆分 - 步骤映射 - 熵计算 - 结果解读”这个链路是否顺畅。生产环境还需要额外考虑技能标签怎么持续维护避免标注口径漂移。评测集多久更新一次防止模型在固定技能分布上过拟合。技能熵报告如何接入已有评测平台是否需要定时任务。多模型对比时技能集合是否对齐不能让每个模型用不同的技能定义。是否需要把技能熵做成线上监控指标观察模型上线后技能结构是否发生变化。6.2 技能熵落地检查清单检查项具体内容是否通过技能集合定义是否覆盖任务全部关键能力是/否技能粒度验证不同标注人员对技能分组是否一致是/否步骤映射规则模型输出能否稳定映射到技能是/否评测集样本量每个技能至少有多少条样本是/否指标报告是否同时输出 avg_success 和 entropy是/否训练正则lambda 是否经过小规模实验验证是/否泛化验证是否在技能组合外的新任务上验证是/否监控计划技能熵是否纳入版本发布对比是/否6.3 下一步可以扩展的方向技能熵作为一个评测和训练信号最值得扩展的三个方向是第一技能结构可视化。把每个模型的技能概率向量投影到二维平面观察不同模型在技能空间里的分布。这样可以直观判断模型是偏向某类技能还是覆盖均衡。第二自动技能发现。目前技能定义依赖人工标注成本较高。可以用无监督聚类对模型中间层表示做分析自动归纳模型实际使用的行为模式再和人工技能定义对齐。第三技能熵与强化学习结合。在 RLHF 或 RLAIF 流程中把技能熵作为奖励模型的一个特征鼓励模型在生成长程推理链时保持技能分化避免策略坍缩到单一的“高分模板”上。对新手来说最有价值的练习不是急着复现复杂公式而是先拿一个小型长程推理数据集手工标注技能分布跑通一遍技能熵计算然后观察模型在不同训练阶段的熵值变化。这个过程做完才能真正理解“模型答对题目”和“模型掌握技能结构”之间的差别。