最近在做一个基于大模型的Agent,需要它根据用户指令自动决定调用哪个API并填好参数。我参考了ReAct的写法,把工具描述和参数schema都写得很详细了,few-shot也给了三四个例子。但实际跑起来,它还是经常把“字符串”类型的参数填成JSON对象,或者明明用户没提某个可选参数,它非要自作主张塞一个默认值进去。更迷的是,有时候让它调用“搜索”工具,它反而去调“计算器”。我已经试过把system prompt里的约束语气加强,还加了“不确认就不要调用”之类的句子,但效果不稳定,同一句话多跑几次结果不一样。想问问大家,这种工具选择的Prompt到底该怎么设计?是不是该把决策逻辑拆成多个子Prompt?还是说要靠温度参数或者后处理硬约束来解决?
用Prompt让Agent调用工具时总是乱选参数,怎么调教都不听话,求指点
全部回复
共 30 条说实话你这问题我太有同感了,之前调一个订票Agent也卡在参数幻觉上,后来发现光堆few-shot没用,模型对“可选项”的理解跟咱们不一样。我后来是把每个工具的参数拆成独立的子决策,先让它用一句话复述用户意图,再问“现在需要哪些字段”,最后才给工具名,等于把ReAct里的Thought和Action中间加了道强制检查。还有那个乱选工具的情况,八成是工具描述里“搜索”和“计算器”的触发词在语义空间里离得太近,你可以试试把描述改成“仅当用户提到查找信息时才用”,然后加一个“其他情况一律不调用”的兜底动作。不过说实话,哪怕这样也还是有随机性,我后来直接上了个规则层,凡是置信度低于0.7就反问用户确认,虽然体验笨了点但至少不会瞎调。你这儿试试把system prompt改成“先列出所有可用工具,再打勾选择”,强制它走一遍全量对比,比单纯加约束句要稳。另外你多跑几次结果不一样,可能跟temperature设置有关,工具选择阶段我都是直接设成0,你可以对比下看看。
试试把工具选择拆成两步,先让模型只选工具再单独填参,我这么改后乱选少了很多。
试试给每个工具单独写个调用规则,让它先选再填参,两步走能稳不少。
或者把few-shot换成反面例子,专治乱填参数。
这种乱填参数的情况我太熟了,本质上是模型在“生成文本”和“遵守schema”之间没对齐好。你可以试试把参数校验从prompt里挪出来,用代码层做一层强校验,比如pydantic或者jsonschema,模型填错了直接报错让它重试,比在prompt里反复强调有用得多。至于调错工具,我觉得问题可能出在工具描述太像了,搜索和计算器如果都写成“处理用户查询”这种模糊的话,模型很容易蒙。把每个工具的适用边界写清楚,甚至加点反例,告诉它什么情况不该用这个工具,效果会好一些。还有一点,temperature调低一点,最好设成0或者0.1,同一句话结果不稳定大概率是采样随机性在作怪。至于拆子prompt,我觉得如果工具数量不多没必要,拆多了反而容易在中间环节丢上下文。你可以先试试把决策和填参分成两步,先让模型输出工具名,再单独一轮填参数,这样至少能定位到底是选错还是填错。
试试把工具选择单独拆成一步,先让它选工具再填参数,混在一起它容易懵。
我之前也踩过这个坑,感觉问题不一定全在prompt措辞上。模型对“参数类型”的理解其实很依赖schema本身的表达方式,比如你把参数写成嵌套对象还是扁平字段,它选错的概率差别挺大。可以试试把每个工具的入参用更接近自然语言的描述写一遍,而不是只丢JSON Schema,尤其要明确说清楚“这个字段必须是字符串,不要传对象”。
另外“自作主张塞默认值”这个事,我觉得可以在工具定义里把可选参数的默认行为写死,或者在代码层做一层校验和兜底,别指望模型每次都听话。至于选错工具,我试过把工具名和触发场景绑定得更具体,比如“搜索”只用于查实时信息,“计算器”只用于数值运算,效果会稳一些。
同一句话跑多次结果不一样,这大概率是采样温度的问题,做工具调用时把temperature调低甚至设成0会好很多。还有个思路是把决策拆成两步:先让模型输出“我要用哪个工具+理由”,再单独让它填参数,这样比一步到位稳定。不过拆多了也会增加延迟和出错链路,得看你的场景能不能接受。
试试把工具选择跟参数填充拆成两步走,先让它选对再填,不然挤一块容易犯迷糊。
感觉问题可能不在语气强不强,而是你把“选工具”和“填参数”塞进一次生成里了,模型容易顾此失彼。我之前也遇到过乱填可选参数的情况,后来在schema里把非必填项直接标成“不确定就留空”,再单独加一步校验,稳了不少。工具选错的话可以试试两段式:先让它只输出工具名,确认后再填参数,别指望一句prompt全搞定。另外temperature调低点,同一句话结果飘多半是采样在作怪。
参数类型填错这事我也踩过,后来发现光靠prompt里写schema没用,得在工具调用外面加一层校验和自动修正,比如检测到该传字符串却给了对象就强制序列化一下,比反复调prompt省心多了。至于乱选工具,我觉得可以在system里把每个工具的适用场景和禁用场景都写清楚,再配上两三个反例,比单纯加强语气管用。还有温度调低一点、同一请求多跑几次取多数结果,也能缓解不稳定。
我踩过同样的坑,后来发现光靠加约束语气基本没用,模型该乱来还是乱来。建议把工具选择做成两段式:先让模型只输出要调哪个工具,确定后再单独一次调用去填参数,拆开之后参数类型错误少了一大半。可选参数那块可以在schema里直接不给默认值,或者在prompt里明确说“用户没提就留空”,别让它自由发挥。至于搜索和计算器搞混,多半是工具描述太抽象,把各自适用场景用大白话写清楚会好很多。