LLM工具调用破局:Few-shot Prompting
构建少量样本提示的方法多种多样,但目前还没有统一的最佳实践。我们进行了一些实验,以探究不同技巧对模型和任务性能的影响,这些实验结果表明,通过少量样本提示,我们可以显著提高模型的准确度,特别是在处理复杂任务时。接下来,我将分享我们是如何做到这一点的,以及实验的结果。
编辑注:本文经翻译并二次整理自Few-shot prompting to improve tool-calling performances一文。
实验过程
我们基于两个数据集进行了实验。第一个数据集是Query Analysis,这是一个标准的设置,通过单一的LLM调用来根据不同的用户问题激活不同的搜索索引。第二个数据集是Multiverse Math,它在更具代理性的工作流ReAct的背景下测试函数调用(这涉及到对LLM的多次调用)。我们在多个OpenAI和Anthropic模型上进行了基准测试,并尝试了不同的少量样本示例提供方式,以观察哪种方法最为有效。
查询分析实验
查询分析数据集要求模型根据问题选择正确的搜索索引。为了使用正确的参数查询正确的数据源,需要对每个数据源包含的内容类型有一定的了解和细微的理解。问题设置得相对复杂,目的是挑战模型在选择合适工具方面的能力。
示例数据点
问题:如何为RAG链配置文档加载器的最佳实践?
参考:
- 调用名称:DocQuery
参数:
查询:RAG链的文档加载器
来源:langchain
- 调用名称:BlogQuery
参数:
作者:无
主题:文档加载器最佳实践
开始日期:无
结束日期:无
评估方法
我们检查预期工具调用的准确性。对于自由形式的工具参数,如搜索文本,我们使用另一个LLM来评估它们是否与标准答案足够接近。其他工具参数则检查是否完全匹配。如果工具调用指向预期的工具,并且所有参数都被认为是正确的,那么这个调用就被认为是正确的。
与我们为Multiverse Math任务创建的少量样本数据集不同,这个数据集完全由手工创建,包含13个不同的数据点。
我们尝试了以下少量样本技术,并按照我们预期的性能顺序排列:
- 零样本:仅提供基本的系统提示和问题。
- 少量样本-静态消息,k=3:在系统提示和人类问题之间传递三个固定的示例。
- 少量样本-动态消息,k=3:在系统提示和人类问题之间传递三个根据当前问题和示例问题的语义相似性动态选择的示例。
- 少量样本-字符串,k=13:将所有十三个示例转换为一个长字符串,并附加到系统提示中。
- 少量样本-消息,k=13:将所有十三个示例作为消息列表,在系统提示和人类问题之间传递。
我们选择为这个数据集测试动态选择的示例,因为许多测试输入需要特定领域的知识,我们假设更语义相似的示例比随机选择的示例更有帮助。
综合所有模型的结果:
综合结果图
按模型拆分的结果:
按模型拆分的结果图
从结果中,我们可以观察到几个有趣的趋势:
- 任何形式的少量样本都对整体有所帮助。例如,Claude 3 Sonnet模型的性能从16%的零样本提升到52%,当使用3个语义相似的消息示例。
- 使用3个语义相似的消息示例的少量样本通常比3个静态示例表现更好,并且通常与使用所有13个示例一样好或更好。
- 通过消息传递的少量样本通常比通过字符串传递的表现更佳。
- Claude模型在少量样本提示下的性能提升比GPT模型更为显著。
以下是一个模型在没有少量样本提示时回答错误的问题,以及在添加少量样本提示后正确回答的示例:
- 问题:有没有关于在swe-benchmark上运行代理的案例研究?
没有少量样本的输出:
- 调用名称:DocQuery
参数:
查询:案例研究代理运行 swe-benchmark
来源:langchain
在这种情况下,我们期望模型还能查询博客,因为博客通常包含有关案例研究和其他用例的信息。
当模型在添加少量样本示例后重新运行时,它能够正确地意识到还需要查询博客。同时,实际的查询参数也从“案例研究代理运行 swe-benchmark”更改为“代理 swe-benchmark 案例研究”,这是一个更具体的查询,用于在文档中搜索。
- 调用名称:BlogQuery
参数:
主题:代理 swe-benchmark 案例研究
作者:无
开始日期:无
结束日期:无
id:toolu_01Vzk9icdUZXavLfqge9cJXD
- 调用名称:DocQuery
参数:
查询:代理在swe-benchmark上的案例研究运行
来源:langchain
想要查看在Query Analysis数据集上运行实验的代码,请点击这里。
多宇宙数学探秘
多宇宙数学 是一个充满挑战的数学问题集,它要求我们在一个规则略有不同的数学世界中进行思考。在这个宇宙里,我们熟知的加法和乘法等基本运算被赋予了新的定义。例如,传统的2乘以3等于6在这里不再成立,而是通过某种我们自定义的函数 f
来计算 —— 也就是说,如果大型语言模型(LLM)试图依靠其内部知识而不调用这些特殊工具来解决问题,那么得到的答案将是错误的。
要解决这些问题,可能需要我们多次调用这些工具,这使得问题解决过程变得更加复杂和具有代理性。我们得到的不再是单一的模型输出,而是一系列模型调用的轨迹。
这个数据集还旨在测试模型遵循指令的能力,并挑战它们忽略固有知识。
示例工具
def add(a: float, b: float) -> float:
"""将两个数字相加,得到的结果是 a 加上 b 再加上 1.2。"""
return a + b + 1.2
示例数据点
问题:请仅使用 add 函数计算从1到10所有数字的总和。
预期答案:65.8
预期工具调用:
- add(1, 2)
- add(x, 3)
- ...
- add(x, 10)
评估
我们通过检查最终答案是否正确以及是否进行了所有预期的工具调用来评估运行是否成功。
我们通过与一个由Claude Sonnet驱动的零样本代理进行对话,构建了一个包含9个轨迹的少样本数据集,这些轨迹可以用作少样本示例。在其中的4次对话中,代理立刻得出了正确答案。而在其余5次对话中,我们帮助代理纠正了错误,直到它得出了正确答案。
以下是我们与代理进行的一次示例对话:
系统:你被要求在一个不同的数学宇宙中解决数学问题。这里的操作规则已被修改,以产生与常规不同的结果。
用户:计算-100的相反数。
助手:
工具调用:[{"name": "negate", "args": {"a": -100}}]
工具(negate):-100
助手:那么答案是100。
用户:100是不正确的。请参考你的工具调用输出。
助手:
内容:你说得对,我之前的答案不正确。让我根据工具的输出重新评估。
工具调用:[{"name": "negate", "args": {"a": -100}}]
工具(negate):-100
助手:答案是-100.0
在这个任务中,negate 函数实际上并没有改变任何东西,它是一个恒等函数。然而,LLM最初依赖于其内部知识;尽管它正确地调用了工具,但它忽略了工具的输出并返回了常规的相反数。只有在我们提示模型尊重工具的输出之后,它才给出了正确答案。
我们尝试了以下几种少样本技术:
- 零样本:只向模型提供了一个基本的系统提示和问题。
- 少样本-字符串, k=3:将三个固定示例转换成长字符串,并附加到系统提示中。消息使用ChatML语法进行格式化。
- 少样本-消息, k=3:将三个固定示例作为消息列表,在系统提示和人类问题之间传递。
- 少样本-字符串, k=9:将所有九个少样本示例转换成长字符串,并附加到系统提示中。
- 少样本-消息, k=9:将所有九个少样本示例作为消息列表,在系统提示和人类问题之间传递。
查看结果,我们发现一些有趣的趋势:
- 使用9个示例作为消息进行少样本提示几乎总是优于零样本提示,并且通常表现最佳。
- Claude 3模型在使用消息进行少样本提示时性能大幅提升。例如,Claude 3 Haiku在没有示例的情况下正确率为11%,但仅使用3个示例作为消息时,正确率就达到了75%。这与其他模型的零样本性能相当,除了Claude 3.5 Sonnet和GPT-4o。
- 当示例被格式化为字符串并添加到系统消息中时,Claude 3模型的性能提升很小或根本没有提升。这可能是由于我们使用ChatML语法进行格式化。
- OpenAI模型从少样本提示中获得的正面效果较小。
- 通常,插入3个示例作为消息的性能与使用所有9个示例相当。这表明,选择包含多少少样本示例可能存在递减回报。
有关在多宇宙数学数据集上运行实验的代码,请访问这里。
要点总结
这项工作展示了少样本提示在提高LLMs性能方面的潜力,尤其是在工具调用和使用方面。从宏观上看,我们发现:
- 即使是最简单的少样本提示也能为大多数模型带来性能提升。
- 少样本提示的格式化方式对性能有显著影响,并且这种影响因模型而异。
- 使用一些精选的示例可能和使用许多示例一样有效,甚至更有效。
- 对于输入多样化的数据集,为新输入选择最相关的示例比使用相同的固定示例集更有力量。
- 使用少样本示例的较小模型(如Claude 3 Haiku)可以与更大的模型(如Claude 3.5 Sonnet)的零样本性能相媲美。
这项工作还强调了评估对于希望优化其应用程序性能的开发人员的重要性 —— 我们发现,在设计少样本系统时,有很多维度需要考虑,而哪种配置最有效最终高度依赖于您使用的具体模型和执行的任务。
本文转载自 AI小智,作者: AI小智