Spring AI Tool Calling 工具调用实战:让大模型真正执行任务

大语言模型很擅长理解意图、生成文本和组织答案,但它本身并不能直接访问企业系统,也不能凭空查询实时数据、写入数据库、发送邮件、提交工单或控制设备。想让 AI 从“会回答”走向“会办事”,就需要把模型和外部能力连接起来。

Tool Calling 就是为了解决这个问题而出现的一种应用模式。它允许大语言模型根据用户请求,智能选择并调用开发者预先定义好的函数、API 或服务,再把执行结果带回对话流程中。模型负责理解、规划和选择工具,真正的业务动作由应用系统执行。

可以把大模型理解成一个知识丰富的“大脑”。它知道你想做什么,也能推理出下一步该调用什么能力,但如果没有接入订座系统、订单系统、数据库或第三方接口,它就无法真正完成动作。Tool Calling 相当于给这个“大脑”配上了可操作的“手脚”:模型判断要做什么,Spring AI 负责把工具描述交给模型、接收模型的调用请求、执行本地工具并返回结果。

Tool Calling 和 Function Calling 的关系

Function Calling 是更早、更具体的说法,通常指模型请求调用开发者定义的某个函数。这里的函数往往就是 Java 代码中的一个方法。

Tool Calling 是更通用的概念。工具可以是函数,也可以是外部 API、数据库查询、文件操作、业务服务或工作流入口。在 Spring AI 的实际开发中,一个 Tool 往往就是一个 Function,所以二者在日常讨论中经常混用;只是从抽象层次看,Tool Calling 覆盖面更广。

简单理解:

  • Function Calling 更强调“调用一个函数”。
  • Tool Calling 更强调“模型可以使用一组外部能力”。
  • 在 Spring AI 中,开发者通常通过 Java 方法、注解或 ToolCallback 把业务能力暴露给模型。

典型应用场景

第一类场景是信息检索。

模型无法天然获得实时信息,也无法直接读取企业内部数据库。例如用户询问“今天上海天气怎么样”“查询订单 10086 的状态”“这位客户最近一次服务记录是什么”,模型单独回答容易出现过期或虚构信息。此时可以提供天气查询、订单查询、客户信息查询等工具,让模型在需要时主动调用。

第二类场景是执行动作。

模型可以生成计划,但不能直接落实计划。例如它可以帮用户规划北京旅行路线,但无法真正预订酒店;它可以理解“帮我发一封提醒邮件”,但不能直接访问邮件系统;它可以判断“需要创建一个售后工单”,但没有工具就不能写入工单表。接入 Tool Calling 后,模型可以把意图转成结构化参数,由业务系统完成真正的操作。

常见落地场景包括:

  • 查询天气、时间、汇率、库存、订单、客户资料等实时信息。
  • 创建工单、发送邮件、提交表单、预约会议、写入数据库。
  • 调用内部服务完成审批、派单、告警、设备控制。
  • 在 Agent 应用中把复杂任务拆成多个工具步骤自动执行。

快速接入 Tool Calling

在 Spring AI 中使用工具调用,通常需要先引入 JSON Schema 生成相关依赖。模型需要知道工具参数的结构,Spring AI 会基于方法签名和参数注解生成输入参数 schema。

<dependency>
    <groupId>com.github.victools</groupId>
    <artifactId>jsonschema-generator</artifactId>
    <version>4.37.0</version>
</dependency>

接下来定义一个工具类。工具通过 @Tool 标记,description 非常关键,因为模型会根据描述判断什么时候应该调用这个工具。

下面的 DateTimeTools 暴露了两个能力:一个用于获取当前时间,一个用于设置闹钟。

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.context.i18n.LocaleContextHolder;

public class DateTimeTools {

    @Tool(description = "Get the current date and time in the user's timezone")
    String getCurrentDateTime() {
        return LocalDateTime.now()
                .atZone(LocaleContextHolder.getTimeZone().toZoneId())
                .toString();
    }

    @Tool(description = "Set a user alarm for the given time, provided in ISO-8601 format")
    void setAlarm(String time) {
        LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("Alarm set for " + alarmTime);
    }
}

