Tools工具使用

Tool的规范

视频讲解请参考:视频讲解

源码请参考:源码请参考

ToolCallback

AI模型调用的实例类接口。

scss 复制代码
/**
 * 
 * 表示一个工具的执行能被一个AI模型触发。
 */
public interface ToolCallback {

	/**
     * AI模型用工具的描述来决定什么时候和如何调用这个Tool
	 */
	ToolDefinition getToolDefinition();

	/**
     * 提供关于如何处理该工具的附加信息的元数据
	 */
	default ToolMetadata getToolMetadata() {
		return ToolMetadata.builder().build();
	}

	/**
	 * 使用给定的参数一起执行工具并返回结果并发送给AI 模型。
	 */
	String call(String toolInput);

	/**
    *使用给定的参数一起执行工具并返回结果并发送给AI 模型。
	 */
	default String call(String toolInput, @Nullable ToolContext toolContext) {
		if (toolContext != null && !toolContext.getContext().isEmpty()) {
			logger.info("By default the tool context is not used,  "
					+ "override the method 'call(String toolInput, ToolContext toolcontext)' to support the use of tool context."
					+ "Review the ToolCallback implementation for {}", getToolDefinition().name());
		}
		return call(toolInput);
	}

}

Spring AI 有 FunctionToolCallbackMethodToolCallback 的两个实现。

ToolDefinition

ToolDefinition 接口提供了AI model 的所需的信息,包括tool名称、描述和输入schema。ToolCallback实现必须提供ToolDefinition 实例来定义tool。

java 复制代码
public interface ToolDefinition {

	/**
	 * The tool name. Unique within the tool set provided to a model.
     * 工具名称,在提供给一个模型的集合中是唯一的
	 */
	String name();

	/**
	 * The tool description, used by the AI model to determine what the tool does.
     * 工具描述,给模型用于决定这个工具是做什么的
	 */
	String description();

	/**
	 * The schema of the parameters used to call the tool.
     * 用来调用tool的参数的结构
	 */
	String inputSchema();

	/**
	 * Create a default {@link ToolDefinition} builder.
	 */
	static DefaultToolDefinition.Builder builder() {
		return DefaultToolDefinition.builder();
	}

}

JSONSchema

Schema用于理解如何调用tool,并准备调用tool的参数。Spring AI 通过JsonSchemaGenerator 类,提供了生成schema的支持。JSONSchema是作为ToolDefinition的一部分进行提供的。

除了为Tool 本身提供描述外,还可以对tool的输入参数进行提供描述。描述可用于提供有关输入参数的关键信息,例如参数应该是什么格式、允许什么值等。这对于帮助 model 理解输入 schema 以及如何使用它很有用。Spring AI 使用以下注解之一为输入参数生成描述提供内置支持:

ToolParam的注解

ini 复制代码
@ToolParam(description = "结果的匹配分数,可以为空; 为空则返回查询的所有结果", required = false)

结果转换器

Tool call的结果使用ToolCallResultConverter序列化,然后发给AI model。

java 复制代码
/**
 * A functional interface to convert tool call results to a String that can be sent back
 * to the AI model.
 *
 * @author Thomas Vitale
 * @since 1.0.0
 */
@FunctionalInterface
public interface ToolCallResultConverter {

	/**
	 * Given an Object returned by a tool, convert it to a String compatible with the
	 * given class type.
	 */
	String convert(@Nullable Object result, @Nullable Type returnType);

}

将tool的结果转换成String类型返回。默认使用的是DefaultToolCallResultConverter序列化JSON,但是你也可以提供自己的结果转换器,通过实现ToolCallResultConverter接口。

自定义结果转换器

方法Tool Call 结果转换

可以通过注解@ToolresultConverter()属性来为tool提供自定义的ToolCallResultConverter

java 复制代码
public class CustomerTools {

    @Tool(description = "获取客户信息, 输入参数是用户id,类型是long,必须输入"
            ,resultConverter = CustomToolCallResultConverter.class
    )
    public Customer getCustomerInfo(Long id){
        //模拟通过数据库查询
        Customer customer = new Customer();
        customer.setId(id);
        customer.setAge(28);
        customer.setUserName("五五");
        return customer;
    }
}
java 复制代码
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.jetbrains.annotations.Nullable;
import org.springframework.ai.tool.execution.ToolCallResultConverter;

import java.lang.reflect.Type;

