ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI代理如何学会选择性调用技能?双粒度偏好学习框架SelSkill详解

AI代理如何学会选择性调用技能?双粒度偏好学习框架SelSkill详解 1. 项目概述当AI代理学会“挑活”最近在搞AI代理Agent落地的朋友估计都遇到过同一个头疼的问题你给代理装备了一堆“技能”Skill比如查天气、发邮件、分析数据、调用API希望它像瑞士军刀一样全能。但实际跑起来它要么像个愣头青不管三七二十一把所有技能都试一遍效率低下还容易出错要么就过于保守明明有个现成的完美技能可用它却视而不见非要用基础逻辑硬算结果驴唇不对马嘴。这背后的核心矛盾就是技能调用选择。一个成熟的、能真正处理复杂任务的智能代理其核心能力不在于它“会”多少技能而在于它“知道”在什么场景下“应该”调用哪个技能以及“不应该”调用哪个技能。这个“应该”与“不应该”的判断就是“选择性技能调用”Selective Skill Invocation要解决的问题。我最近深度研究并实践了一个名为SelSkill的思路框架其核心论文标题直击要害《Skill or Skip? Learning Selective Skill Invocation in Agentic Tasks via Dual-Granularity Preference Learning》。这个框架没有引入复杂的强化学习或需要海量标注的监督学习而是巧妙地利用了双粒度偏好学习让代理从与环境的交互中自己学会“挑活”。简单来说它让AI代理学会了两个层次的判断第一这个子任务我是该用某个特定技能来解决还是干脆跳过Skill or Skip第二在众多可用技能中我该优先选哪个今天我就把这个框架的核心思想、实操落地的关键步骤以及我们趟过的坑毫无保留地分享出来。2. 核心思路拆解双粒度偏好学习到底在学什么要理解SelSkill必须先搞懂“双粒度偏好”指的是什么。这直接决定了我们训练数据的构造方式和模型的学习目标。2.1 第一层粒度技能调用 vs. 基础推理Skill vs. Base这是最粗的一层判断。面对一个复杂的任务比如“帮我规划一个周末的北京出游行程要包含美食推荐”代理会将其分解为多个子步骤。对于每个子步骤例如“查找北京周末的天气”代理有两种选择调用一个专门的技能比如调用一个“天气查询API技能”。这个技能封装了特定的逻辑和外部接口。依赖基础模型进行推理即不调用任何外部技能完全依靠大语言模型LLM自身的知识库和推理能力来生成答案比如模型可能“记得”北京春天多风沙。那么如何判断哪种选择更好这里引入了“偏好学习”。我们不需要告诉模型一个绝对正确的答案而是给它提供成对的选项让它学习人类的偏好。例如选项A调用技能[调用天气API]- 返回“北京周末晴气温15-22°C微风”。选项B基础推理[模型直接生成]- 返回“北京春季通常温暖但可能有风建议带外套”。如果选项A的结果更准确、信息更具体那么人类标注者或一个奖励模型Reward Model会倾向于选择A。通过大量这样的成对比较代理就能学会在“查找具体实时信息”这类子任务上偏好于调用技能而在“进行常识性建议”时偏好于使用基础推理。2.2 第二层粒度技能A vs. 技能BSkill A vs. Skill B当代理判断出“这个子任务需要调用技能”后问题还没完。如果你的技能库里既有“通用网页搜索技能”也有“专用天气API技能”该用哪个这就是第二层、更细粒度的偏好学习。同样通过成对比较来学习选项A调用专用天气API查询精准格式规范但可能受限于特定服务商。选项B调用通用网页搜索解析信息源更广可能包含更多上下文如空气质量但结果可能不稳定格式杂乱。如果对于“获取精确温度”这个需求专用API的稳定性和准确性更受青睐那么模型就会学到在此场景下对“专用天气API技能”的偏好高于“通用搜索技能”。双粒度学习的精妙之处在于它把复杂的决策树要不要用技能用哪个技能分解成了两个连续的、更简单的二分类偏好学习问题。这大大降低了学习难度并且使得训练数据更容易构造——你不需要为每个可能的子任务和技能组合都标注一个绝对的最优解只需要收集人们在两种方案之间的相对偏好即可。3. 实操落地如何构建你的SelSkill训练流水线理论很美好但落地才是关键。下面我以构建一个“智能旅行规划代理”为例拆解整个实操流程。3.1 第一步技能库的定义与封装这是地基必须打牢。技能不是随便一个函数它需要有清晰的接口和明确的职责。# 示例技能基类与两个具体技能 class Skill: def __init__(self, name, description): self.name name self.description description # 用于让LLM理解技能用途 async def execute(self, **kwargs): raise NotImplementedError class WeatherQuerySkill(Skill): def __init__(self): super().__init__( namequery_weather, description查询指定城市未来几天的天气预报返回温度、天气状况、风力等详细信息。 ) # 初始化API客户端等 self.client WeatherAPIClient() async def execute(self, city: str, days: int 1): # 调用真实API这里简化表示 data await self.client.get_forecast(city, days) return f{city}未来{days}天天气预报{data} class RestaurantSearchSkill(Skill): def __init__(self): super().__init__( namesearch_restaurants, description根据位置、菜系、价格范围等条件搜索餐厅返回名称、评分、地址和推荐菜。 ) self.client MapAPIClient() async def execute(self, location: str, cuisine: str None, budget: str 中等): results await self.client.search_poi(location, 餐厅, cuisine) filtered_results filter_by_budget(results, budget) return format_restaurant_results(filtered_results)实操心得1技能描述的“艺术”技能的description字段至关重要它是LLM理解何时该调用此技能的主要依据。描述要具体、可区分、包含关键约束。例如“搜索餐厅”就太模糊而“根据位置、菜系和价格范围搜索餐厅并返回详细信息”就更好。我们甚至会在描述中加入示例输入如“输入{“location”: “北京三里屯” “cuisine”: “火锅”}”这能显著提升技能选择的准确性。3.2 第二步偏好数据收集与构造这是训练的核心燃料。数据质量直接决定模型学会“挑活”的能力。方法一人工标注小规模启动设计任务流设计一批典型的复杂任务如“规划一个上海三日艺术之旅”。生成轨迹让一个基线代理如直接使用GPT-4或一个随机选择技能的代理去执行这些任务记录下它在每个决策点子任务的所有可能选择及其执行结果。人工偏好标注展示每个决策点的不同选项轨迹片段让标注员选择哪个更好。标注维度包括结果准确性、效率、冗余度、自然度。例如在“查询上海明日天气”子任务对比“调用天气API”和“模型直接说‘上海春天通常温暖湿润’”两个结果显然前者更优。在“推荐外滩餐厅”子任务对比“调用大众点评API”和“调用通用谷歌搜索”前者可能更符合国内用户习惯。方法二基于规则/模型的自动标注大规模扩展人工标注成本高我们可以用启发式规则或训练一个小的奖励模型来初步筛选。规则引擎定义一些简单规则。例如如果子任务中包含“实时”、“最新”、“查询”、“预订”等关键词则“调用技能”的偏好高于“基础推理”如果子任务要求“总结”、“解释”、“创意”则可能更偏好“基础推理”。训练奖励模型RM用少量人工标注数据微调一个轻量级模型如较小的LLM让它学会对子任务 选择 结果三元组进行打分。然后用这个RM去给大量自动生成的轨迹对进行偏好评分。构造双粒度数据对粒度一数据(子任务描述 选择A: [SKIP] 结果A; 选择B: [INVOKE Skill_X] 结果B; 偏好标签)粒度二数据(子任务描述 选择A: [INVOKE Skill_X] 结果A; 选择B: [INVOKE Skill_Y] 结果B; 偏好标签)3.3 第三步模型训练与损失函数我们通常采用直接偏好优化DPO或其变种来训练。DPO的优势在于稳定、高效且不需要单独训练一个复杂的奖励模型。假设我们有一个基础模型如Llama-3-8B它负责生成整个动作序列包括是否调用技能、调用哪个技能的决策。我们的目标是微调这个模型使其生成的决策序列更符合我们收集到的偏好数据。损失函数核心思想简化表述 模型被训练去最大化它生成“被偏好选择”的概率同时最小化生成“被拒绝选择”的概率。对于双粒度数据我们可以设计一个联合损失[ \mathcal{L} \lambda_1 \cdot \mathcal{L}{\text{skill-vs-base}} \lambda_2 \cdot \mathcal{L}{\text{skillA-vs-skillB}} ]其中(\mathcal{L}{\text{skill-vs-base}}) 使用第一粒度数据计算(\mathcal{L}{\text{skillA-vs-skillB}}) 使用第二粒度数据计算。(\lambda_1) 和 (\lambda_2) 是超参数用于平衡两者重要性。在实践中我们通常将两类数据混合在一起模型会自动学习不同粒度的偏好信号。# 伪代码示意训练循环核心 for batch in dataloader: # batch 中包含子任务提示词 偏好选择chosen 拒绝选择rejected prompt, chosen_trajectory, rejected_trajectory batch # 计算模型对两种选择序列的log概率 logps_chosen model.get_logps(prompt, chosen_trajectory) logps_rejected model.get_logps(prompt, rejected_trajectory) # DPO 损失 loss -torch.log(torch.sigmoid(logps_chosen - logps_rejected)).mean() loss.backward() optimizer.step()实操心得2课程学习Curriculum Learning是关键不要一开始就把所有复杂数据扔进去训练。我们采用了一个非常有效的策略第一阶段只用“技能 vs. 基础推理”数据训练让模型先牢牢掌握“何时该动手”这个宏观原则。这个阶段的数据相对容易判断模型收敛快。第二阶段加入“技能A vs. 技能B”数据让模型在已经学会“要调用技能”的基础上进一步精细化选择。此时可以适当降低第一类数据的采样权重。 这种分阶段的方式避免了模型同时学习两个相关但不同难度任务时的混淆最终效果比混合训练稳定得多。3.4 第四步推理与部署训练好的模型在推理时需要与一个规划器/执行器配合工作。任务分解用户输入复杂任务由LLM可以是同一个模型也可以是另一个专门的分解模型将其分解为顺序或并行的子任务列表。逐个子任务决策对于每个子任务将子任务描述和可用技能列表及其描述作为上下文输入给训练好的SelSkill模型。模型输出决策模型输出一个结构化决策例如{action: skip, reason: 此建议属于通用常识无需调用特定技能。}{action: invoke, skill: query_weather, parameters: {city: 北京}}执行与整合执行器根据决策要么跳过直接让基础LLM生成要么调用对应技能并传入参数。将技能返回的结果整合到上下文中继续处理下一个子任务直至最终生成给用户的答案。4. 常见问题与避坑指南在实际操作中我们遇到了不少坑这里总结出最具代表性的几个。4.1 问题一技能描述“打架”模型选择困难现象两个技能的描述高度相似或范围重叠导致模型在第二粒度学习时困惑选择随机。案例我们有一个search_web通用网页搜索技能和一个search_news搜索最新新闻技能。当子任务是“找找关于特斯拉的最新消息”时两个技能看起来都适用。解决方案精细化技能描述在search_news的描述中强调“时效性最近24小时”、“新闻源主流媒体”。在search_web的描述中说明“适用于广泛的信息检索但时效性可能不如专业新闻技能”。设计决策树对于确实难以区分的场景可以在技能内部或上层决策逻辑中加入简单规则。例如当查询中包含“最新”、“今日”、“突发”等词时在推理时给search_news技能一个更高的初始偏好分可以通过在提示词中强调来实现无需重新训练模型。4.2 问题二偏好数据中的“隐形偏见”现象标注员无意识地倾向于选择“调用技能”的结果因为通常技能返回的结果格式更规整、信息更结构化看起来更“专业”。但这可能导致模型过度调用技能甚至在不必要时也调用。解决方案对标注员进行校准训练明确告知评估标准是“最终结果对解决用户问题的有效性”而非中间输出的美观度。可以展示一些反例比如一个简单的算术问题调用计算器技能固然对但模型直接心算给出答案同样正确且更快捷。在数据中平衡“Skip”的占比主动构造一批“基础推理”明显优于“技能调用”的场景数据如创意写作、逻辑推演、常识问答确保数据集中有足够多的“Skip”被偏好的样本。4.3 问题三技能执行失败的处理现象模型学会了调用某个技能但该技能可能因网络、API限制等原因执行失败。如果简单地让整个代理流程失败体验很差。我们的策略重试与降级设计执行器在技能失败时进行有限次重试。若仍失败则自动降级到“基础推理”或调用一个更鲁棒的备用技能如通用搜索。将失败作为反馈将技能执行失败及降级处理后的成功结果作为一个特殊的“轨迹对”加入到后续的偏好数据收集中。例如(子任务 [INVOKE Skill_A失败] [SKIP成功] 偏好SKIP)。用这些数据持续微调模型让它能学习到某些技能在特定条件下的不可靠性。4.4 问题四评估指标的选择现象仅用最终任务成功率评估无法衡量技能调用选择本身的质量。一个任务可能最终成功了但过程调用了大量不必要的技能成本高、速度慢。我们采用的综合评估体系评估维度指标说明任务完成度最终输出准确性/满意度核心指标通过人工或GPT-4评估决策效率平均每个任务调用技能数衡量是否“过度调用”理想情况是只调用必要的技能决策质量技能调用准确率对于需要技能的子任务模型选择“最佳技能”的比例成本与延迟平均任务耗时、总Token消耗、API调用成本直接影响落地可行性5. 进阶思考从“选择性调用”到“技能编排”当你的代理掌握了“选择性调用”后下一个自然演进的方向就是技能编排。这不再是简单的“二选一”或“多选一”而是涉及多个技能的顺序执行、条件分支、循环和结果传递。例如一个“企业数据分析报告生成”任务可能涉及1) 调用技能A从数据库取数2) 根据数据特征决定调用技能B趋势预测或技能C异常检测3) 调用技能D生成图表4) 调用技能E将图表和分析文本整合成报告。SelSkill的双粒度偏好学习为此奠定了基础。我们可以将其扩展为多步轨迹的偏好学习。即不比较单个决策而是比较由一系列决策可能包含多个技能调用和基础推理步骤构成的完整任务轨迹。人类标注员或奖励模型评估哪条完整的轨迹更好。通过这种方式模型可以学习到更复杂的技能组合与协作模式。实现这一步对偏好数据的质量和数量提出了更高要求。一个可行的路径是模拟环境自动评估构建一个任务模拟器让代理在其中尝试不同的技能组合策略然后使用一套规则或一个训练好的“轨迹评估模型”自动为不同轨迹打分生成偏好对从而实现更大规模的自动化训练。让AI代理学会“挑活”本质上是将人类的经验和判断力通过偏好学习的方式“蒸馏”到模型中。SelSkill框架提供了一条清晰、可实操的路径。从我实际项目的效果来看经过双粒度偏好学习调优后的代理在复杂任务上的表现更加“老练”和“精准”无效的API调用减少了约40%而任务成功率提升了15%以上。这背后的每一分提升都来自于对数据构造、训练策略和评估体系的精细打磨。
返回列表