本文探讨了通过“少量示例提示”(few-shot prompting)来提高大型语言模型(LLM)在调用工具时的性能。研究表明,少量示例提示能够显著提升模型在多种任务上的表现。通过一系列实验,作者分析了不同提示构造方式对模型性能的影响,发现选择合适的示例和格式化方式是提高性能的关键。

  1. 实验设置

    • 研究使用了两个数据集进行实验:Query Analysis 和 Multiverse Math。Query Analysis 测试模型如何基于用户问题选择搜索索引,而 Multiverse Math 则考察模型在更复杂的多次调用场景中的表现。
  2. 少量示例提示技术

    • 实验中采用了多种少量示例提示技术,包括零-shot、静态和动态消息等方式。结果表明,动态选择的示例通常优于静态示例,且使用消息格式的表现优于字符串格式。
  3. 性能评估

    • 通过检查工具调用的召回率和参数的匹配程度来评估模型的表现。实验结果显示,少量示例提示普遍提高了模型的准确性,尤其是 Claude 模型的表现提升显著。
  4. 关键发现

    • 使用少量相关示例(如 3 个)可以与使用更多示例(如 9 个)达到相似的效果,显示出示例数量的边际效益递减。此外,小型模型在使用少量示例时,表现能够与大型模型相媲美。
  5. 未来研究方向

    • 文章提出了未来的研究问题,包括负面示例的效果、最佳的示例检索方法以及在复杂任务中如何选择示例等,鼓励开发者探索更多优化 LLM 性能的可能性。

少样本提示提高工具调用效率

工具是大语言模型 (LLM) 应用的重要组成部分,我们一直在努力改进 LangChain 的工具接口(参见我们关于 标准化工具调用核心工具改进 的文章)。

我们还在研究如何 提升 LLM 工具调用的性能。一种常见的方法是使用 少样本提示,即在提示中加入示例输入和期望输出。研究表明,少样本提示能显著提升模型在多种任务中的表现。

构建少样本提示的方法很多,但缺乏最佳实践。我们进行了几次实验,探讨不同技术如何影响模型和任务的性能,愿意与大家分享我们的结果。

实验

我们在两个数据集上进行了实验。第一个数据集是 Query Analysis,这是一个标准场景,模型根据用户问题调用不同的搜索索引。第二个数据集是 Multiverse Math,测试在更智能化的 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

评估

我们检查预期工具调用的召回率。对于自由形式的工具参数,如搜索文本,我们使用另一个大语言模型来评估其是否与标准文本足够相似。所有其他工具参数都检查是否完全匹配。如果调用了预期的工具且所有参数都正确,则该工具调用被认为是正确的。

构建少样本数据集

与我们为 Multiverse Math 任务创建的少样本数据集不同,这个少样本数据集完全是手工制作的。该数据集包含13个数据点(与评估用的数据点不同)。

少样本技术

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

  • 零样本:仅提供基本系统提示和问题。
  • 少样本静态消息,k=3 :三个固定示例作为系统提示和问题之间的消息列表传递。
  • 少样本动态消息,k=3 :三个动态选择的示例作为系统提示和问题之间的消息列表传递。示例根据当前问题与示例问题的语义相似性进行选择。
  • 少样本字符串,k=13 :将所有13个少样本示例转换为一个长字符串,并附加到系统提示中。
  • 少样本消息,k=13 :所有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

查看在 Query Analysis 数据集上运行实验的代码请点击 这里

Multiverse Math

Multiverse Math 是一个数学谜题和问题的数据集。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个示例相当。这表明少样本示例的数量存在边际效益递减。

查看在 Multiverse Math 数据集上运行实验的代码请点击 这里

备注和未来工作

收获

这项工作展示了少样本提示在提高 LLM 工具使用性能方面的潜力。从整体上看:

  • 即使是最简单的少样本提示也能提高大多数模型的性能。
  • 少样本提示的格式对性能有很大影响,并且这种影响取决于具体模型。
  • 使用一些精心选择的示例可能比使用大量示例更有效。
  • 对于输入多样化的数据集,选择最相关的示例比使用固定示例集更有效。
  • 较小的模型(如 Claude 3 Haiku)配合少样本示例可以媲美更大模型(如 Claude 3.5 Sonnet)的零样本性能。

这项工作还强调了评估对开发者优化应用程序性能的重要性——我们发现设计少样本系统时需要考虑许多因素,而最佳配置取决于所使用的具体模型和执行的任务。

未来工作

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

  1. 插入负面少样本示例(即错误答案的示例)与仅插入正面示例相比效果如何?
  2. 少样本示例的最佳语义搜索方法是什么?
  3. 为达到性能和成本的最佳平衡,需要多少少样本示例?
  4. 在智能体工作负载中使用轨迹作为少样本示例时,包含首次正确的轨迹和包含初始不完美但有纠正的轨迹哪个更好?

如果您进行过类似的基准测试或有未来评估的想法,我们很想听到您的意见!