最近在折腾本地Agent,用的Qwen2.5-7B-Instruct配合LangChain,任务就是让它调用几个简单的工具(查天气、算日期、搜维基)。单轮对话还行,但只要多轮交互,它就开始“犯迷糊”——要么把工具参数写错格式,要么明明该调用工具却直接编答案,甚至偶尔会重复调用同一个工具好几遍。我试过调低temperature到0.1,也加了Few-shot示例,还是不太稳。看网上说用函数调用微调版会好点,但我只有一张消费级显卡,微调不太现实。想问问大家:本地小模型做Agent工具调用,有没有什么提示词技巧或者框架上的取舍?还是说只能妥协用API版?
Qwen2.5本地部署做Agent,工具调用老是不稳定,大家怎么解决的?
全部回复
共 26 条试试换vLLM部署加outlines做约束解码,参数格式基本不会飞,比调temperature管用。
我拿Qwen2.5-7B也搭过类似的,多轮确实容易崩。后来换成它的function calling专用模板,别让LangChain自己拼tool prompt,稳了不少。另外工具别一次给太多,3个以内它还能hold住,多了就开始乱选。还有个坑是历史消息全塞进去会干扰,我改成只保留最近两轮加工具结果就正常多了。
我最近也在折腾Qwen2.5-7B做本地Agent,工具调用确实容易崩,尤其是多轮之后参数格式乱飞。后来我换了个思路,不让模型直接输出JSON,而是用ReAct那种“Thought+Action”的文本格式,解析器自己写得糙一点反而更稳。另外LangChain的agent executor对本地小模型有点重,换成自己写个简单循环,把历史里工具返回结果截断短一点,重复调用会少很多。微调确实没必要,7B这尺寸提示词和框架兜底比模型本身更重要。
我之前也拿Qwen2.5-7B在本地搭过类似的Agent,说实话这个模型在单步工具调用上还行,但一旦涉及多轮状态跟踪就很容易崩。你说的“该调工具却直接编答案”我太熟了,本质上是它没把工具调用当成一个必须执行的强约束,而是当成了一个可选的文本生成方向。LangChain的AgentExecutor本身对输出解析容错就比较差,模型稍微偏一点格式就直接挂掉或者瞎跑。
后来我换了个思路,不用LangChain那套ReAct循环,改成自己写一个简单的状态机,每一步只让模型做一件事——要么输出结构化的工具调用JSON,要么明确说“不需要工具”。提示词里把工具schema写死,并且强制它每次只输出一个JSON对象,解析失败就重试一次并带上错误信息。这样虽然笨,但稳定性反而上来了,重复调用的问题也少了很多。
另外Qwen2.5本身对function calling是有专门模板的,如果你直接用transformers加载,最好走它官方的chat template,别让LangChain自己拼prompt,那个格式经常和模型训练时不一致。消费级显卡微调确实不现实,但可以试试用llama.cpp的grammar或者outlines做约束解码,强制输出符合JSON schema,这个对本地小模型帮助特别大。
如果任务链路很长、工具又多,说实话7B确实有点勉强,可以考虑Qwen2.5-14B的量化版,或者干脆把复杂编排交给代码、只让模型做单步决策。API版当然省心,但本地部署的乐趣不就在于折腾嘛,慢慢调还是能用的。
Qwen2.5-7B做Agent确实有点吃力,我试过类似的配置,多轮一上来就容易乱。后来发现关键不是temperature,而是system prompt里得把工具描述写死,参数格式用JSON Schema卡死,别给它自由发挥的空间。另外LangChain的AgentExecutor对本地小模型不太友好,换成手动拼prompt加正则解析会稳不少。如果实在不行,可以考虑Qwen2.5-14B的GPTQ量化版,单卡24G应该能跑,比7B靠谱很多。
换vLLM部署加guided decoding,用JSON schema约束输出格式,工具调用立马稳一半。