一、工具调用
工具调用(也称为函数调用)是AI应用中的一种常见模式,允许模型与一组API或工具进行交互,从而增强其能力。
工具主要用于以下场景:
信息检索。此类工具可用于从外部源(如数据库、Web服务、文件系统或网络搜索引擎)检索信息。其目标是扩展模型的知识,使其能够回答原本无法回答的问题。因此,它们可用于检索增强生成(RAG)场景。例如,可以使用工具来检索给定位置的当前天气、检索最新新闻文章或查询数据库中的特定记录。
执行操作。此类工具可用于在软件系统中执行操作,例如发送电子邮件、在数据库中创建新记录、提交表单或触发工作流。其目标是自动化原本需要人工干预或显式编程的任务。例如,在与聊天机器人交互时,可以使用工具为客户预订航班、填写网页上的表单,或在代码生成场景中基于自动化测试(TDD)实现Java类。
尽管我们通常将工具调用称为模型的能力,但实际上提供工具调用逻辑的是客户端应用程序。模型只能请求工具调用并提供输入参数,而应用程序负责根据输入参数执行工具调用并返回结果。模型无法访问作为工具提供的任何API,这是一个关键的安全考虑因素。
Spring AI提供了便捷的API来定义工具、解析来自模型的工具调用请求并执行工具调用。以下部分概述了Spring AI中的工具调用功能。
请查看 Chat模型比较,了解哪些AI模型支持工具调用。
请按照指南从已弃用的FunctionCallback迁移到ToolCallback API。
二、快速开始
让我们看看如何在Spring AI中开始使用工具调用。我们将实现两个简单的工具:一个用于信息检索,另一个用于执行操作。信息检索工具将用于获取用户时区的当前日期和时间。操作工具将用于在指定时间设置闹钟。
2.1 信息检索
AI模型无法访问实时信息。任何假设了解当前日期或天气预报等信息的提问,模型都无法回答。但是,我们可以提供一个能够检索此类信息的工具,并让模型在需要访问实时信息时调用该工具。
让我们在一个DateTimeTools类中实现一个工具,用于获取用户时区的当前日期和时间。该工具不需要参数。Spring Framework的LocaleContextHolder可以提供用户的时区。该工具将定义为用@Tool注解的方法。为了帮助模型理解是否以及何时调用此工具,我们将提供该工具功能的详细描述。
importjava.time.LocalDateTime;importorg.springframework.ai.tool.annotation.Tool;importorg.springframework.context.i18n.LocaleContextHolder;classDateTimeTools{@Tool(description="Get the current date and time in the user's timezone")StringgetCurrentDateTime(){returnLocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();}}接下来,让我们使该工具对模型可用。在此示例中,我们将使用ChatClient与模型交互。我们将通过tools()方法传递一个DateTimeTools实例来向模型提供该工具。当模型需要知道当前日期和时间时,它将请求调用该工具。在内部,ChatClient将调用该工具并将结果返回给模型,然后模型将使用工具调用结果生成对原始问题的最终响应。
ChatModelchatModel=...Stringresponse=ChatClient.create(chatModel).prompt("What day is tomorrow?").tools(newDateTimeTools()).call().content();System.out.println(response);输出将类似于:
Tomorrow is 2015-10-21.
您可以再次尝试询问相同的问题。这次,不要向模型提供工具。输出将类似于:
I am an AI and do not have access to real-time information. Please provide the current date so I can accurately determine what day tomorrow will be.
如果没有工具,模型不知道如何回答该问题,因为它无法确定当前日期和时间。
2.2 执行操作
AI模型可用于生成实现某些目标的计划。例如,模型可以生成预订前往丹麦旅行的计划。然而,模型没有执行计划的能力。这就是工具的用武之地:它们可用于执行模型生成的计划。
在前面的示例中,我们使用了一个工具来确定当前日期和时间。在此示例中,我们将在同一个DateTimeTools类中定义第二个工具,用于在特定时间设置闹钟。目标是从现在开始10分钟后设置闹钟,因此我们需要向模型提供两个工具来完成此任务。
我们将新的工具添加到之前的DateTimeTools类中。新工具将接受一个参数,即ISO-8601格式的时间。然后,该工具将向控制台打印一条消息,指示闹钟已设置为给定时间。与之前一样,该工具被定义为用@Tool注解的方法,我们还用它来提供详细描述,以帮助模型理解何时以及如何使用该工具。
importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;importorg.springframework.ai.tool.annotation.Tool;importorg.springframework.context.i18n.LocaleContextHolder;classDateTimeTools{@Tool(description="Get the current date and time in the user's timezone")StringgetCurrentDateTime(){returnLocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();}@Tool(description="Set a user alarm for the given time, provided in ISO-8601 format")voidsetAlarm(Stringtime){LocalDateTimealarmTime=LocalDateTime.parse(time,DateTimeFormatter.ISO_DATE_TIME);System.out.println("Alarm set for "+alarmTime);}}接下来,让这两个工具对模型都可用。我们将使用ChatClient与模型交互。我们将通过tools()方法传递一个DateTimeTools实例来向模型提供这些工具。当我们要求从现在开始10分钟后设置闹钟时,模型首先需要知道当前日期和时间。然后,它将使用当前日期和时间来计算闹钟时间。最后,它将使用闹钟工具来设置闹钟。在内部,ChatClient将处理来自模型的任何工具调用请求,并将任何工具调用执行结果发送回模型,以便模型可以生成最终响应。
ChatModelchatModel=...Stringresponse=ChatClient.create(chatModel).prompt("Can you set an alarm 10 minutes from now?").tools(newDateTimeTools()).call().content();System.out.println(response);在应用程序日志中,您可以检查闹钟是否已在正确的时间设置。