工具调用算是基础功能中的最后一块拼图了
实际上工具调用并不是让大模型调用其他的工具软件,而是将代码工程中的一些接口开放给大模型使用,比如下面的样例
最小化样例
/*** 调用工具* 可以使用toolContext传递参数* @param userInput* @return*/@GetMapping("/ai/tool")String generation(String userInput){return this.chatClient.prompt().user(userInput).tools(new DateTimeTools()).call().content();}class DateTimeTools
{@Tool(description = "获取当前日期时间")String getCurrentDateTime(){return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();}}
工具调用共分两步:
1)声明:在想要开放给大模型使用的方法上添加@Tool
2)注册:调用请求时通过tools方法注册工具类
注解说明
Tool注解:用来标注作为工具的方法,有下列属性:
name:名称,唯一识别该方法,不可重复
description:描述,方便大模型理解工具的作用
returnDirect:工具调用后,是直接返回,还是将调用结果送往大模型,默认送往大模型
resultConverter:结果转换器
ToolParam注解:搭配Tool注解使用,用来对方法参数进行说明,有下列属性:
required:该参数是否必填,默认是
description:描述,方便大模型理解该参数的作用
进阶知识
大概了解了如何使用后,我们来看看工具调用的原理和相关接口及实现。
工具调用原理
整体步骤
如下图所示,共分为6步:
1.发送带有工具定义的请求到大模型
2.大模型返回是否需要调用工具,若需要,则同时返回当符合预定义模式的输入参数的响应。
3. 应用程序负责根据工具名称识别对应工具,并使用提供的输入参数执行该工具。
4. 工具调用的结果由应用程序进行处理。
5. 应用程序将工具调用结果返回至模型。
6. 模型最终利用工具调用结果作为附加上下文生成响应
执行链路
了解了大概步骤,我们来跟踪解析一下spring-ai框架的内部代码,主要分为2个视角:
注册时:即调用ChatClient的tools方法时,框架会将对象交给MethodToolCallbackProvider,由其对该对象进行扫描,识别出被Tool注解标记的方法,并将其转换为ToolCallback列表。
调用时:即调用ChatClient的call方法时(实际为获取结果时),会调用对应底层ChatModel的call方法,此时可以从请求前和请求后来分析代码:
请求前:在ChatModel的createRequest方法中,获取每个ToolCallback中的ToolDefinition(工具定义),并加入到请求参数中。
请求后:ToolExecutionEligibilityPredicate.isToolExecutionRequired方法根据大模型的响应确定是否需要工具调用;若需要,ToolCallingManager.executeToolCalls则根据大模型响应中的ToolCall(包括工具名和调用参数)找到对应的ToolCallback对象,调用其call方法;调用完后,判断是否直接返回,若不直接返回,则将工具响应追加到提示词中并发送给大模型。
相关接口及实现
主要接口
接口 | ToolCallbackProvider | ToolCallingManager | ToolCallback | ToolCallResultConverter |
实现类 | MethodToolCallbackProvider | DefaultToolCallingManager | MethodToolCallback | DefaultToolCallResultConverter |
产出 | ToolCallback | ToolExecutionResult | String | String |
作用 | 注册时将对象转换为ToolCallback | 执行工具调用 | 工具的封装类 | 结果转换器,将工具执行结果转换为字符串 |
备注 | ToolCallback包含ToolDefinition、ToolMetadata等子元素和call方法 | 内部调用ToolCallback得到String,将其封装为InternalToolExecutionResult,然后进一步处理为ToolExecutionResult | 内部调用被Tool注解的方法得到Object,然后调用ToolCallResultConverter得到String | 将Object转换为String |
ToolDefinition:工具定义,包含名称、描述、入参格式等。
ToolMetadata:工具元数据,包含是否直接返回等信息。
ToolExecutionEligibilityPredicate:判断是否需要调用工具(AssistantMessage中的toolCalls不为空)
ps:FunctionCallback已过时,推荐使用ToolCallback