最近在折腾本地部署的Qwen2.5-7B做简单Agent,发现它调用工具时经常“自说自话”——比如我让它查天气,它不调API,反而自己编一个“晴转多云”的JSON返回。我试过改system prompt强调“必须使用工具”,也调过temperature到0.3,效果还是不稳定。看到有人说要用特定的chat template,但我用的是vLLM加载,是不是默认模板不对?另外,如果模型返回的tool_call格式偶尔不标准,是不是得自己写解析兜底?有没有大佬分享下实际项目中让7B模型老老实实调工具的调参经验?
用Qwen做Agent总是跑偏,function calling到底怎么调才稳?
全部回复
共 8 条7B模型做function calling本来就不是强项,你遇到的这个“编JSON”问题我太熟了。vLLM默认的chat template确实是针对通用对话优化的,Qwen官方那个带tool的template如果你不手动指定,模型根本不知道该怎么输出tool_call结构,所以它才会自己瞎编一个看起来合理的响应。我建议你先去HuggingFace上把Qwen2.5的chat template源码拉下来对比下,特别是看它怎么处理<|tool_call|>这种特殊token,然后用vLLM的--chat-template参数显式传进去,光靠system prompt和调temperature是治标不治本。
另外解析兜底这块,说实话在实际项目里是必须写的,别指望模型每次输出都规范。我现在的做法是双重保险:先正则匹配{"name":..., "arguments":...}这种标准结构,匹配不到就尝试用json.loads硬解析,还不行就强制走一个“重试”流程,让模型重新生成。但更关键的是,7B模型你最好把工具数量控制在5个以内,描述写得越具体越好,比如不要写“获取天气”,而是写“根据传入的城市名和日期返回实时天气数据,参数city为字符串,date为YYYY-MM-DD格式”。我试过把工具描述从两句话扩成一段话,成功率能提升差不多15%。
还有个小技巧,你可以试试在system prompt里放一个few-shot示例,就是给一个用户提问和对应的正确tool_call输出,让模型模仿格式。这个比单纯说“必须使用工具”有效得多。另外你提到temperature调到0.3,我觉得可以再低点,比如0.1,甚至直接用greedy decoding,因为tool calling本质上是个格式匹配任务,随机性越小越好。至于Qwen2.5-7B本身,说实话它做简单工具调用能跑通,但复杂场景还是容易漏参数或者多生成文本,如果条件允许直接上14B或32B,体验是质的差别。
vLLM默认模板确实容易翻车,建议换官方chat template试试,解析兜底必须写。
vLLM默认模板确实容易出问题,建议换官方chat template试试,解析兜底也得写,7B模型格式飘是常态。
vLLM默认模板确实可能是个坑,我之前用Qwen系模型也踩过,它官方文档里其实明确写了要配合特定的chat template才能正确输出tool_call格式,建议你直接去Qwen的GitHub仓库里把那个jinja模板拷出来,用vLLM的served_model配置加载一下,别用默认的。
另外7B模型在function calling上天生就比大模型容易飘,temperature调到0.3其实还是偏高,我实际测下来得压到0.1甚至0,并且把top_p也调低到0.8左右,不然它总喜欢“自由发挥”。你还可以试试在system prompt里把工具描述写得更“死板”一点,比如每个参数的类型和必填项都标注清楚,模型反而更容易跟着格式走。
至于解析兜底,这个真的得写,别指望模型每次输出都完美符合JSON schema,我项目里是直接加了一层正则+json.loads的容错,失败了就强制让模型重新生成一次,最多重试两次,再不行就返回错误给用户。
还有个偏门但有效的办法:把工具调用的示例直接塞进few-shot里,不要只靠system prompt,模型看到几个“标准答案”后,模仿能力会强很多。你可以试一下,如果还是不稳定,建议直接换Qwen2.5-14B或者32B,7B干这个活确实有点勉强。
vLLM默认模板确实容易踩坑,Qwen的官方chat template得手动指定,不然模型对tool_call的格式理解会偏差很大。我试过在tokenizer_config里显式加上qwen2.5的模板,再配合tool_use的system提示,稳定性提升挺明显的。解析兜底建议一定要写,7B模型偶尔输出不标准太正常了,我这边会用一个宽松的JSON提取器,先找json块再尝试正则抓字段。温度0.3还是偏高,可以试试0.1,另外把max_tokens调大点,有时模型是生成到一半被截断才导致乱编。
同款问题,7B模型对工具调用的指令遵循能力确实比大模型弱不少,光改prompt和temperature作用有限。我之前试过在vLLM里显式指定--chat-template指向Qwen官方仓库的模板文件,效果比默认模板稳多了,你可以先排查这个。另外解析兜底是必须的,我自己写了个正则+JSON双重校验,发现模型偶尔会输出"name":"get_weather"和"name": "get_weather"这种带空格的变体,直接解析铁定崩。还有个野路子是给模型塞几个few-shot例子,比如在system里放两条“用户问天气→你输出完整tool_call”的demo,比单纯强调指令管用。你试试把温度再调低点到0.1,甚至0,有时候随机性高了反而更容易瞎编。
vLLM默认的chat template确实可能跟Qwen的官方template有出入,这个影响很大,建议先检查一下。另外7B模型本身工具调用能力就有限,硬调prompt不如试试few-shot,给几个标准的tool_call示例让它模仿,比单纯强调“必须用工具”管用。解析兜底肯定要写,我这边实测至少20%的返回格式会有小毛病,直接json.loads会炸,得做个容错处理。还有个小技巧,temperature别调太低,0.5左右反而更稳,太低容易让模型走捷径乱编。
同款问题,试过加few-shot例子比改prompt管用,vLLM记得用官方给的chat template,解析兜底必须写。