1、pom文件
XML
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-tool-calling-baidutranslate</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-tool-calling-weather</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit-jupiter.version}</version>
</dependency>
</dependencies>
2、yml文件,由于本机ollama上的模型支持的function call 时好时坏,所以使用阿里的
dashscope的qwq-plus模型
html
spring:
ai:
alibaba:
toolcalling:
baidutranslate:
enabled: true
app-id: xxxxxxxxxx
secret-key: yyyyyyyyy
time:
enabled: true
weather:
enabled: true
api-key: ${WEATHER_API_KEY}
dashscope:
api-key: sk-xoxoxoxoxoxo
chat:
model: qwq-plus
embedding:
model: text-embedding-v2
3、百度翻译的appid和key
java
package com.alibaba.cloud.ai.toolcall.component.baidutranslate;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "spring.ai.alibaba.toolcalling.baidutranslate")
public class BaidutranslateProperties {
private String appId;
private String secretKey;
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
}
4、百度翻译的tool
java
package com.alibaba.cloud.ai.toolcall.component.baidutranslate.method;
import com.alibaba.cloud.ai.toolcall.component.baidutranslate.BaidutranslateProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.http.HttpHeaders;
import org.springframework.util.DigestUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
/**
* @author yingzi
* @date 2025/3/27:11:13
*/
public class BaidutranslateTools {
private static final Logger logger = LoggerFactory.getLogger(BaidutranslateTools.class);
private static final String TRANSLATE_HOST_URL = "https://fanyi-api.baidu.com/api/trans/vip/translate";
private static final Random random = new Random();
private final WebClient webClient;
private final String appId;
private final String secretKey;
public BaidutranslateTools(BaidutranslateProperties properties) {
assert StringUtils.hasText(properties.getAppId());
this.appId = properties.getAppId();
assert StringUtils.hasText(properties.getSecretKey());
this.secretKey = properties.getSecretKey();
this.webClient = WebClient.builder()
.defaultHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded")
.build();
}
@Tool(description = "Baidu translation function for general text translation")
public Map<String, String> baiduTranslateMethod(@ToolParam(description = "Content that needs to be translated") String q,
@ToolParam(description = "Source language that needs to be translated") String from,
@ToolParam(description = "Target language to translate into") String to) {
if (!StringUtils.hasText(q) || !StringUtils.hasText(from)
|| !StringUtils.hasText(to)) {
return null;
}
String salt = String.valueOf(random.nextInt(100000));
String sign = DigestUtils.md5DigestAsHex((appId + q + salt + secretKey).getBytes());
String url = UriComponentsBuilder.fromHttpUrl(TRANSLATE_HOST_URL).toUriString();
try {
MultiValueMap<String, String> body = constructRequestBody(q, from, to, salt, sign);
Mono<String> responseMono = webClient.post().uri(url).bodyValue(body).retrieve().bodyToMono(String.class);
String responseData = responseMono.block();
assert responseData != null;
logger.info("Translation request: {}, response: {}", q, responseData);
return parseResponse(responseData);
}
catch (Exception e) {
logger.error("Failed to invoke translate API due to: {}", e.getMessage());
return null;
}
}
private MultiValueMap<String, String> constructRequestBody(String q, String from, String to, String salt, String sign) {
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("q", q);
body.add("from", from);
body.add("to", to);
body.add("appid", appId);
body.add("salt", salt);
body.add("sign", sign);
return body;
}
private Map<String, String> parseResponse(String responseData) {
ObjectMapper mapper = new ObjectMapper();
try {
Map<String, String> translations = new HashMap<>();
TranslationResponse responseList = mapper.readValue(responseData, TranslationResponse.class);
String to = responseList.to;
List<TranslationResult> translationsList = responseList.trans_result;
if (translationsList != null) {
for (TranslationResult translation : translationsList) {
String translatedText = translation.dst;
translations.put(to, translatedText);
logger.info("Translated text to {}: {}", to, translatedText);
}
}
return translations;
}
catch (Exception e) {
try {
Map<String, String> responseList = mapper.readValue(responseData,
mapper.getTypeFactory().constructMapType(Map.class, String.class, String.class));
logger.info(
"Translation exception, please inquire Baidu translation api documentation to info error_code:{}",
responseList);
return responseList;
}
catch (Exception ex) {
logger.error("Failed to parse json due to: {}", ex.getMessage());
return null;
}
}
}
public record TranslationResult(String src, String dst) {
}
public record TranslationResponse(String from, String to, List<TranslationResult> trans_result) {
}
}
5、翻译 controller
java
package com.alibaba.cloud.ai.toolcall.controller;
import com.alibaba.cloud.ai.toolcall.component.baidutranslate.BaidutranslateProperties;
import com.alibaba.cloud.ai.toolcall.component.baidutranslate.method.BaidutranslateTools;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/translate")
public class TranslateController {
private final ChatClient dashScopeChatClient;
private final BaidutranslateProperties baidutranslateProperties;
public TranslateController(ChatClient.Builder chatClientBuilder, BaidutranslateProperties baidutranslateProperties) {
this.dashScopeChatClient = chatClientBuilder.build();
this.baidutranslateProperties = baidutranslateProperties;
}
/**
* 无工具版
*/
@GetMapping("/chat")
public String simpleChat(@RequestParam(value = "query", defaultValue = "帮我把以下内容翻译成英文:你好,世界。") String query) {
return dashScopeChatClient.prompt(query).call().content();
}
/**
* 调用工具版 - function
*/
@GetMapping("/chat-tool-function")
public String chatTranslateFunction(@RequestParam(value = "query", defaultValue = "帮我把以下内容翻译成英文:你好,世界。") String query) {
return dashScopeChatClient.prompt(query).tools("baiduTranslateFunction").call().content();
}
/**
* 调用工具版 - method
*/
@GetMapping("/chat-tool-method")
public String chatTranslateMethod(@RequestParam(value = "query", defaultValue = "帮我把以下内容翻译成英文:你好,世界。") String query) {
// 从配置文件中,获取,自动加载
return dashScopeChatClient.prompt(query).tools(new BaidutranslateTools(baidutranslateProperties)).call().content();
}
}
6、不带工具测试如下

7、带工具测试如下
