最近在试MCP协议做模型微调,想用Function Calling能力让模型学会调用外部工具。但发现微调后,模型在复杂场景下老是把工具参数搞错,比如把 get_weather 的 city 参数填成 temperature 的值。
我用的开源模型基座是Qwen2.5-7B,训练数据是自己写的一些工具调用示例,大概500条,格式按MCP的tool schema写的。
想问下是不是数据格式有问题?还是得加一些随机负例?或者MCP的tool call本身有坑?求大佬指点。
用MCP微调模型时,工具调用总是跑偏,有人遇到吗?
全部回复
共 187 条500条确实偏少,而且工具调用这种任务光靠正例不够,模型很容易学到参数位置的表面模式而不是语义映射。建议掺一些参数错位或缺失的负例,让它学会区分不同字段的含义。另外检查下训练时tool schema是不是每次都以system prompt形式完整注入,有时候格式对但注入方式不一致也会跑偏。
500条确实有点少,尤其是工具调用这种结构化输出任务,模型很容易过拟合到表面模式。你提到的参数串位问题,我猜大概率是训练数据里参数顺序和schema定义的顺序不一致导致的,Qwen2.5对这种位置信息还挺敏感的。可以检查一下你每条样本里tool call的JSON是不是严格按schema的property顺序生成的,如果不是,模型可能学到的就是“第一个参数填第一个值”这种错误映射。另外MCP的tool schema里如果有嵌套对象或者可选参数,训练时最好显式保留或省略,别混着来,不然模型会懵。随机负例可以加,但重点不是让模型学会“不调用”,而是让它学会“参数名和值要对齐”,可以构造一些参数名和值故意错位的样本,label里纠正过来。还有个小技巧,微调时把tool schema作为system prompt的一部分拼进去,比只放在训练样本里效果更稳。你跑偏具体是在多工具选择时还是单工具参数填充时?如果是前者,可能还得补一些工具描述之间的区分度。
500条确实有点少,尤其是工具调用这种对参数边界特别敏感的任务,模型很容易学到表面的模式而不是真正的语义映射。我怀疑问题可能出在你的训练样本里不同工具的参数名有重叠或者语义相近,比如city和temperature都属于天气领域,模型在泛化时容易混淆。建议你检查一下数据里有没有出现过参数值被错误填充的负例,如果没有,加一些“错误示范+正确纠正”的对比样本会有帮助。另外Qwen2.5-7B本身对function calling的支持不是专门优化的,你可能需要看看它的chat template里工具描述是怎么拼接的,有时候schema的嵌套层级太深,模型会忽略字段名。我自己试过在微调时把工具调用拆成两步,先让模型选工具再填参数,效果比一步到位好不少。还有个小技巧是给每个参数加一个简短的描述前缀,比如“城市名:”,这样模型对齐起来更稳。MCP本身协议层没啥大坑,但它的schema格式如果字段顺序和训练数据不一致,也容易让模型犯迷糊。
我之前也遇到过类似问题,后来换了方案。
我之前也遇到过类似问题,后来换了方案。
500条确实有点少,尤其是Qwen2.5-7B这种体量的模型,微调时很容易把参数名和参数值搞混,本质上是它还没真正建立起“字段名→语义槽位”的映射,只是在模仿格式。你观察到的city填成temperature的值,很像是训练数据里参数顺序或模板太单一,模型学到了位置捷径而不是字段语义。建议先检查一下你的tool schema在样本里是不是每次都一模一样地出现,如果顺序固定、措辞固定,模型很容易过拟合到表面模式。加负例是有用的,但别只加随机负例,最好构造那种“参数名对但值错位”的hard negative,让模型学会区分槽位边界。另外MCP本身在tool call这块没有特别大的坑,主要是schema描述要足够清晰,字段的description别写太泛。可以试试把工具调用拆成两步训练,先让模型输出要调哪个工具和参数名,再填值,减少一次性生成的耦合。还有个小经验是学习率别太高,7B模型微调function calling很容易把通用能力带崩,跑偏有时候是灾难性遗忘的表现。
有没有更详细的教程推荐?