最近尝试用MCP协议微调一个轻量模型,想让它学会调用外部天气API。数据我按照官方示例整理了多轮工具调用记录,但微调后模型要么不触发tool_call,要么参数格式乱套(比如把location写成“北京”而不是“city:北京”)。
MCP微调时工具调用老是失败,是prompt写错了还是参数没对齐?
全部回复
共 2 条我也在试MCP微调,遇到类似的问题,感觉数据格式这块容易踩坑。你检查过tool_call的prompt模板里key和value的分隔符吗?我上次发现模型把location写成“北京”是因为思维链里没强制它输出json结构,加了个“请严格输出{“city”: “北京”}”的约束就好多了。你用的是哪种基座模型?
这问题我前段时间也踩过坑,折腾了好几天才跑通。说几点实战经验吧。
首先,工具调用的prompt格式其实比想象中敏感。MCP微调时,工具描述的写法直接影响模型能不能正确理解参数结构。你提到的“北京”和“city:北京”这个差异,大概率是训练数据里工具调用的格式没对齐。建议检查一下数据中每个tool_call的完整json结构,尤其是参数键名是不是和工具定义里完全一致。有时候模型会学习到训练数据里的习惯,比如你数据里如果混用了“location”和“city”作为键,它就会随机抽一个。
另外,微调时数据质量比数量重要。我之前用官方示例跑,发现它给的示例里工具调用往往是单轮且参数很简单,但实际场景多轮对话需要模型记住之前的上下文。如果数据里只有“用户问天气-模型调用工具-返回结果”这种直来直去的模式,模型很难学会在对话中间主动触发tool_call。建议在数据里多掺一些需要模型根据历史对话判断是否要调工具的例子,比如用户先问“今天热吗”,模型推断需要查天气再发起调用。
还有个小细节:训练时的损失函数权重。有些框架默认对工具调用token和普通文本token一视同仁,但其实工具调用的格式(比如json括号、逗号)对整体任务成败影响很大。可以试试在loss计算时对工具调用序列部分增加权重,或者干脆把工具调用的格式固定成类似chat模板的硬约束,减少模型自由发挥的空间。
最后,如果微调后模型完全不触发tool_call,先检查一下tokenizer对特殊标记的处理。MCP协议里工具调用通常有特殊标记,如果tokenizer没正确编码或者训练时被当成了普通文本,模型就学不会生成。可以单独打印一下模型生成的首个token概率分布,看看它是不是压根没把工具调用标记当成候选。