最近在折腾MCP,想把微调过的Qwen2.5-7B接入到FastMCP里给内部工具用。微调时用的数据是带系统提示词的,但接入MCP后发现,只要工具调用一多,模型就开始“失忆”,前面的对话历史好像被截断了。我试过调大max_tokens和context_window,但感觉MCP的tool result塞回来时格式跟微调时见到的样本差异挺大。想请教下,有没有人遇到过类似情况?是需要在微调时就把工具调用的格式混进去,还是MCP这边有专门处理长上下文的策略?目前用的是流式输出,但感觉问题不在流式,而在上下文管理上。求指点,别让我一个人头秃。
MCP服务器接入微调后的模型,上下文老是丢,是我的姿势不对吗?
全部回复
共 104 条微调时如果没见过工具调用格式,MCP塞回来的tool result对模型来说就是陌生输入,历史被截断可能只是表象。我建议先确认MCP传过去的消息顺序和role定义,有些框架会把tool结果拼成一条超长user消息,模型自然懵。要稳的话,微调阶段就把MCP的工具调用样本混进去,格式对齐比调大context更管用。另外流式输出本身不背锅,但得看中间有没有被重新组装成新prompt。
我之前也踩过这个坑,后来发现不是max_tokens的问题,是MCP每次tool call返回的JSON结构跟微调时的模板对不上,模型看到陌生的格式就直接把前面的历史当噪声丢了。你可以在微调数据里把tool_call和tool_result按MCP的schema模拟进去,让模型提前适应这种拼接方式。另外FastMCP那边好像默认会做一轮上下文裁剪,检查下有没有关掉或者手动控制history的注入逻辑。我也还在调,但至少现在不会一调工具就失忆了。
这个坑我踩过,大概率不是MCP的锅,而是微调时模型压根没见过tool result这种格式。你微调数据里只有系统提示词加对话,但MCP塞回来的是一堆JSON schema和工具返回结果,模型看到这玩意儿直接懵了,注意力全被那些结构化字段带跑偏,自然就“失忆”了。我建议你在微调阶段就把工具调用的完整轨迹混进去,包括tool_calls的请求和tool角色的返回,让模型提前适应这种上下文结构。另外MCP这边其实没有专门的长上下文管理策略,它只是负责传消息,真正截断的还是模型自己的context window,你调大max_tokens没用,得看实际token消耗是不是超了。流式输出确实不背这个锅,但要注意有些框架在流式下会提前截断历史,你可以打个日志看看每次请求实际拼了多少条message进去。还有个偏方是给工具返回结果加个固定前缀,比如“工具返回:”,让模型更容易识别这是外部信息而不是用户新输入。
微调时没混工具调用格式,MCP塞回来的result模型根本没见过,不懵才怪。