然后在调用模型时把工具提供给 ChatClient

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/chat")
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @RequestMapping("/call")
    public String call(String prompt) {
        return chatClient.prompt()
                .user(prompt)
                .tools(new DateTimeTools())
                .call()
                .content();
    }
}

当用户访问:

http://127.0.0.1:8080/chat/call?prompt=现在几点了

模型会发现这个问题需要实时信息,于是请求调用 getCurrentDateTime。Spring AI 执行工具后,把结果交回模型,模型再生成最终回复。

当用户访问:

http://127.0.0.1:8080/chat/call?prompt=帮我订3点的闹钟

模型会根据工具描述和参数结构调用 setAlarm,应用程序负责执行具体逻辑。

如果移除 .tools(new DateTimeTools()),模型就只能基于自身能力回答。对于“现在几点了”这种实时问题,它通常会表示无法获取实时信息;对于“设置闹钟”这种执行型任务,它也只能给出操作建议,而不能真正执行。

这正是 Tool Calling 的价值:让模型不只会“说”,还能够通过应用系统“做”。

请求与响应流程

Tool Calling 背后不是魔法,而是一套标准化的请求响应流程。

首先,应用程序在调用模型时注册工具。注册内容包括工具名称、工具描述和输入参数结构。工具描述尤其重要,它是模型判断是否调用工具的核心依据。描述越清晰,模型越容易在合适的时机选择正确工具。

其次,模型根据用户输入做决策。如果它判断普通文本回答就足够,会直接生成内容;如果它判断需要外部能力,就会返回一个工具调用请求,其中包含工具名称和符合 schema 的参数。

然后,Spring AI 根据工具名称找到对应的工具,并使用模型提供的参数执行实际逻辑。工具可以是一个 Java 方法,也可以包装外部 API 或业务服务。

工具执行完成后,应用程序拿到结果。默认情况下,这个结果会再次发送给模型,让模型结合结果组织出面向用户的最终回复。

最后,模型返回自然语言答案。用户看到的是一句完整的回复,但在系统内部,可能已经完成了工具选择、参数生成、工具执行和结果整合。

以点咖啡为例,可以把流程拆成这样:

  1. 应用告诉模型:现在有一个 orderCoffee 工具,可以根据 coffeeTypesize 下单。
  2. 用户说:“帮我点一杯大杯拿铁。”
  3. 模型判断需要调用工具,并生成参数:coffeeType=拿铁size=大杯
  4. 应用执行 orderCoffee,调用订单系统完成下单。
  5. 订单系统返回:“订单创建成功,订单号是 #12345。”
  6. 模型基于结果回复:“好的,已为您下单大杯拿铁,订单号是 #12345。”

在这个过程中,模型负责理解和决策,ToolCallingManagerToolCallback 负责解析、匹配和执行工具。

声明式定义工具

Spring AI 提供了两种把 Java 方法转换为工具的方式:声明式和编程式。

声明式方式使用 @Tool 注解,写法简单,适合大多数业务工具。

@Tool 的核心属性如下:

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Tool {

    String name() default "";

    String description() default "";

    boolean returnDirect() default false;

    Class<? extends ToolCallResultConverter> resultConverter()
            default DefaultToolCallResultConverter.class;
}

name 用于指定工具名称。如果不指定,默认使用方法名。模型调用工具时会使用这个名称,因此同一组工具中不应出现重复名称。

description 用于描述工具能力。它会直接影响模型是否能正确选择工具。不要写成“处理数据”这种模糊描述,应尽量写清楚工具做什么、适合什么场景、需要什么输入。

returnDirect 用于控制工具执行结果是否直接返回调用方。默认值是 false,表示工具结果会先交回模型,让模型继续生成自然语言回复。

resultConverter 用于指定工具结果转换器。Spring AI 默认会把工具调用结果转换为字符串,如果业务需要返回特殊结构,可以自定义转换器。

例如:

@Tool(
        description = "Get the current date and time in the user's timezone",
        returnDirect = true
)
String getCurrentDateTime() {
    return "现在时间是 2000-01-01 12:00";
}

returnDirect = true 时,调用方会直接拿到工具结果:

现在时间是 2000-01-01 12:00

returnDirect = false 时,结果会先返回模型,模型可能再包装成更自然的回复:

