ToolCalling
实时信息获取不到,LLM大模型搞不定实时信息。 所有现在要使用Tool Calling
spring官网: docs.spring.io/spring-ai/r…
spring ai alibaba官网: java2ai.com/docs/framew…
ToolCalling是什么
Tool Calling: LLM的外部utils工具类
- ToolCalling允许大模型与一组API或工具进行交互,将LLM的智能与外部工具或API无缝衔接,从而增强大模型功能。
- LLM大模型本身不能实际调用工具,只指示应该调用哪个函数以及如何调用
ToolCalling能做什么?
- 实时信息访问(比如天气、股票信息等)
- 执行某种工具类/辅助类操作
ToolCalling 工作流程
- 当我们想要使 tool 可用于 model 时,我们在聊天请求中包含其定义。每个 tool 定义包括名称、描述和输入参数的 schema。
- 当 model 决定调用 tool 时,它发送带有 tool 名称和根据定义 schema 建模的输入参数的响应。
- 应用程序负责使用 tool 名称来识别并使用提供的输入参数执行 tool。
- Tool call 的结果由应用程序处理。
- 应用程序将 tool call 结果发送回 model。
- Model 使用 tool call 结果作为附加上下文生成最终响应。
开发步骤
创建module
POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.miao</groupId>
<artifactId>SpringAIAlibaba-test01</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>SAA-10ToolCalling</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 模型服务灵积 调用alibaba生态的协议 对标openai协议 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>1.0.0.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
</dependency>
</dependencies>
</project>
写yml
server:
port: 8082
servlet:
encoding:
enabled: true
force: true
charset: UTF-8
spring:
application:
name: SAA-10
ai:
dashscope:
api-key: ${qwen-api-key}
chat:
options:
model: qwen3-vl-flash
主启动类
package com.miao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SAA10ToolCallingApplication {
public static void main(String[] args) {
SpringApplication.run(SAA10ToolCallingApplication.class, args);
}
}
业务类
config配置
package com.miao.config;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SaaLLMConfig {
private static final String QWEN_MODEL = "qwen3-max";
private static final String DEEPSEEK_MODEL = "deepseek-v3.1";
@Value("${spring.ai.dashscope.url")
private String qwenUrl;
@Bean(name = "deepseek")
public ChatModel deepSeek() {
return DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi.builder()
.apiKey(System.getenv("qwen-api-key"))
.build())
.defaultOptions(DashScopeChatOptions.builder()
.withModel(DEEPSEEK_MODEL)
.build())
.build();
}
@Bean(name = "qwen")
public ChatModel qwen() {
return DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi.builder()
.apiKey(System.getenv("qwen-api-key"))
.build())
.defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build())
.build();
}
@Bean(name = "deepseekChatClient")
public ChatClient deepSeekChatClient(@Qualifier("deepseek") ChatModel deepseekModel) {
return ChatClient.builder(deepseekModel)
.defaultOptions(ChatOptions.builder().model(DEEPSEEK_MODEL).build())
.build();
}
@Bean(name = "qwenChatClient")
public ChatClient qwenChatClient(@Qualifier("qwen") ChatModel qwenModel) {
return ChatClient.builder(qwenModel)
.defaultOptions(ChatOptions.builder().model(QWEN_MODEL).build())
.build();
}
}
tools工具
package com.miao.utils;
import org.springframework.ai.tool.annotation.Tool;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeTools {
/**
* returnDirect = false 表示返回结果不直接返回给用户,而是作为后续处理的输入
* returnDirect = true 表示返回结果直接返回给用户
*
* 如果没有msg入参,直接抛出异常,所以在此处加了一共没有什么用的参数
*/
@Tool(name = "get_cur_time", description = "获取当前时间", returnDirect = false)
public String getCurrentDateTime(String msg) {
return LocalDateTime.now().toString();
}
}
controller
package com.miao.controller;
import com.miao.utils.DateTimeTools;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.tool.ToolCallingChatOptions;
import org.springframework.ai.support.ToolCallbacks;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RestController
public class ToolCallingController {
@Resource
private ChatModel deepseek;
@Resource
private ChatClient deepseekChatClient;
@GetMapping(value = "/toolCalling")
public Object toolCalling(@RequestParam(name = "msg", defaultValue = "现在多少年 几点几分了") String msg) {
// 1 工具类注册到工具集里面
ToolCallback[] tools = ToolCallbacks.from(new DateTimeTools());
// 2将工具类配置进入ChatOptions对象
ChatOptions toolOptions = ToolCallingChatOptions
.builder()
.toolCallbacks(tools)
.build();
// 3 构建提示词
Prompt prompt = new Prompt(msg, toolOptions);
return deepseek.call(prompt).getResult().getOutput().getText();
}
@GetMapping(value = "/chatClientToolCalling")
public Flux<String> chatClientToolCalling(@RequestParam(name = "msg", defaultValue = "现在多少年 几点几分了") String msg) {
return deepseekChatClient.prompt(msg)
.tools(new DateTimeTools())
.stream()
.content();
}
}