LLM 函数调用:智能体腾飞的双翼,扩展 AI 应用边界

文摘   2024-08-20 18:01   中国香港  

TLDR:大型语言模型 (LLM) 的函数调用能力如同赋予智能体 (Agent) 腾飞的双翼,极大扩展了其应用范围。本文深入探讨了 LLM 函数调用的评估与优化策略,详细介绍了 BFCL 和 NFCL 两种主流评估框架,并通过实验结果展示了精心设计的提示和输出结构对提升 LLM 函数调用性能的重要性。文章还展望了 LLM 与复合 AI 系统的结合以及结构化生成技术等前沿方向,为 LLM 的未来发展指明了方向。

LLM 的演进与函数调用的兴起

近年来,大型语言模型 (LLM) 的发展可谓日新月异,它们正在迅速改变人们与 AI 交互的方式。从最初的文本生成到如今的多模态理解,LLM 的能力不断扩展,逐渐渗透到生活的方方面面。如果将 LLM 比作一个强大的智能体 (Agent),那么函数调用能力的出现,则如同赋予其腾飞的双翼,使其能够突破原有的限制,翱翔于更广阔的天空。LLM 正在朝着更加智能、更加通用的方向发展,而函数调用正是其迈向新高度的关键一步。

函数调用:赋能 LLM 与外部世界交互

那么,究竟什么是函数调用呢?简单来说,函数调用是指 LLM 调用外部代码(如 API 或自定义函数)的能力。通过函数调用,LLM 可以访问和利用外部数据源、工具和服务,从而完成诸如查询数据库、控制智能家居设备、生成代码等复杂任务。想象一下,只需要用自然语言向 LLM 描述需求,它就能自动调用相应的函数,完成你想要的操作,这将是多么便捷和高效!

根据 Databricks 的观察,目前主要的两种利用函数调用的企业用例为:

  1. 1. Agent 和复杂的多轮聊天机器人

  2. 2. 批量推理特征提取

Agent

人们对 LLM 的“Agent”能力越来越感兴趣。一般来说,LLM Agent 应该能够以最少的用户干预完成可能需要多个步骤的复杂任务。在实践中,通常需要函数调用来完成其中几个步骤:如前所述,它是使 LLM 能够与现有软件基础设施(例如数据库)交互的底层功能,例如通过 REST API。

考虑以下场景:一家大型企业,在 SQL 数据库中拥有大量的财务预测数据。借助函数调用,可以构建一个具有该数据读取权限的聊天机器人。内部用户可以向聊天机器人询问复杂的问题,例如“根据去年的趋势,我们 XYZ 产品在本财政年度的预计收入是多少?”,聊天机器人可以使用函数调用来请求两个日期之间的财务数据,然后可以使用这些数据来给出准确的估计。以下是一个示例:

User: "根据去年的趋势,我们 XYZ 产品在本财政年度的预计收入是多少?"

Chatbot: 要回答这个问题,我需要检索一些财务数据。让我检查一下我们的数据库。

[Function Call: get_financial_data]
Parameters:
  - product: "XYZ"
  - start_date: "2023-07-01"  // 假设上一个财政年度从这个日期开始
  - end_date: "2024-06-30"    // 当前财政年度结束
  - columns: ["last_year_revenue", "growth_rate"]

# 这可以通过将聊天机器人设计为包装模型的复合 AI 系统来直接执行,
# 也可以由用户手动执行,用户返回响应

[Function Response]
{
  "last_year_revenue": 10000000,
  "growth_rate": 0.15,
}

Chatbot: 根据我检索到的数据,我可以为您提供 XYZ 今年收入的预测:

XYZ 去年的收入为 1000 万美元。该产品同比增长率为 15%。

根据这一趋势预测,我们可以估计 XYZ 今年的总收入约为 1150 万美元。该预测考虑了当前的增长率和今年迄今为止的表现。

您想让我进一步分解此计算或提供有关预测的任何其他信息吗?

批量推理特征提取