public class CustomToolCallResultConverter implements ToolCallResultConverter {
    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * ToolCallResultConverter 接口的作用是将工具方法的返回值对象转换为字符串,
     * 因为 AI 模型最终接收的是文本格式的结果。你需要将 Customer 对象序列化为 JSON 或其他可读格式。
     * @param result
     * @param returnType
     * @return
     */
    @Override
    public String convert(@Nullable Object result, @Nullable Type returnType) {
        if (result == null) {
            return "No customer found";
        }

        // 如果结果是 Customer 类型,转换为格式化的字符串
        if (result instanceof Customer customer) {
            try {
                // 方式1: 转换为 JSON 格式(推荐)
                String json = objectMapper.writeValueAsString(customer);
                return json;

                // 方式2: 转换为人类可读的自然语言描述
                // return String.format("Customer found - ID: %d, Name: %s, Age: %d",
                //         customer.getId(),
                //         customer.getUserName(),
                //         customer.getAge());

            } catch (JsonProcessingException e) {
                return "Error converting customer data: " + e.getMessage();
            }
        }
        // 其他类型的默认处理
        return result.toString();
    }
}

编程式Tool Call 结果转换

通过设置 MethodToolCallback.BuildertoolCallResultConverter() 属性来为 tool 提供自定义的自定义结果返回类。

less 复制代码
 Method method = ReflectionUtils.findMethod(CustomerTools.class, "getCustomerInfo", Long.class);
        MethodToolCallback customerToolCallback = MethodToolCallback.builder()
                .toolDefinition(
                        ToolDefinition.builder()
                                .description("获取客户信息, 输入参数是用户id,类型是long,必须输入")
                                .inputSchema(JsonSchemaGenerator.generateForMethodInput(method))
                                .name("getCustomerInfo")
                                .build()
                )
                .toolMethod(method)
                .toolObject(new CustomerTools())
                .toolCallResultConverter(new CustomToolCallResultConverter())
                .build();

Tool结果直接返回

默认情况下,tool call的结果作为响应返回model。然后model可以使用结果继续对话。

在某些情况下,可能希望将结果直接返回给调用者,而不是将其发送回model。

代码实现,在返回tool执行结果的类中封装了是否直接返回,并判断是否直接返回。

组装的话是在类:org.springframework.ai.model.tool.ToolCallingManager中

在类:com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel

使用方式:

returnDirect = true

ini 复制代码
public class CustomerTools {

    @Tool(description = "获取客户信息, 输入参数是用户id,类型是long,必须输入"
            ,resultConverter = CustomToolCallResultConverter.class
            ,returnDirect = true //设置直接返回
    )
    public Customer getCustomerInfo(Long id){
        //模拟通过数据库查询
        Customer customer = new Customer();
        customer.setId(id);
        customer.setAge(28);
        customer.setUserName("五五");
        return customer;
    }
}

如果是编程式的话,通过toolMetadata方式来配置

less 复制代码
        MethodToolCallback customerToolCallback = MethodToolCallback.builder()
                .toolDefinition(
                        ToolDefinition.builder()
                                .description("获取客户信息, 输入参数是用户id,类型是long,必须输入")
                                .inputSchema(JsonSchemaGenerator.generateForMethodInput(method))
                                .name("getCustomerInfo")
                                .build()
                )
                .toolMethod(method)
                .toolObject(new CustomerTools())
                .toolCallResultConverter(new CustomToolCallResultConverter())
                .toolMetadata(ToolMetadata.builder()
                        .returnDirect(true) //设置直接返回
                        .build()
                )
                .build();

ReactAgent中使用工具

直接使用

通过tools方法设置ToolCallback工具类型。可以配置多个。

scss 复制代码
/**
     * 通过tools方法直接使用tool
     */
    @Test
    public void test7() throws GraphRunnerException {
        ToolCallback weatherTool = FunctionToolCallback.builder("get weather",
                new WeatherTool())
                .description("Get weather for a given city")
                .inputType(WeatherToolRequest.class)
                .build();

        ToolCallback searchTool = FunctionToolCallback.builder("search",
                 new SearchTool())
                .description("Search for information")
                .inputType(SearchToolInput.class)
                .build();

        ChatModel chatModel = CreateChatClient.createDashScopeChatModel();

        ReactAgent agent = ReactAgent.builder()
                .name("my_agent")
                .tools(weatherTool,searchTool)
                .model(chatModel)
                .systemPrompt("You are a helpful assistant with access to weather and search tools.")
                .saver(new MemorySaver())
                .build();
        AssistantMessage message = agent.call("北京的天气怎么样");
        System.out.println(message.getText());
    }

适用场景:

  • 工具数量不是很多。
  • 工具定义在编译时已知。
  • 需要类型安全的工具定义。

方法工具

通过methodTools方法来传入带有注解@Tool注解方法的对象。这种方式简洁,直白。

