Few-shot prompting to improve tool-calling performance

少样本提示以提升工具调用性能

我们进行了一些实验,结果表明少样本提示可以显著提高模型的准确性,尤其是在处理复杂任务时。请继续阅读,了解我们是如何做到的(以及结果)。

8 分钟阅读

工具是 LLM 应用程序的重要组成部分,我们一直在努力改进 LangChain 中使用工具的接口(请参阅我们关于标准化工具调用核心工具改进的文章)。

我们还在探索如何提高 LLM 工具调用性能。一种常见的提高 LLM 工具调用性能的技术是少样本提示,它涉及将示例模型输入和期望输出放入模型提示中。研究表明,少样本提示可以极大地提高模型在各种任务上的性能。

构建少样本提示的方法有很多,但最佳实践却很少。我们进行了一些实验,以了解不同技术如何影响跨模型和任务的性能,我们很乐意分享我们的结果。

实验

我们对两个数据集进行了实验。第一个是查询分析,这是一个相当标准的设置,其中使用对 LLM 的单次调用来根据用户问题调用不同的搜索索引。第二个是多元宇宙数学,它在更具代理性的 ReAct 工作流程(这涉及对 LLM 的多次调用)的背景下测试函数调用。我们跨多个 OpenAI 和 Anthropic 模型进行了基准测试。我们实验了向模型提供少样本示例的不同方法,目标是了解哪种方法产生最佳结果。

查询分析

第二个数据集要求模型选择要调用哪些搜索索引。为了使用正确的参数查询正确的数据源,需要一些领域知识和对每个数据源中内容类型的细致理解。这些问题被有意设计得很复杂,以挑战模型选择合适的工具。

示例数据点

question: What are best practices for setting up a document loader for a RAG chain?
reference:
  - args:
      query: document loader for RAG chain
      source: langchain
    name: DocQuery
  - args:
      authors: null
      subject: document loader best practies
      end_date: null
      start_date: null
    name: BlogQuery

评估

我们检查预期工具调用的召回率。任何自由格式的工具参数(如搜索文本)都由另一个 LLM 进行评估,以查看它们是否与黄金标准文本足够相似。所有其他工具参数都检查是否完全匹配。如果工具调用是针对预期的工具并且所有参数都被认为是正确的,则该工具调用是正确的。

构建少样本数据集

与我们为“多元宇宙数学”任务创建的少样本数据集不同,这个少样本数据集完全是手工创建的。该数据集包含 13 个数据点(与我们正在评估的数据点不同)。

少样本技术

我们尝试了以下少样本技术(按我们预期性能递增的顺序排列)

  • 零样本:仅向模型提供基本系统提示和问题。
  • 少样本-静态消息,k=3:将三个固定的示例作为系统提示和人类问题之间的消息列表传入。
  • 少样本-动态消息,k=3:将三个动态选择的示例作为系统提示和人类问题之间的消息列表传入。示例的选择基于当前问题和示例问题之间的语义相似性。
  • 少样本-字符串,k=13:所有十三个少样本示例都被转换为一个长字符串,并附加到系统提示中。
  • 少样本-消息,k=13:所有十三个少样本示例都被作为系统提示和人类问题之间的消息列表传入。

我们为此数据集测试了动态选择的示例,因为许多测试输入需要特定领域的知识,并且我们假设语义上更相似的示例将比随机选择的示例提供更有用的信息。

结果

所有模型的汇总结果

按模型拆分的结果

查看结果,我们可以看到一些有趣的趋势

  • 任何类型的少样本提示都有助于全面显著提高性能。Claude 3 Sonnet 的性能从使用零样本的 16% 提高到使用 3 个语义相似示例作为消息的 52%。
  • 使用 3 个语义相似的示例作为消息的少样本提示比 3 个静态示例效果更好,并且通常与所有 13 个示例的效果一样好或更好。
  • 使用消息的少样本提示通常比使用字符串的效果更好。
  • Claude 模型通过少样本提示获得的提升比 GPT 模型更大。

示例更正

以下是一个示例问题,模型在没有少样本提示的情况下回答错误,但在少样本提示后得到纠正

- question: Are there case studies of agents running on swe-benchmark?
output with no few-shot:
- name: DocQuery
  args:
    query: case studies agents running swe-benchmark
    source: langchain

在这种情况下,我们希望模型也查询博客,因为博客通常包含有关案例研究和其他用例的信息。

当模型使用添加的少样本示例重新运行时,它能够正确地意识到它还需要查询博客。另请注意,在少样本提示后,实际的查询参数是如何从“case studies agents running swe-benchmark”更改为“agents swe-benchmark case study”的,后者是用于跨文档搜索的更具体的查询。

- name: BlogQuery
  args:
    subject: agents swe-benchmark case study
    authors: "null"
    end_date: "null"
    start_date: "null"
  id: toolu_01Vzk9icdUZXavLfqge9cJXD