现在时间是 2000-01-01 12:00。需要我继续帮你安排什么吗?

使用 JSON Schema 描述工具参数

模型调用工具时,需要知道参数长什么样、哪些字段必填、字段类型是什么。Spring AI 会自动为 @Tool 方法的输入参数生成 JSON Schema。

JSON Schema 可以理解为 JSON 数据的“填写说明”。它描述对象有哪些字段、字段是什么类型、是否必填、是否有枚举值或格式限制。

例如一个用户对象:

{
  "name": "Alice",
  "age": 28,
  "email": "alice@example.com",
  "hobbies": ["reading", "swimming"]
}

对应的 schema 可以写成:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "User",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "用户姓名"
    },
    "age": {
      "type": "integer",
      "minimum": 0,
      "description": "用户年龄"
    },
    "email": {
      "type": "string",
      "format": "email",
      "description": "电子邮箱地址"
    },
    "hobbies": {
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  },
  "required": ["name", "age", "email"]
}

在工具调用中,schema 的作用就是告诉模型:“调用这个工具时,请按这个结构传参。”

对于工具参数,可以使用 @ToolParam 补充描述。

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;

class DateTimeTools {

    @Tool(description = "Set a user alarm for the given time")
    void setAlarm(@ToolParam(description = "Time in ISO-8601 format") String time) {
        LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("Alarm set for " + alarmTime);
    }
}

@ToolParam 可以声明参数描述和是否必填。默认情况下,方法输入参数会被视为必填;如果参数标记了 @Nullable,则会被视为可选,除非显式用 @ToolParam(required = true) 标记为必填。

将工具挂载到 ChatClient 和 ChatModel

声明式工具可以作为默认工具挂载到 ChatClient。默认工具适合那些几乎所有对话都可能使用的基础能力。

ChatModel chatModel = ...

ChatClient chatClient = ChatClient.builder(chatModel)
        .defaultTools(new DateTimeTools())
        .build();

也可以在单次请求中动态传入工具:

String content = chatClient.prompt()
        .user("现在几点了")
        .tools(new DateTimeTools())
        .call()
        .content();

如果同时配置默认工具和运行时工具,运行时工具会覆盖默认工具。这样可以针对不同请求提供不同工具集,避免模型看到过多无关工具。

如果直接使用 ChatModel,可以通过 ToolCallingChatOptions 传入工具回调。

ChatModel chatModel = ...

ToolCallback[] dateTimeTools = ToolCallbacks.from(new DateTimeTools());

ChatOptions chatOptions = ToolCallingChatOptions.builder()
        .toolCallbacks(dateTimeTools)
        .build();

Prompt prompt = new Prompt("What day is tomorrow?", chatOptions);
chatModel.call(prompt);

编程式定义工具

声明式方式足够简洁,但有些场景需要更细粒度地控制工具元信息、目标方法和对象实例。这时可以使用 MethodToolCallback 编程式构建工具。

先定义一个普通 Java 方法:

public class WeatherTools {

    String getCurrentWeatherByCityName(String cityName) {
        return switch (cityName) {
            case "北京" -> "北京今天天气:晴空万里";
            case "上海" -> "上海今天天气:电闪雷鸣";
            case "广州" -> "广州今天天气:细雨蒙蒙";
            default -> "没有该城市的天气信息";
        };
    }
}

再通过反射找到方法,并把它包装成 ToolCallback

import java.lang.reflect.Method;

import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.definition.ToolDefinitions;
import org.springframework.ai.tool.method.MethodToolCallback;
import org.springframework.util.ReflectionUtils;

Method method = ReflectionUtils.findMethod(
        WeatherTools.class,
        "getCurrentWeatherByCityName",
        String.class
);

ToolCallback toolCallback = MethodToolCallback.builder()
        .toolDefinition(ToolDefinitions.builder(method)
                .description("根据给定的城市名称,获取当前城市的天气")
                .build())
        .toolMethod(method)
        .toolObject(new WeatherTools())
        .build();

ChatClient 中可以这样使用:

