Skip to content

99. Spring AI 工具调用与工具管理 ​

难度 P1 高频 · 岗位 应用 · 频率 ★★★ · 预计阅读 11 min

本题阅读地图 ​

  1. 💡 简要回答
  2. 📝 详细解析
  3. 🎯 面试总结

👔面试官:Spring AI 里的工具调用是怎么实现的?和直接用 OpenAI API 有什么区别?

🙋‍♂️我:Spring AI 就是封装了一下吧,本质上还是调 OpenAI 的接口。

👔面试官:封装当然是一方面,但 Spring AI 的工具调用有什么特别的设计?比如怎么把一个 Java 方法暴露给 LLM?

🙋‍♂️我:应该是写个接口定义什么的?或者用配置?

👔面试官:用注解。Spring AI 的亮点是用 @Tool 注解直接把普通 Java 方法变成 LLM 可调用的工具,不需要手写 JSON Schema。而且框架帮你管了整个调用链路,包括解析 tool_calls、分发到对应方法、把结果塞回对话。这些都回去好好了解一下。

💡 简要回答 ​

Spring AI 的工具调用设计得很简洁:用 @Tool 和 @ToolParam 注解直接标记 Java 方法,框架自动帮你生成 JSON Schema,并且处理整个调用分发流程。

你不需要手动写 schema、不需要自己解析 LLM 返回的 tool_calls、不需要把工具结果组装成消息再调 LLM。Spring AI 全包了,你要做的只是写业务逻辑。

📝 详细解析 ​

核心机制:注解驱动的工具定义 ​

Spring AI 最牛的地方在于,它让工具定义变得极其简单。一个普通的 Java 方法,加两个注解就能变成 LLM 可调用的工具:

java
@Service
public class WeatherService {

    @Tool(description = "获取指定城市的实时天气信息,包括气温、天气状况、风速")
    public String getWeather(
        @ToolParam(description = "城市名称,如北京、上海,不要带省份") String city,
        @ToolParam(description = "温度单位,celsius或fahrenheit", required = false) String unit
    ) {
        // 你的业务逻辑:调天气 API、查数据库...
        return weatherApi.query(city, unit);
    }
}

注意这里有几个关键设计:

  1. @Tool 注解加在方法上,description 参数就是告诉 LLM 这个工具能做什么。这跟手写 JSON schema 里的 description 是同一个作用,但用注解写起来更自然。

  2. @ToolParam 注解加在参数上,告诉 LLM 每个参数是什么意思、是不是必填。Spring AI 会自动从这些注解里提取信息,生成符合 OpenAI Function Calling 规范的 JSON schema。

  3. 方法签名完全自由,返回值可以是 String、可以是对象,Spring AI 会自动序列化成 LLM 能理解的格式。

完整调用流程 ​

有了工具定义,怎么用起来?Spring AI 的 ChatClient 设计得很巧妙:

java
@Configuration
public class AgentConfig {

    @Bean
    public ChatClient chatClient(ChatModel chatModel, WeatherService weatherService) {
        return ChatClient.builder(chatModel)
            .defaultTools(weatherService)  // 注册工具,可以注册多个
            .defaultSystem("你是一个有用的助手,可以使用工具帮助用户")
            .build();
    }
}

@RestController
public class ChatController {
    @Autowired
    private ChatClient chatClient;

    @PostMapping("/chat")
    public String chat(@RequestBody String userMessage) {
        return chatClient.prompt()
            .user(userMessage)
            .call()           // 这里 Spring AI 自动处理:LLM 决策 → 调工具 → 结果返回 → 生成最终答案
            .content();
    }
}

用户发「北京今天天气怎么样?」,整个流程是这样的:

  1. Spring AI 把 WeatherService 里的方法转成 JSON schema,和 prompt 一起发给 LLM
  2. LLM 返回 tool_calls,说要调 getWeather,参数 {"city": "北京"}
  3. Spring AI 自动解析,找到 WeatherService.getWeather 方法,反射调用
  4. 拿到结果「晴天 25°C」,塞进对话历史作为 tool 消息
  5. 再次调用 LLM,LLM 生成最终自然语言回答

你写的代码里完全看不到这些步骤,Spring AI 全包办了。这就是框架的价值:把通用流程抽象掉,你只关心业务逻辑。

工具管理:数量多了怎么办 ​

实际项目里工具可能很多,几十个甚至上百个。全塞给 LLM 会有两个问题:一是 prompt 太长浪费 token,二是工具太多 LLM 决策容易出错。

Spring AI 提供了几种管理方式:

1. 按功能分组

java
@Bean
public List<Object> coreTools() {
    // 通用工具:搜索、计算、日历等
    return List.of(new SearchTool(), new CalculatorTool(), new CalendarTool());
}

@Bean
public List<Object> domainTools() {
    // 业务工具:数据库查询、报表生成等
    return List.of(new DatabaseQueryTool(), new ReportGeneratorTool());
}

// 不同场景用不同工具集
chatClient.prompt()
    .tools(coreTools())  // 只用核心工具
    .user(question)
    .call();

2. 动态工具选择(RAG 检索)

java
// 先把所有工具的 description 做 embedding 存向量库
// 用户提问时,检索最相关的几个工具
List<Tool> relevantTools = toolRetriever.findRelevant(userQuery, topK=5);

chatClient.prompt()
    .tools(relevantTools)  // 只把相关的 5 个工具传给 LLM
    .user(userQuery)
    .call();

这跟 RAG 检索文档的原理一样,只不过检索的是工具描述。好处是 LLM 看到的工具少了,决策更准确,token 也省下来了。

🎯 面试总结 ​

面试时说 Spring AI 工具调用,要抓住这几个点:

  1. 注解驱动:@Tool + @ToolParam 注解让工具定义变得极其简单,不需要手写 JSON schema
  2. 全流程封装:从 schema 生成、tool_calls 解析、方法分发、结果组装,Spring AI 全包了
  3. 工具管理:工具多了要分组管理或动态选择,避免一次性塞太多工具给 LLM

对比直接用 OpenAI API 的好处是:你不用关心 Function Calling 的协议细节,写 Java 方法就行。缺点是灵活度稍低,如果要做一些特殊的自定义逻辑,可能需要绕过框架。


章节首页 · ← Q98 · Q100 →

最后更新2026-05-01
难度P1
频率medium
阅读11 min
主题tool-use / framework
觉得有帮助?把这个链接转给正在求职的朋友 · 用 Ctrl + K 全站搜索其它题