chat - 工具(Tool)的四种定制与注册
2026年3月11日 下午5:04:45
1、函数工具的四种定制方式:
- 用
@ToolMapping注解方法开发 - 用
FunctionToolDesc动态申明开发 - 用
FunctionTool原始接口定制开发 - 用
AbsTool定制开发(介绍 FunctionTool 和 FunctionToolDesc 之间)
提示:所有工具的定制,也是 MCP Tool 的定制(通用)
方式一: ToolMapping 注解声明方式(比较简洁,一个类里可有多个函数工具)
我们定义个工具类,并设定一个 “天气查询” 函数和 “联网搜索” 的函数
import org.noear.solon.ai.annotation.ToolMapping;
import org.noear.solon.annotation.Param;
//可以加组件注解(支持注入和拦截)
public class Tools {
//天气查询
@ToolMapping(description = "获取指定城市的天气情况")
public String get_weather(@Param(name = "location", description = "根据用户提到的地点推测城市") String location) {
return "晴,24度"; //可使用 “数据库” 或 “网络” 接口根据 location 查询合适数据;
}
//订单查询
@ToolMapping(description = "联网查询")
public String web_search(@Param(name = "query", description = "查询关键字(以空隔隔开)") String query) {
return "...";
}
//...//可以加其它注解函数
}
应用参考:
public void case3() throws IOException {
ChatResponse resp = chatModel
.prompt("今天杭州的天气情况?")
.options(o -> o.toolAdd(new MethodToolProvider(new Tools())) //会自动匹配天气函数
.toolAdd(new Tools2()) //也可以省略 MethodToolProvider(内部自动转换)
.call();
}
方式二: FunctionToolDesc 构建声明方式(适合动态构建)
定制示例:
FunctionToolDesc weatherTool = new FunctionToolDesc("get_weather")
.description("获取指定城市的天气情况")
.stringParamAdd("location", "根据用户提到的地点推测城市")
.doHandle(map -> {
return "24度";
});
应用参考:
public void case3() throws IOException {
ChatResponse resp = chatModel
.prompt("今天杭州的天气情况?")
.options(o -> o.toolsAdd(weatherTool)) //会自动匹配天气函数
.call();
}
方式三: FunctionTool 原始接口实现方式(适合高级定制,一般改用 AbsTool 更简便)
定制示例:
//可以加组件注解(支持注入和拦截)
public class WeatherTool implements FunctionTool {
private List<ParamDesc> params = new ArrayList<>();
public WeatherTool() {
//友好的描述,有助于大模型推测参数值
params.add(new ParamDesc("location", String.class, true, "根据用户提到的地点推测城市"));
}
@Override
public String name() {
return "get_weather";
}
@Override
public String description() {
//友好的描述,有助于大模型组织回复消息
return "获取指定城市的天气情况";
}
@Override
public boolean returnDirect() {
return false;
}
@Override
public ONode inputSchema() {
return ToolSchemaUtil.buildToolParametersNode(params, new ONode());
}
@Override
public String handle(Map<String, Object> args) {
String location = (String) args.get("location");
if(location == null) {
//大模型有可能会识别失败
throw new IllegalStateException("arguments location is null (Assistant recognition failure)");
}
return "24度";// 可使用 “数据库” 或 “网络” 接口根据 location 查询合适数据;
}
}
应用参考:
public void case3() throws IOException {
ChatResponse resp = chatModel
.prompt("今天杭州的天气情况?")
.options(o -> o.toolsAdd(new WeatherTool())) //会自动匹配天气函数
.call();
}
方式四: AbsTool 扩展的实现方式(比 FunctionTool 简洁)
定制示例(以上面的 WeatherTool 为例):
//可以加组件注解(支持注入和拦截)
public class WeatherTool extends AbsTool {
public WeatherTool() {
//友好的描述,有助于大模型推测参数值
addParam("location", String.class, true, "根据用户提到的地点推测城市"));
}
@Override
public String description() {
//友好的描述,有助于大模型组织回复消息
return "获取指定城市的天气情况";
}
@Override
public String handle(Map<String, Object> args) {
String location = (String) args.get("location");
if(location == null) {
//大模型有可能会识别失败
throw new IllegalStateException("arguments location is null (Assistant recognition failure)");
}
return "24度";// 可使用 “数据库” 或 “网络” 接口根据 location 查询合适数据;
}
}
2、工具的注册(添加)和作用域
- 作为默认工具(是即每次请求时都会附加)。可在语言模型构建时添加。
public void case3() throws IOException {
ChatModel.of("http://127.0.0.1:11434/api/chat")
.provider("ollama")
.model("llama3.2")
.defaultToolAdd(new WeatherTool()) //添加默认工具(即所有请求可用)
.defaultToolAdd(new WeatherTool2()) //可以添加多套工具(只是示例下)
.build();
ChatResponse resp = chatModel
.prompt("今天杭州的天气情况?")
.call();
//打印消息
log.info("{}", resp.getMessage());
}
- 作为请求工具(当次请求时附加)。和全局工具相比,只是作用域不同。
public void case3() throws IOException {
ChatModel.of("http://127.0.0.1:11434/api/chat")
.provider("ollama")
.model("llama3.2")
.build();
ChatResponse resp = chatModel
.prompt("今天杭州的天气情况?")
.options(o -> o.toolAdd(new WeatherTool())) //添加请求函数
.call();
//打印消息
log.info("{}", resp.getMessage());
}