函数调用通常是指 LLM 从用户提供的 API 或函数调用函数的能力。但这也意味着模型必须以函数签名和描述定义的确切格式输出函数调用。在实践中,这是通过使用 JSON 作为函数的表示来完成的。这方面可以用来解决一个普遍存在的用例:从非结构化数据中以 JSON 对象的形式提取结构化数据。我们称之为“批量特征提取”,并发现企业利用函数调用来执行此任务的情况相当普遍。例如,一家律师事务所可以使用具有函数调用功能的 LLM 来处理大量的合同,以提取关键条款,识别潜在风险,并根据其内容对每个文档进行分类。以这种方式使用函数调用允许这家律师事务所将大量数据转换为易于解析和从中获取见解的简单 JSON。

评估框架:BFCL 和 NFCL 深度解析

为了评估 LLM 的函数调用能力,研究人员开发了多种评估框架。其中,Berkeley 函数调用排行榜 (BFCL) 和 Nexus 函数调用排行榜 (NFCL) 是两种最具代表性的评估框架,它们分别从不同的角度对 LLM 的函数调用能力进行评估。

BFCL:全面评估 LLM 函数调用能力

BFCL 由 Gorilla-openfunctions-v2 的创建者创建和维护,包含五类测试:简单函数、多函数、并行函数、并行多函数和相关性检测。它可以全面评估 LLM 在不同场景下的函数调用能力,例如,它可以测试 LLM 是否能够正确识别需要调用的函数,是否能够正确传递参数,以及是否能够处理多个函数的并行调用等。

Image 1: BFCL Intervention Without Evals

NFCL:聚焦真实世界 API 调用场景

NFCL 来自 NexusRaven-v2 的创建者,其类别基于其 API 的来源而不是评估类型。它们在难度上也有所不同,包括:NVD 库、VirusTotal、OTX、Places、Climate API、VirusTotal Nested 和 NVD Nested。NFCL 更侧重于 LLM 在真实世界 API 调用场景下的表现,例如,它可以测试 LLM 是否能够正确调用天气预报 API、地图导航 API 等。

Image 2: NFCL Evaluation Without Interventions

实验结果:不同模型的函数调用能力对比

一项实验对比了不同 LLM 模型在 BFCL 和 NFCL 上的表现。结果显示,GPT-4o 在大多数情况下表现最佳,紧随其后的是 Llama3-70b-instruct。这表明,随着模型规模的增大,LLM 的函数调用能力也得到了显著提升。

Image 3: BFCL Evaluation After Interventions
Image 4: NFCL Evaluation After Interventions

优化策略:提升 LLM 函数调用性能的关键

为了进一步提升 LLM 的函数调用性能,可以采取以下优化策略:

精心设计的系统提示:引导 LLM 思考

通过提供详细的系统提示,可以引导 LLM 在决定调用哪个函数之前进行推理,例如,可以明确告诉 LLM 当前可用的函数列表,以及每个函数的功能和参数。这就像给 LLM 提供了一份操作指南,使其能够更加清晰地理解用户的意图,并选择合适的函数进行调用。以下是一个示例:

请根据你自己的判断来决定是否应该调用函数。特别是,你必须遵循以下指导原则:
    1. 你可以假设用户已经自己实现了该函数。
    2. 你可以假设用户会自己调用该函数。你不应该要求用户调用该函数并让你知道结果;他们会自己做。你只需要传递名称和参数。
    3. 切勿使用相同的参数两次调用函数。不要重复你的函数调用!
    4. 如果所有函数都与用户的问题无关,请不要进行任何不必要的函数调用。
    5. 不要假设可以访问此提示中未列出的任何函数,无论它们多么简单。也不要假设可以访问代码解释器。不要编造函数。

你只能根据以下格式规则调用函数:
    
规则 1:你可以访问的所有函数都包含在 {tool_list_start}{tool_list_end} XML 标记内。你不能使用未在此标记之间列出的任何函数。
    
规则 2:对于每个函数调用,输出符合函数模式的 JSON。你必须将函数调用包装在 {tool_call_start}[...工具调用列表...]{tool_call_end} XML 标记中。每个调用将是一个 JSON 对象,其中包含键“name”和“arguments”。“name”键将包含你正在调用的函数的名称,“arguments”键将包含你作为 JSON 对象传递给函数的参数。顶级结构是这些对象的列表。你必须在 {tool_call_start} 和 {tool_call_end} 标记之间输出有效的 JSON!
   