java 复制代码
    public void test8() throws GraphRunnerException {
        ChatModel chatModel = CreateChatClient.createDashScopeChatModel();

        ReactAgent agent = ReactAgent.builder()
                .methodTools(new DateTimeTools()) // 通过method tools指定tool
                .name("my agent")
                .model(chatModel)
                .systemPrompt("You are a helpful assistant with date and time")
                .build();

        AssistantMessage message = agent.call("获取当前时间,并设置一个10分钟后的闹钟");
        System.out.println(message.getText());
    }

工具提供者

使用 ToolCallbackProvider 接口动态提供工具。这种方式适合需要根据运行时条件动态决定提供哪些工具的场景。

ini 复制代码
public void test9() throws GraphRunnerException {
        ToolCallback weatherTool = FunctionToolCallback.builder("get weather",
                        new WeatherTool())
                .description("Get weather for a given city")
                .inputType(WeatherToolRequest.class)
                .build();

        ToolCallback searchTool = FunctionToolCallback.builder("search",
                        new SearchTool())
                .description("Search for information")
                .inputType(SearchToolInput.class)
                .build();

        ToolCallbackProvider toolCallbackProvider = new CustomToolCallbackProvider(List.of(weatherTool, searchTool));
        //动态控制有哪些工具
        //ToolCallbackProvider toolCallbackProvider = new CustomToolCallbackProvider(List.of(weatherTool, searchTool),false);

        ChatModel chatModel = CreateChatClient.createDashScopeChatModel();
        ReactAgent agent = ReactAgent.builder()
                .name("my agent")
                .model(chatModel)
                .toolCallbackProviders(toolCallbackProvider)
                .systemPrompt("You are a helpful assistant with access to weather and search tools.")
                .build();

        AssistantMessage message = agent.call("北京的天气怎么样,今天发生了什么新闻");
        System.out.println(message.getText());

    }

工具名解析

通过toolNames()方法指定工具名称,配置resolver()方法提供的ToolCallbackResolver来解析工具。这种方式适合工具定义和工具使用分离的场景toolNames()方法必须与resolver()方法配合使用,否则抛出异常。

java 复制代码
/**
     * 工具名词解析方式使用Tool
     *
     */
    @Test
    public void test10() throws GraphRunnerException {
        ToolCallback weatherTool = FunctionToolCallback.builder("get weather",
                        new WeatherTool())
                .description("Get weather for a given city")
                .inputType(WeatherToolRequest.class)
                .build();

        ToolCallback searchTool = FunctionToolCallback.builder("search",
                        new SearchTool())
                .description("Search for information")
                .inputType(SearchToolInput.class)
                .build();

        StaticToolCallbackResolver resolver = new StaticToolCallbackResolver(List.of(weatherTool, searchTool));

        ChatModel chatModel = CreateChatClient.createDashScopeChatModel();
        ReactAgent agent = ReactAgent.builder()
                .name("my agent")
                .model(chatModel)
                .description("An agent with multiple tools")
                .instruction("You are a helpful assistant with access to calculator and search tools.")
                .toolNames("get weather", "search")
                .resolver(resolver)
                .build();

        AssistantMessage message = agent.call("北京天气怎么样?");
        System.out.println(message);

    }

注意点:工具可能动态变化,但是工具名词要保持稳定。

总结

方式 适用场景 优点 缺点
tools方式 工具数量少、定义简单 简单直接、类型安全 工具多时代码冗长
methodTools方式 工具方法定义在类中 代码组织清晰、易于维护 需要创建一个工具类
toolCallbackProviders 可以动态的提供工具 灵活、支持运行时决策 需要实现对应的接口,代码复杂度提高
toolNames和resolver 工具定义和使用分离 解耦、支持配置化。tool name和具体的tool分离 必须配置resolver
相关推荐
小林ixn1 小时前
从“酸辣土豆丝”到“马铃薯做法”:手把手教你用 RAG 实现语义搜索
人工智能·llm
睿智的羊2 小时前
Cove API 的 RAG 模块拆解:一套面向 Agent 的可组合知识检索工具体系
人工智能
love530love2 小时前
AI Agent + 本地 ComfyUI 无头模式实战:关闭 IDE 后 AI 独立重启并完成图文生成
ide·人工智能·windows·python·音视频·agent·devops
FriendshipT2 小时前
Ultralytics:解读Attention模块
人工智能·pytorch·python·深度学习·目标检测
生活爱好者!2 小时前
AI加持的笔记工具,比备忘录好用,NAS一键部署blinko
人工智能·笔记
IT_陈寒2 小时前
SpringBoot自动配置没生效?你可能漏了这个注解
前端·人工智能·后端
今日综合2 小时前
2026精选教务管理系统深度分析:功能差异、收费模式全拆解
大数据·人工智能
长明2 小时前
C#项目组织与概念梳理
后端·c#
SilentSamsara2 小时前
模型部署方案选型:REST/gRPC/批量推理/边缘部署的场景决策
人工智能·深度学习·算法·机器学习