目录
[一、企业级 AI 开发的核心痛点:大模型 "看不见" 企业私有数据](#一、企业级 AI 开发的核心痛点:大模型 “看不见” 企业私有数据)
[Tool Calling 两大核心能力](#Tool Calling 两大核心能力)
[二、Spring AI Tool Calling 完整代码实战(智能票务退票案例)](#二、Spring AI Tool Calling 完整代码实战(智能票务退票案例))
[1. 对外对话接口 Controller](#1. 对外对话接口 Controller)
[2. 工具定义 Service:@Tool 注解声明可调用业务方法](#2. 工具定义 Service:@Tool 注解声明可调用业务方法)
[3. 底层业务服务:真实操作数据库逻辑](#3. 底层业务服务:真实操作数据库逻辑)
[4. Spring Security 权限配置(企业级必备)](#4. Spring Security 权限配置(企业级必备))
[三、企业落地 Tool Calling 核心注意事项(避坑指南)](#三、企业落地 Tool Calling 核心注意事项(避坑指南))
[1. 严格限制工具入参 / 返回值类型](#1. 严格限制工具入参 / 返回值类型)
[2. AI 无法自动匹配工具:参数描述是关键](#2. AI 无法自动匹配工具:参数描述是关键)
[3. 防范模型幻觉:AI 强行编造参数调用工具](#3. 防范模型幻觉:AI 强行编造参数调用工具)
[4. 工具命名、参数名必须业务可读](#4. 工具命名、参数名必须业务可读)
[5. 单工具参数数量控制在 5 个以内](#5. 单工具参数数量控制在 5 个以内)
[6. 禁止工具执行超长耗时同步操作](#6. 禁止工具执行超长耗时同步操作)
[7. 工具数量过多引发模型 "选择困难"](#7. 工具数量过多引发模型 “选择困难”)
[四、海量工具解决方案:RAG 向量库动态加载工具](#四、海量工具解决方案:RAG 向量库动态加载工具)
一、企业级 AI 开发的核心痛点:大模型 "看不见" 企业私有数据
通用大模型的能力边界存在天然短板,也是企业落地智能应用最大的阻碍:
- 知识时效性断层:模型训练数据存在固定时间截止点,无法获取实时业务数据;
- 数据隔离壁垒:企业核心业务数据存储在内部数据库、政务系统、票务、ERP、CRM 等私有系统,公网训练无法触达;
- 无业务执行能力:模型只能生成文字,无法完成退票、下单、查询企业档案、资金操作等真实业务动作。
举两个典型业务场景:
- 场景 1:用户提问「全国有多少姓名为徐庶的登记人口」,通用大模型完全无权限访问政务人口接口,无法给出答案;
- 场景 2:智能票务助手对话中用户说「帮我退掉车票 1001,姓名张三」,AI 仅凭文本无法操作票务数据库执行退票逻辑。
早期解决方案是多模型链路拼接、手动解析对话调用接口,代码冗余、维护成本极高。而Tool Calling(又称 Function Call 工具调用) 是 Spring AI 提供的标准化方案,完美解决「信息检索 + 业务执行」两大核心需求,让大模型自主调用企业内部 Java 业务接口。
Tool Calling 两大核心能力
- 信息检索增强(轻量化 RAG) 对接数据库、内部 Web 服务、文件、搜索引擎,补充模型私有 / 实时信息。例如查询库存、客户档案、实时工单、政务数据,弥补模型知识盲区。
- 自动化业务操作 触发系统真实行为:退票、创建订单、发送企业邮件、提交审批、修改数据库记录,AI 从问答助手升级为业务执行 Agent。
二、Spring AI Tool Calling 完整代码实战(智能票务退票案例)
基于 Spring Boot + Spring AI + Spring Security 实现带权限控制的退票工具,完整分层代码可直接复用。
1. 对外对话接口 Controller
接收用户自然语言对话,全局注入业务工具集,自动触发工具调用逻辑
package org.liu.tools;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ToolsConttroller {
private ChatClient chatClient;
// 构造器注入ChatClient与工具服务,全局注册所有工具
public ToolsConttroller(ChatClient.Builder clientBuilder, ToolService toolService) {
this.chatClient = clientBuilder.defaultTools(toolService).build();
}
/**
* AI对话统一入口,自然语言自动匹配工具执行退票等业务
* @param message 用户对话文本
* @return AI整合工具返回数据后的自然语言回复
*/
@RequestMapping("/tool")
public String tool(@RequestParam(value = "message") String message) {
return chatClient.prompt().user(message).call().content();
}
}
2. 工具定义 Service:@Tool 注解声明可调用业务方法
核心注解@Tool定义工具用途,@ToolParam描述入参,整合 Spring Security 权限校验,限制高危操作仅管理员可用
package org.liu.tools;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
@Service
public class ToolService {
@Autowired
private TicketService ticketService;
/**
* AI可调用退票工具,仅ADMIN管理员角色允许执行
* @param ticketNumber 车票唯一编号
* @param userName 乘车人姓名
* @return 操作结果+当前操作用户
*/
@Tool(description = "用于办理车票退票业务,传入车票号与乘车人姓名即可完成退票操作")
@PreAuthorize("hasRole('ADMIN')")
public String cancel(
@ToolParam(description = "待退票的车票唯一编号,必填") String ticketNumber,
@ToolParam(description = "车票登记的乘车人真实姓名,必填") String userName
){
// 获取当前登录操作用户
String loginUser = SecurityContextHolder.getContext().getAuthentication().getName();
ticketService.canel(ticketNumber, userName);
return loginUser + "执行退票操作成功";
}
}
3. 底层业务服务:真实操作数据库逻辑
package org.liu.tools;
import org.springframework.stereotype.Service;
@Service
public class TicketService {
/**
* 底层退票数据库操作,项目中替换为MyBatis/MyBatis-Plus持久层逻辑
*/
public void canel(String ticketNumber,String userName){
System.out.println("车票"+ticketNumber+",乘车人"+userName+"退票成功,更新数据库订单状态");
}
}
4. Spring Security 权限配置(企业级必备)
工具涉及资金、订单等高危操作,必须做身份与角色拦截,配置内存用户示例(生产替换数据库用户)
package org.liu.tools.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableMethodSecurity // 开启方法级权限校验,支持@PreAuthorize
public class Security {
// 测试用户:普通用户USER、管理员ADMIN
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withUsername("user").password("password").roles("USER").build();
UserDetails admin = User.withUsername("admin").password("123").roles("ADMIN").build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorizeRequests -> authorizeRequests
.requestMatchers("/tool").permitAll() // 对话接口放行,工具内部做方法鉴权
.anyRequest()
.authenticated())
.with(new FormLoginConfigurer<>(), Customizer.withDefaults());
return http.build();
}
// 测试用明文密码编码器,生产环境替换BCryptPasswordEncoder
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
三、企业落地 Tool Calling 核心注意事项(避坑指南)
结合票务、政务、金融项目落地踩坑,整理 7 条生产级规范:
1. 严格限制工具入参 / 返回值类型
推荐支持 :Java 基础类型、Record、简单 POJO、List、Map; 禁止使用:复杂循环依赖实体、IO 流、Session 上下文等特殊对象,会导致模型解析 Schema 失败。
2. AI 无法自动匹配工具:参数描述是关键
现象:用户明确需要退票,但 AI 完全不调用cancel工具,直接文字回复无法操作; 解决方案:
- 完善
@Tool、@ToolParam描述,清晰说明工具使用场景、参数用途、必填项; - 调低 temperature(随机性)可缓解,但不推荐作为长期方案,优先优化注释描述。
3. 防范模型幻觉:AI 强行编造参数调用工具
大模型容易凭空生成不存在的车票号、用户 ID,直接触发业务操作,风险极高:
- 工具注解增加严格参数描述,标注字段格式、长度约束;
- 工具方法内部增加参数校验(非空、正则、数据库预查询),非法参数直接拦截;
- 系统全局 Prompt 增加约束:禁止编造业务编号,参数缺失必须向用户追问;
- 资金、风控、删除类高危工具,增加人工二次确认交互,多一层校验屏障。
4. 工具命名、参数名必须业务可读
AI 依靠方法名、注释判断是否调用工具,禁止缩写、乱码、无意义参数名:
- 坏示例:
op(String a,String b); - 好示例:
cancel(String ticketNumber,String userName)。
5. 单工具参数数量控制在 5 个以内
参数过多会大幅膨胀工具 Schema 的 token 消耗,模型极易混淆字段、传参错乱,多参数场景拆分多个细分工具。
6. 禁止工具执行超长耗时同步操作
工具同步阻塞会拉长用户对话响应时间:
- 查询类逻辑缓存 Redis,减少 DB 查询耗时;
- 复杂计算、异步任务、文件导出改为异步处理,工具仅触发任务,返回任务编号供用户后续查询。
7. 工具数量过多引发模型 "选择困难"
系统注册上百个工具会出现两个严重问题:
- 所有工具描述全部带入请求上下文,触发 token 上限报错;
- 模型无法精准匹配对应工具,随机调用无关接口。
四、海量工具解决方案:RAG 向量库动态加载工具
当企业工具规模达到数十上百个,不能全局defaultTools一次性注入全部工具,采用工具描述 + 向量检索动态匹配架构,解决工具泛滥问题:
实现流程
- 工具元数据入库 :项目启动时扫描所有
@Tool工具,提取方法描述、功能、参数说明,转为向量存入向量数据库; - 对话实时检索:用户发送对话时,将用户问题向量化,从向量库检索语义相似度最高的 3-5 个工具;
- 动态绑定工具:仅将检索匹配到的少量工具注入当前 ChatClient 会话,大幅减少上下文 token,消除选择困难。
架构优势
- 上下文轻量化,避免 token 超限;
- 精准匹配业务工具,降低幻觉、错调用概率;
- 支持工具模块化管理,不同业务线隔离工具集。