规则 3:如果用户决定运行该函数,他们将在以下查询中输出函数调用的结果。如果它回答了用户的问题,你应该在以下消息中加入函数的输出。

结构化输出:确保函数调用准确可靠

通过使用 XML 标记和严格的格式来构建输出,可以使解析函数调用变得容易和可靠,例如,可以要求 LLM 将函数调用封装成 JSON 格式,并明确指定每个参数的名称和值。这就像给 LLM 制定了一套编码规范,使其能够生成结构化的输出,从而降低出错的可能性。以下是一个示例:

假设你可以使用的函数是:
<tools>
[{'type': 'function', 'function': {'name': 'determine_body_mass_index', 'description': '计算给定体重和身高的体重指数。', 'parameters': {'type': 'object', 'properties': {'weight': {'type': 'number', 'description': '个体的体重,单位为千克。这是一个浮点型值。', 'format': 'float'}, 'height': {'type': 'number', 'description': '个体的身高,单位为米。这是一个浮点型值。', 'format': 'float'}}, 'required': ['weight', 'height']}}}]
[{'type': 'function', 'function': {'name': 'math_prod', 'description': '计算列表中所有数字的乘积。', 'parameters': {'type': 'object', 'properties': {'numbers': {'type': 'array', 'items': {'type': 'number'}, 'description': '要相加的数字列表。'}, 'decimal_places': {'type': 'integer', 'description': '要四舍五入的小数位数。默认为 2。'}}, 'required': ['numbers']}}}]
[{'type': 'function', 'function': {'name': 'distance_calculator_calculate', 'description': '计算两个地理坐标之间的距离。', 'parameters': {'type': 'object', 'properties': {'coordinate_1': {'type': 'array', 'items': {'type': 'number'}, 'description': '第一个坐标,一对纬度和经度。'}, 'coordinate_2': {'type': 'array', 'items': {'type': 'number'}, 'description': '第二个坐标,一对纬度和经度。'}}, 'required': ['coordinate_1', 'coordinate_2']}}}]
</tools>

并且用户问:
问题:纽约的当前时间是多少?

那么你应该回答:
<thinking>
让我们从我可以访问的函数列表开始:
- determine_body_mass_index:由于此函数与获取当前时间无关,因此我不会调用它。
- math_prod:由于此函数与获取当前时间无关,因此我不会调用它。
- distance_calculator_calculate:由于此函数与获取当前时间无关,因此我不会调用它。
可用的函数 [determine_body_mass_index, math_prod, distance_calculator] 均与给定查询无关。请检查你是否遗漏了任何相关函数。
作为大型语言模型,如果没有访问适当工具的权限,我无法提供纽约的当前时间。
</thinking>

LLM 函数调用的未来方向

复合 AI 系统:LLM 的协同效应

将 LLM 作为复合 AI 系统的一部分,可以使其与其他系统协同工作,例如,可以将 LLM 与知识图谱、数据库等系统结合起来,从而构建更加强大的 AI 应用。这就像将 LLM 融入到一个更大的生态系统中,使其能够发挥更大的作用。

结构化生成技术:保障输出格式的可靠性

结构化生成技术可以有效地约束 LLM 的输出,使其符合预定义的格式,例如 JSON 或 XML。这对于需要 LLM 与其他系统进行交互的应用场景至关重要,例如,在电商平台中,LLM 可以使用结构化生成技术来生成符合 API 规范的产品描述。

结论:迈向更智能的 AI 应用

LLM 函数调用能力的不断发展,将为 AI 应用带来更多可能性。通过不断优化评估方法和改进模型性能,未来将能够打造更加智能、可靠的 AI 应用,为人类社会带来更多福祉。相信在不久的将来,LLM 将会成为生活中不可或缺的一部分,帮助人们更高效地完成各种任务,并带来更多惊喜。

相关链接

  • • Beyond the Leaderboard: Unpacking Function Calling Evaluation:

    https://www.databricks.com/blog/unpacking-function-calling-eval

子非AI
子非AI,焉知AI之乐:分享AI的有趣应用和创新案例,让你了解AI的乐趣。
 最新文章