无论你是使用大语言模型还是搭建Agent,其核心能力往往都指向同一个关键点——工具调用(也称函数调用)。然而,不得不承认,当前通用模型在这一方面的表现远未达到令人放心的程度。本文将深入探讨如何有效提升函数调用的准确性。

本文的核心思路来源于一篇前沿论文:《Robust Function-Calling for On-Device Language Models via Function Masking》。如果你对此感兴趣,可以查阅原文获取更多技术细节。
函数调用的过程
首先,让我们来看一个典型的函数调用流程,上图已清晰展示。在整个过程中,每个候选函数都包含四个关键元素:函数名、参数名、默认值和描述。模型需要输出完整且准确的函数调用代码以实现用户意图;若没有合适的候选函数,则输出一个空列表。
能否成功取决于两个环节:一是模型准确地将用户意图与候选函数的功能匹配——即选对函数;二是模型正确理解每个参数的用法——即填对参数。
发现的问题
- 函数名称与参数名称的误导
- 对命名的过度依赖
函数名称和参数名称的误导
函数的定义中通常包含函数名、参数名和描述。然而,函数名和参数名的写法往往非常紧凑,例如 cal_sum 或 max_value,很容易受设计者个人风格的影响。如果模型仅靠名字来推测功能,就极易产生歧义,尤其在功能较为复杂的情况下。
举个例子:一个名为 parse_data 的函数,在某个场景下可能是解析JSON数据,在另一场景下却是解析CSV文件,仅看名字根本无法区分。
同样的困惑也会出现在参数上。模型看到参数名时,可能会联想到训练数据中类似名称的历史用法,从而被带偏。具体来看,这些误导可以分为以下几类:
函数名称误导。 如果用户意图恰好与训练数据中某个函数的名字高度吻合,模型在测试时可能会优先选择该函数,即使它的实际功能并不匹配。
例如,训练集里有一个名为 fetch_data 的函数,用于从数据库获取用户数据,但测试集中同名函数是从外部API获取数据,模型很可能只看名字就做出了错误选择。
参数名称误导。 当测试环境中参数的功能或描述发生变化时,模型常会固守原先的用法,导致调用失败。
比如有一个参数叫 timeout,在一个场景中是整数(秒),在另一个场景中却是类似“10s”的字符串。模型如果习惯了整数格式,遇到字符串就会出错。
命名偏好带来的困扰。 当测试环境中函数或参数的命名风格与训练集不一致时,模型的表现会变得很不稳定。例如 CamelCase 与 snake_case 的差异,就会使轻量级模型的置信度大幅降低。
过度关注命名的影响
为了验证这一问题,研究者开展了一组实验:在测试集中屏蔽了函数和参数名称——即用随机字符串替换它们,然后观察模型表现的变化。结果发现,大多数模型的性能出现了显著下降。
相比之下,Hammer模型在相同设置下性能下降非常有限,表明它在应对各种命名模式时具备很强的适应性。
那么,它是如何做到的?
方法
函数屏蔽
解决这类问题最直接的方法是:尽可能减少函数名和参数名的干扰,同时强制模型依赖候选函数的描述来理解其功能与用法。
描述的优势在于:
- 描述采用自然语言编写,更加灵活、完整,通常能涵盖函数名和参数名所要表达的全部信息。
- 尽管描述也可能带有设计者的个人风格,但往往更为准确、详细,不易产生歧义或误导。
下图展示了函数屏蔽的具体流程:
论文的实验结果自然是积极的,请参考下面的测试数据:
Hammer2.0
Hammer2.0 已经正式发布,最小版本仅有0.5B参数,最大版本为7B。你可以在自己的环境或MaaS平台上部署进行测试。
注意
最后需要说明的是,论文中的函数屏蔽方案并不一定适用于所有人的场景。实际接触到的客户大多基于API调用,函数数量通常不多,因此最终效果更取决于函数Schema的定义方式以及基础模型本身的性能。