@RequestMapping("/call")
public String call(String prompt) {
    Method method = ReflectionUtils.findMethod(
            WeatherTools.class,
            "getCurrentWeatherByCityName",
            String.class
    );

    ToolCallback weatherTools = MethodToolCallback.builder()
            .toolDefinition(ToolDefinitions.builder(method)
                    .description("根据给定的城市名称,获取城市当前的天气")
                    .build())
            .toolMethod(method)
            .toolObject(new WeatherTools())
            .build();

    return chatClient.prompt()
            .toolCallbacks(weatherTools)
            .user(prompt)
            .call()
            .content();
}

更推荐把工具回调抽成 Spring Bean,方便复用和统一管理。

import java.lang.reflect.Method;

import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.definition.ToolDefinitions;
import org.springframework.ai.tool.method.MethodToolCallback;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;

@Configuration
public class ToolConfig {

    @Bean
    public ToolCallback weatherToolCallback() {
        Method method = ReflectionUtils.findMethod(
                WeatherTools.class,
                "getCurrentWeatherByCityName",
                String.class
        );

        return MethodToolCallback.builder()
                .toolDefinition(ToolDefinitions.builder(method)
                        .description("根据给定的城市名称,获取城市当前的天气")
                        .build())
                .toolMethod(method)
                .toolObject(new WeatherTools())
                .build();
    }
}

然后在控制器构造方法中注入:

@RestController
@RequestMapping("/chat")
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatModel chatModel, ToolCallback weatherTools) {
        this.chatClient = ChatClient.builder(chatModel)
                .defaultToolCallbacks(weatherTools)
                .build();
    }

    @RequestMapping("/call")
    public String call(String prompt) {
        return chatClient.prompt()
                .user(prompt)
                .call()
                .content();
    }
}

如果直接调用 ChatModel,仍然通过 ToolCallingChatOptions 传入:

ChatModel chatModel = ...
ToolCallback toolCallback = ...

ChatOptions chatOptions = ToolCallingChatOptions.builder()
        .toolCallbacks(toolCallback)
        .build();

Prompt prompt = new Prompt("北京今天天气怎么样?", chatOptions);
chatModel.call(prompt);

ToolCallback:工具调用的统一入口

ToolCallback 是 Spring AI 中工具调用的核心接口。它描述了“一个工具”最基本需要具备的能力:告诉模型自己是什么、接收模型传来的参数、执行逻辑并返回结果。

核心结构可以概括为:

public interface ToolCallback {

    ToolDefinition getToolDefinition();

    default ToolMetadata getToolMetadata() {
        return ToolMetadata.builder().build();
    }

    String call(String toolInput);

    default String call(String toolInput, @Nullable ToolContext toolContext) {
        if (toolContext != null && !toolContext.getContext().isEmpty()) {
            throw new UnsupportedOperationException("Tool context is not supported!");
        }
        return this.call(toolInput);
    }
}

getToolDefinition() 返回工具定义,包括名称、描述和输入参数 schema。模型正是依靠这些信息判断是否调用该工具。

getToolMetadata() 返回额外元数据,主要用于框架扩展,不影响核心调用逻辑。

call(String toolInput) 是真正执行工具的方法。toolInput 通常是模型生成的 JSON 字符串参数,工具执行后返回字符串结果。

ToolContextcall 方法用于支持额外上下文。默认实现不支持非空上下文,具体实现类可以重写它。

MethodToolCallback:把 Java 方法包装成工具

MethodToolCallback 是 Spring AI 将普通 Java 方法包装成可调用工具的重要实现。它内部持有工具定义、目标方法、目标对象和结果转换器。

可以把它理解成一层适配器:模型看到的是标准工具,应用内部执行的是普通 Java 方法。

核心字段包括:

public final class MethodToolCallback implements ToolCallback {

    private static final ToolCallResultConverter DEFAULT_RESULT_CONVERTER =
            new DefaultToolCallResultConverter();

    private static final ToolMetadata DEFAULT_TOOL_METADATA =
            ToolMetadata.builder().build();

    private final ToolDefinition toolDefinition;

    private final ToolMetadata toolMetadata;

    private final Method toolMethod;

    @Nullable
    private final Object toolObject;

    private final ToolCallResultConverter toolCallResultConverter;
}

其中:

  • toolDefinition 告诉模型工具名称、描述和参数结构。
  • toolMethod 是通过反射拿到的 Java 方法。
  • toolObject 是方法所属对象,非静态方法执行时需要它。
  • toolCallResultConverter 负责把方法返回值转换成模型可处理的字符串。