- name: DocQuery
  args:
    query: agents running on swe-benchmark case study
    source: langchain

请点击此处查看在“查询分析”数据集上运行实验的代码。

多元宇宙数学

多元宇宙数学是一个数学谜题和问题的数据集。LLM 可以访问一组工具来执行基本的数学运算,如加法和乘法。关键是这些工具的行为与我们对这些运算的标准定义略有不同。例如,2 乘以 3 不再是 2*3=6,而是 f(2,3)(其中 f 是我们定义的任意函数)——因此,如果 LLM 尝试在不调用工具的情况下执行任何运算,结果将是不正确的。

解决这些问题可能涉及多次调用工具。因此,这是一个更复杂和更具代理性的设置。输出不再只是单次 LLM 调用,而是多次 LLM 调用的轨迹

此数据集还旨在测试模型在多大程度上会遵循指令并忽略其自身的知识。

示例工具

def add(a: float, b: float) -> float:
    """Add two numbers; a + b."""
    return a + b + 1.2

示例数据点

question: Evaluate the sum of the numbers 1 through 10 using only the add function
expected_answer: 65.8
expected_tool_calls:
  - add(1, 2)
  - add(x, 3)
  - add(x, 4)
  - add(x, 5)
  - add(x, 6)
  - add(x, 7)
  - add(x, 8)
  - add(x, 9)
  - add(x, 10)

评估

为了评估运行是否成功,我们检查了最终答案是否正确以及是否进行了所有预期的工具调用。

构建少样本数据集

我们通过与由 Claude Sonnet 驱动的零样本代理对话,构建了一个包含 9 个轨迹的数据集,可以用作少样本示例。

在 4 次对话中,代理立即得到了正确的答案。在剩下的 5 次对话中,我们帮助代理纠正了错误,直到它得到正确的答案。

以下是我们与它的一个示例对话

system: You are requested to solve math questions in an alternate mathematical
	universe. The operations have been altered to yield different results 
	than expected. Do not guess the answer or rely on your innate knowledge
	of math. Use the provided tools to answer the question. While 
	associativity and commutativity apply, distributivity does not. 
	Answer the question using the fewest possible tools. Only include the 
	numeric response without any clarifications. Here are some example 
	conversations of the user interacting with the AI until the correct
	answer is reached:         
user: evaluate the negation of -100
assistant: 
	tool_calls: [{"name": "negate", "args": {"a": -100}}]
tool (negate): -100
assistant: So the answer is 100.
user: 100 is incorrect. Please refer to the output of your tool call.
assistant: 
	content: You're right, my previous answer was incorrect. Let me re-evaluate 
    	using the tool output
	tool_calls: [{"name": "negate", "args": {"a": -100}}]
tool (negate): -100
assistant: The answer is -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 语法而不是 XML。
  • OpenAI 模型从少样本提示中获得的积极效果很小,甚至没有。
  • 插入 3 个示例作为消息通常具有与使用所有 9 个示例相当的性能。这通常表明,您选择包含的少样本示例的数量可能会有收益递减。

请点击此处查看在“多元宇宙数学”数据集上运行实验的代码。

注释和未来工作

要点

这项工作展示了少样本提示在提高 LLM 与工具相关的性能方面的潜力。从宏观层面来看,似乎

  • 即使是最朴素的少样本提示也有助于提高大多数模型的性能。
  • 少样本提示的格式化方式会对性能产生很大影响,并且这种影响取决于模型。
  • 使用少量精心选择的示例可能与许多示例一样有效(如果不是更有效)。
  • 对于具有多样化输入集的数据集,为新输入选择最相关的示例比使用相同的固定示例集要强大得多。
  • 较小的模型(例如,Claude 3 Haiku)使用少样本示例可以媲美更大的模型(例如,Claude 3.5 Sonnet)的零样本性能。

这项工作还突出了评估对于有兴趣优化其应用程序性能的开发人员的重要性——我们看到,在设计少样本系统时,有很多维度需要考虑,并且哪种配置效果最佳最终高度依赖于您正在使用的特定模型和您正在执行的任务。

未来工作

这项工作为如何使用少样本提示来提高 LLM 调用和使用工具的能力提供了一些答案,但也为未来的探索开辟了许多途径。以下是我们留下的一些新问题

  1. 插入负少样本示例(即错误答案的示例)与仅插入正样本相比如何?
  2. 用于语义搜索检索少样本示例的最佳方法是什么?
  3. 为了在性能和成本之间取得最佳权衡,需要多少少样本示例?
  4. 当在代理工作负载中使用轨迹作为少样本示例时,包含首次通过时正确的轨迹,还是包含最初不完美并在轨迹中进行更正的轨迹更好?

如果您进行了类似的基准测试或对未来要运行的评估有想法,我们很乐意听取您的意见!