一个尴尬的场景
想象你是一个资深工程师,手下有个实习生叫小 G。小 G 脑子很聪明,但记不住流程细节,所以你给他写了一本"操作手册"——什么时候该查哪个数据库、什么时候该调用哪个工具、什么时候该跳过哪一步。
某天小 G 在一个问答任务上翻车了。你翻看他的执行日志,发现问题出在第三步:他该查"巴拿马法院 1993 年定罪的领导人",却答了 Manuel Noriega 而不是标准答案 Noriega。
这时候你会怎么做?
A. 把操作手册重写一遍
B. 在手册里加一条"遇到人名时用简称"
C. 修一下评分器,让它能识别别名
D. 什么都不改,因为这是评分器的问题
如果你选了 A 或 B,恭喜,你正在犯当前大多数 LLM 技能优化系统都在犯的错。
问题的根源:失败不等于"该改技能"
南京大学的 SkillAA 团队(尚子乔、葛凌越、郭兰哲)发现了一个被忽视的问题:当前所有"技能进化"系统都在用"失败 → 改技能"的单一映射,但真实场景里失败的原因五花八门——可能是技能写错了,可能是检索没找到关键证据,可能是模型视觉识别错了字符,甚至可能只是评分器太严格。
把所有失败都归因于"技能有问题",就像把所有 bug 都归因于"代码写错了"——有时候是硬件故障,有时候是数据缺失,有时候是需求文档自相矛盾。盲目改代码只会越改越坏。
SkillAA 的核心贡献,就是给"技能优化"这件事装上了一套精准归因 + 定向修复 + 闸门验证的工程化流水线。
核心设计:把技能变成"有地址的图"
SkillAA 的第一个关键决策,是把技能从一段段平铺的文本,变成一张有地址的有向图。
每个节点不是一坨自然语言描述,而是被拆成三个结构化字段:
- when_to_use:什么时候该用这个技能(触发条件)
- how_to_use:具体怎么执行(步骤序列)
- avoid:什么时候不该用(排除边界)
节点之间用带类型的边连接,比如 prereq(前置依赖)、enhance(增强组合)。
这个设计的好处是什么?每个可编辑的位置都有了地址。就像代码库里的 src/auth/login.py:42——当 bug 出现时,你能精确指向"就是这一行这个函数这个分支",而不是"整个登录模块重写一下"。
这就是 SkillAA 名字里 "Attribution"(归因)的真正含义:不是笼统地说"技能有问题",而是定位到具体哪个节点的哪个字段。
六条归因路径:失败也有分类学
SkillAA 最有洞察力的设计,是定义了六条归因路径。当一次执行失败时,teacher 模型会对照执行记录诊断,把失败归入以下六类之一:
| 归因码 | 失败条件 | 授权的修改 |
|---|---|---|
| MISSING_SKILL_FAMILY | 缺少整个技能 | 新增节点 + 绑定边 |
| MISSING_ACTIVATION_CUE | 技能存在但没被激活 | 只扩展 when_to_use |
| HARMFUL_EXISTING_RULE | 现有语义导致错误 | 只替换出问题的字段 |
| MISSING_OR_INCORRECT_PROCEDURE | 步骤/边界/关系缺失 | 补全 how_to_use 或 avoid |
| EXECUTION_LAPSE | 图是对的,但模型没按图执行 | NO_PATCH(不改图) |
| INSUFFICIENT_EVIDENCE | 证据不足以定位 | NO_PATCH(保留原图) |
注意最后两行。NO_PATCH 是 SkillAA 的一等公民输出——当诊断发现"图是对的,是模型执行走样了"或者"证据不够,定位不到具体字段"时,正确做法是什么都不改。
这个设计看似简单,实则深刻。当前所有技能进化系统都隐含一个假设:"失败了就该改点什么"。SkillAA 用 NO_PATCH 明确否定了这个假设——有些失败不是技能的锅,强行改图只会把好的技能改坏。
两道闸门:像数据库事务一样管理技能修改
定位到该改哪里、提出了候选修改之后,SkillAA 不会直接提交。它设了两道闸门,像数据库的事务隔离机制一样层层把关。
Local Gate:局部回归测试
第一道闸门是局部级的。对于每个候选修改(或一组相互依赖的修改,称为 atomic group),SkillAA 只重跑可能受影响的用例:
- 这个节点被哪些用例用过?(
Q_use) - 修改的源头是哪些用例?(
Q_src) - 用例记录缺失的也纳入(
Q_unk)
重跑后统计三个数:
n_fixed:原来错的现在对了n_broken:原来对的现在错了n_unresolved:原来错的还是错的
只有当 n_fixed > n_broken + n_unresolved 时,这个修改才被保留。否则,整个 atomic group 回滚——节点字段恢复原值,新增的节点和边一起撤销。
这就像数据库的行级约束:改了一行,先检查所有相关行的一致性,不一致就回滚。
Big Gate:epoch 级提交
第二道闸门是epoch 级的。所有通过 Local Gate 的修改合并成一个候选图 \(\tilde{G}^{(t+1)}\),在整个 update pool 上跑一遍:
n_corrected:原来错的现在对了n_regressed:原来对的现在错了
只有 n_corrected > n_regressed 时,才提交这个候选图作为新的基准。否则,图和参考执行记录都恢复到 epoch 开始前的状态。
这就像数据库的 COMMIT:所有局部修改通过了行级约束还不够,整个事务必须让全局指标净正向才能提交。
关键实验:不是所有失败都是"图能修的"
SkillAA 在三个 benchmark 上验证:SearchQA(问答)、LiveMath(数学)、DocVQA(文档视觉问答)。用 gpt-5.6-sol 作为 student 和 teacher,三个 epoch 后:
- SearchQA:81.5%
- LiveMath:66.7%
- DocVQA:91.2%
在九个 model-benchmark 组合上,SkillAA 都取得了最高点估计值。但更有意思的不是这些数字,而是两个"负面"结果。
负面结果一:ALFWorld 上改图反而变差
在 ALFWorld(一个交互式家庭任务环境)上,所有方法在 100 步内都能 100% 完成。但在 50 步的紧预算下,初始技能反而是最好的——SkillAA 改了图之后,成功率反而从 95.5% 掉到 92.5%。
这是一个反直觉但极其重要的发现:当初始技能已经足够支撑任务,剩余失败来自探索或执行时,改图不仅没用,还会帮倒忙。
这就像一个已经写对的函数,你硬要"优化"它,结果引入了 bug。知道什么时候不改,和知道改什么一样重要。
负面结果二:残差错误审计
团队手动审计了六个 held-out 上的错误,发现它们需要四种完全不同的修复:
- 评分器问题:模型答 Manuel Noriega,标准答案 Noriega——该修评分器,不是改技能
- 证据缺失:检索没找到"第一任国务卿"的"第一"——该改检索,不是改技能
- 定理识别错误:数学定理选了相关但非等价的——该加领域知识库,不是改技能
- 视觉识别错误:手写日期 7/18 看成 11/18——该加 OCR 交叉验证,不是改技能
六个错误里只有一个是真正的技能缺陷(role selection),而且因为只出现一次,连这个都不够格做持久化修改——需要同类错误反复出现才能确认是系统性技能缺陷。
这个残差审计是整篇论文最有工程价值的部分。它告诉我们:"答错了"不等于"技能错了"。把所有错误都塞给技能系统,就像把所有系统故障都塞给应用层——数据库慢了改应用代码,网络抖了改应用代码,硬件坏了改应用代码。
工程洞察:三件事比"改技能"更重要
综合 SkillAA 的设计和实验,有三个工程洞察值得所有做 agent 系统的人记住。
洞察一:把技能变成"有地址的空间"
从"一段技能文本"到"一张有节点字段和类型边的图",不只是表示形式的升级,而是把技能从"可读文档"变成了"可寻址的代码库"。
没有地址,你只能说"这个技能有问题"。有地址,你可以说"节点 #7 的 when_to_use 字段缺了第 3 个触发条件"。前者无法做定向修复,后者可以。
这和软件工程的演进一模一样:从"改这个文件"到"改这个函数的这一行"到"改这个分支的这一个 commit"。粒度越细,修复越精确,回滚越干净。
洞察二:NO_PATCH 是一等公民
当前所有技能进化系统都在追求"改得更多、改得更好"。SkillAA 反其道而行,把"不改"提升到和"改"同等重要的地位。
这不是保守主义,而是对失败原因多样性的尊重。当失败可能来自检索、感知、推理、执行、评分器中的任何一个环节时,把所有失败都塞给技能系统,就像把所有疾病都开抗生素——不仅治不好病毒感染,还会制造超级细菌。
SkillAA 的 NO_PATCH 路径,相当于给技能系统装了一个"分诊台":先判断这个失败是不是技能能修的,不是就转诊到其他组件。
洞察三:两道闸门 = 事务化技能管理
Local Gate + Big Gate 的设计,本质上是把数据库事务管理的思路搬到了技能优化上:
- Local Gate = 行级约束(修改不能破坏局部一致性)
- Big Gate = 事务提交(整个 epoch 的修改必须让全局指标净正向)
这个设计解决了一个长期被忽视的问题:技能修改的副作用。改了一个技能,可能修好了 A 任务但搞坏了 B 任务——以前没人检查这个。SkillAA 的 Local Gate 专门抓这种回归。
一个更深的洞察:什么时候该改图,什么时候该换模型
论文最后提出了一个我非常喜欢的框架:graph-addressable vs capability-limited failures。
- Graph-addressable failure:技能图里某个字段或边有明确缺陷,改了就能修好
- Capability-limited failure:技能图是对的,但模型本身能力不够(推理、感知、执行)
当 epoch 级别的修改开始反复被 Big Gate 拒绝时,这是一个停止信号——不是模型能力到顶了,而是"图能修的都修完了,剩下的得靠改模型"。
未来的系统应该交替进行:改图修 graph-addressable 的失败,改模型修 capability-limited 的失败,两者迭代推进。这就像软件迭代:先优化算法(改图),再升级硬件(改模型),循环往复。
对步子哥们的启示
如果你在做 agent 系统、在用 skill 或 prompt 管理任务流程,SkillAA 给了三个直接可用的思路:
-
给你的 skill 加地址:不要把 skill 写成一坨 markdown,拆成 when_to_use / how_to_use / avoid 三个字段,用图结构管理依赖关系。这样失败时你能定位到具体字段,而不是"重写整个 skill"。
-
设两道闸门:改 skill 之前先问"这个修改会影响哪些已通过的 case",改完之后跑一遍回归测试。全局指标净正向才提交,否则回滚。这比"改了就上线"靠谱十倍。
-
学会说 NO_PATCH:不是所有失败都该改 skill。先诊断失败原因——是触发条件没命中?步骤错了?还是模型本身能力不够?前两者改图,后者改模型(或换更大的模型)。把"不改"作为合法输出,能避免大量无效修改。
开源代码
论文配套代码已开源:https://github.com/Ziqiao-Shang/SkillAA
仓库包含图优化器、Gate 实现、benchmark 数据准备脚本、以及完整的 per-example 预测记录。用 gpt-5.6-sol 作为 student/teacher,三个 epoch 就能复现主表结果。终端图(SearchQA 30 节点 8 边、LiveMath 37 节点 40 边、DocVQA 20 节点 19 边)也已发布,可以直接用来做 inference-only 的消融实验。
论文信息
- 标题:SkillAA: Attribution-Guided Skill-Graph Updating with Targeted Validation and Rollback
- 作者:Ziqiao Shang, Lingyue Ge, Lan-Zhe Guo(南京大学)
- arXiv:2609.20455
- 代码:https://github.com/Ziqiao-Shang/SkillAA
个人思考:SkillAA 最让我欣赏的不是它的数字,而是它对"失败"的尊重。当前 AI 圈的技能进化系统都在追求"改得更多更快",但真正成熟的工程系统知道——知道什么时候不改,比知道改什么更难也更重要。这和软件工程里"不要为了修 bug 而引入 bug"是同一个道理。
NO_PATCH 作为一等公民输出,这个设计哲学值得所有做 agent 自进化的团队借鉴。不是所有失败都是技能的锅,承认这一点,技能系统才能真正可靠。
讨论回复
加载中...正在加载回复...
推荐
智谱 GLM-5 已上线
我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。