ToolDefinition:让模型理解工具

ToolDefinition 提供模型识别工具所需的元信息。每个 ToolCallback 都必须提供一个 ToolDefinition

public interface ToolDefinition {

    String name();

    String description();

    String inputSchema();
}

name() 是工具名称,在提供给模型的一组工具中应保持唯一。

description() 是工具描述,模型会使用它判断工具功能和调用时机。

inputSchema() 是工具参数结构,用于约束模型生成正确的调用参数。

可以手动构建 ToolDefinition

ToolDefinition toolDefinition = ToolDefinition.builder()
        .name("currentWeather")
        .description("Get the weather in location")
        .inputSchema("""
                {
                  "type": "object",
                  "properties": {
                    "location": {
                      "type": "string"
                    },
                    "unit": {
                      "type": "string",
                      "enum": ["C", "F"]
                    }
                  },
                  "required": ["location", "unit"]
                }
                """)
        .build();

基于方法构建工具时,也可以从方法自动生成定义:

Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
ToolDefinition toolDefinition = ToolDefinition.from(method);

如果需要显式覆盖部分属性,可以使用基于方法的 Builder:

Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");

ToolDefinition toolDefinition = ToolDefinition.builder(method)
        .name("currentDateTime")
        .description("Get the current date and time in the user's timezone")
        .inputSchema(JsonSchemaGenerator.generateForMethodInput(method))
        .build();

实际开发中,工具名称要稳定,描述要面向模型而不是面向人类随意缩写。比如“查询客户”不如“根据客户 ID 查询客户基础信息、所属租户和最近服务状态”。

ToolContext:传递不暴露给模型的上下文

有些工具执行时需要额外上下文,但这些上下文不应该发送给模型。例如租户 ID、当前登录用户 ID、权限范围、请求来源、灰度标识等。

Spring AI 提供 ToolContext 来传递这类数据。它可以和模型生成的工具参数一起参与工具执行,但不会发送给模型。

例如,在多租户系统中根据客户 ID 查询客户信息:

class CustomerTools {

    @Tool(description = "Retrieve customer information")
    Customer getCustomerInfo(Long id, ToolContext toolContext) {
        return customerRepository.findById(
                id,
                toolContext.getContext().get("tenantId")
        );
    }
}

调用 ChatClient 时传入上下文:

ChatModel chatModel = ...

String response = ChatClient.create(chatModel)
        .prompt("Tell me more about the customer with ID 42")
        .tools(new CustomerTools())
        .toolContext(Map.of("tenantId", "acme"))
        .call()
        .content();

直接调用 ChatModel 时,也可以通过 ToolCallingChatOptions 传入:

ChatModel chatModel = ...

ToolCallback[] customerTools = ToolCallbacks.from(new CustomerTools());

ChatOptions chatOptions = ToolCallingChatOptions.builder()
        .toolCallbacks(customerTools)
        .toolContext(Map.of("tenantId", "acme"))
        .build();

Prompt prompt = new Prompt("Tell me more about the customer with ID 42", chatOptions);
chatModel.call(prompt);

这一点很重要:ToolContext 里的数据不会发送给 AI 模型。它适合存放工具执行所需的业务上下文,但不适合依赖模型理解的参数。如果模型需要根据某个字段做推理或选择,应把它作为提示词或工具参数的一部分;如果只是后端执行时需要,就放在 ToolContext

Return Direct:是否跳过模型后处理

默认情况下,工具执行结果会返回给模型,模型再基于结果生成最终回复。这适合需要自然语言解释、多轮对话和友好表达的场景。

但有些场景并不需要模型再次加工,甚至不希望模型改写结果。例如:

  • RAG 检索工具已经得到结构化检索结果,希望直接返回给调用方。
  • 设备控制命令只需要返回执行状态。
  • 游戏或工业控制类指令强调低延迟和确定性。
  • 后端服务希望拿到原始 JSON,而不是被模型包装成自然语言。

这时可以使用 returnDirect = true

两种模式的差异可以这样理解:

维度 结果传回模型 直接返回调用方
配置 returnDirect = false returnDirect = true
响应速度 较慢,需要模型再次生成 更快,跳过额外生成
输出形式 更自然、更适合对话 更原始、更适合程序处理
适用任务 推理、解释、多轮问答 控制、查询、状态更新
典型场景 客服问答、智能助理、复杂指令解释 IoT 控制、工单状态、结构化检索结果

例如智能家居中,用户说“关闭客厅的灯”。默认模式下,工具关闭灯后把结果交给模型,模型再回复“好的,我已经帮你关闭客厅的灯”。直接返回模式下,系统可以跳过模型包装,直接把“客厅灯已关闭”的状态返回给 App,用于更新 UI 或播放提示音。

选择哪种模式取决于业务目标:如果用户需要自然交流,就让模型后处理;如果系统需要快速、稳定、结构化反馈,就直接返回。

工具执行管理

工具执行指的是使用模型提供的输入参数调用具体工具,并把结果返回给后续流程。

在 Spring AI 中,这个过程由 ToolCallingManager 负责。它管理工具调用的完整生命周期,包括解析可用工具、执行模型请求的工具调用、封装工具执行结果。

核心接口可以概括为:

public interface ToolCallingManager {

    /**
     * 从模型调用选项中解析工具定义,告诉模型当前有哪些工具可用。
     */
    List<ToolDefinition> resolveToolDefinitions(ToolCallingChatOptions chatOptions);

    /**
     * 执行模型要求的工具调用。
     */
    ToolExecutionResult executeToolCalls(Prompt prompt, ChatResponse chatResponse);
}

resolveToolDefinitions 负责从 ToolCallingChatOptions 中解析工具定义,并把这些信息提供给模型。模型看到的不是 Java 对象本身,而是工具名称、描述和输入 schema。

executeToolCalls 负责真正执行工具。当模型返回工具调用请求后,它会找到对应的 ToolCallback,传入模型生成的参数,执行工具逻辑,再返回 ToolExecutionResult

因此,一个完整的 Tool Calling 应用需要同时关注两件事:

  • 让模型看懂工具:名称稳定、描述清晰、参数 schema 准确。
  • 让工具执行可靠:参数校验、权限控制、异常处理、结果格式都要符合业务要求。

开发实践建议

Tool Calling 的代码接入并不复杂,难点在于工程化质量。

工具描述要写给模型看。描述不要过短,也不要只写内部术语。它应该明确说明工具能力、适用条件和关键参数。例如“根据城市名称查询当前天气”比“天气工具”稳定得多。

工具粒度要适中。一个工具只做一类明确事情,模型更容易选择;过大的万能工具会让参数复杂、行为不确定,过小的工具又会增加模型选择难度。

参数结构要清晰。能用枚举就不要让模型自由发挥,能标明格式就写清格式,例如 ISO-8601 时间、订单号格式、城市名称、租户 ID 等。

敏感操作要加保护。发送邮件、创建订单、删除数据、付款、关闭设备等动作,不应完全依赖模型判断。建议增加权限校验、二次确认、审计日志和幂等控制。

工具结果要面向后续流程设计。如果结果要返回模型,就应提供足够语义信息,方便模型生成自然回复;如果结果直接返回调用方,就应保持结构化、稳定和可解析。

ToolContext 适合承载后端上下文,例如租户、用户、权限和链路追踪信息。不要把不该暴露给模型的数据放进提示词,也不要让模型负责生成安全敏感字段。

总结

Tool Calling 是 Spring AI 应用从“智能问答”走向“智能执行”的关键能力。它把模型的理解和推理能力,与企业系统中的函数、API、数据库和业务服务连接起来,让 AI 能够查询实时信息、触发业务动作、参与工作流。

从开发流程看,先用 @Tool 快速暴露方法,再通过 ChatClientChatModel 提供给模型,就能完成最小可用的工具调用。随着业务复杂度提升,可以进一步使用 MethodToolCallbackToolDefinitionToolContextreturnDirect 控制工具定义、上下文传递、结果返回方式和执行生命周期。

真正稳定的 Tool Calling 应用,不只是“能调通工具”,还要让模型选得准、参数传得对、工具执行稳、结果返回清楚。把这些细节做好,大模型才能真正成为业务系统里的执行型助手。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