第 14 篇:AI 只会聊天?教你千问点奶茶能力的底层技术(Java+AI落地实战系列 | Function Calling 完整实现,从问答升级为业务执行助手)
本文是《Java+AI 落地实战 从入门到生产级》系列第14篇
往期回顾:
-
第1篇:Java程序员学AI/转AI全指南,从CURD到AI应用工程师(零算法,4周落地)
-
第2篇:Java 后端转 AI,这条完整链路 90% 的人没搞懂!AI 怎么自动干活、Java转AI链路:LLM、RAG、FunctionCall、ToolCall、Skills、Agent、MCP
-
第3篇:别再焦虑了!Java开发做AI,根本不用学Python
-
第4篇:10分钟跑通!SpringBoot对接通义千问,实现AI对话功能
-
第5篇:SpringBoot实现流式输出,和ChatGPT体验一模一样
-
第6篇:对话记忆怎么实现?Java版多轮上下文对话完整方案
-
第7篇:从零搭建本地RAG知识库,内网可用,零API费用
-
第8篇:支持PDF/Word/Excel!Java实现多格式文档自动解析入库
-
第9篇:别再用内存向量库了!Milvus向量数据库Java对接全指南
-
第10篇:RAG检索准确率太低?5个优化技巧,准确率提升50%
-
第11篇:多租户权限隔离!企业级知识库部门级权限管控方案
-
第12篇:一键对接企业微信!把知识库装进企业微信,全员开箱即用
-
第 13 篇:Java 对接通义千问大模型,性能优化全攻略
上一篇我们搞定了本地大模型全链路性能优化,系统已经能稳定支撑业务并发。但目前的 AI 系统还停留在 “问答机器人” 阶段 —— 用户问什么,它就答什么,真要查个订单、查个年假、提交个工单,还是得人手动去业务系统操作。
今天我们就通过 Function Calling(工具调用) 能力,让大模型主动判断用户意图,自动调用业务接口、查询数据库,把 AI 从 “只会说话的顾问” 升级成 “能动手干活的助手”,能力边界直接上一个台阶。
先看一眼能力升级前后的差异:

一、先搞懂:Function Calling 到底是什么?
很多人以为工具调用是大模型直接执行代码,完全不是。大模型本身不会调接口、不会查数据库,它只做一件事:判断用户的问题要不要调用工具、调用哪个工具、传什么参数。
完整的工具调用流程只有 4 步:
- 用户提问:比如 “帮我查一下订单号 20240601 的物流状态”
- 意图判断:大模型识别用户需要调用「查询订单物流」工具,生成结构化参数(订单号 = 20240601)
- 后端执行:Java 服务拿到工具名和参数,真实调用业务接口 / 数据库,拿到执行结果
- 整理返回:把执行结果喂给大模型,让它整理成自然语言回答用户
说白了,大模型是 “大脑” 负责决策,Java 后端是 “手” 负责执行,两者配合就能实现所有业务场景的自动化。

二、前置准备:定义工具规范
我们先以两个最常用的工具为例,覆盖绝大多数业务场景:
- 查询员工剩余年假(查数据库)
- 查询订单物流状态(调第三方接口)
第一步:定义工具注解与基础接口
自定义注解标记工具方法,方便后续自动注册,扩展性极强。
/**
* 工具方法注解,标记该方法可被大模型调用
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AiTool {
String name(); // 工具名称,唯一标识
String description(); // 工具描述,告诉大模型这个工具是干嘛的
}
/**
* 工具执行结果
*/
@Data
@AllArgsConstructor
public class ToolResult {
private Boolean success;
private String data;
}
第二步:实现具体业务工具
@Component
public class BusinessTools {
@Autowired
private EmployeeMapper employeeMapper;
@Autowired
private OrderApiService orderApiService;
/**
* 工具1:查询员工剩余年假
*/
@AiTool(name = "query_annual_leave", description = "查询指定员工的剩余年假天数,入参为员工姓名或员工工号")
public ToolResult queryAnnualLeave(String employeeName) {
try {
Double leaveDays = employeeMapper.selectLeaveDaysByName(employeeName);
return new ToolResult(true, "员工" + employeeName + "剩余年假:" + leaveDays + "天");
} catch (Exception e) {
return new ToolResult(false, "查询失败:未找到该员工信息");
}
}
/**
* 工具2:查询订单物流状态
*/
@AiTool(name = "query_order_logistics", description = "查询指定订单的物流状态,入参为订单号")
public ToolResult queryOrderLogistics(String orderNo) {
try {
String logisticsInfo = orderApiService.getLogistics(orderNo);
return new ToolResult(true, logisticsInfo);
} catch (Exception e) {
return new ToolResult(false, "查询失败:订单号不存在");
}
}
}
重点:工具的 description 一定要写清楚,这是大模型判断要不要调用这个工具的依据,描述越准确,调用准确率越高。
三、核心实现:通义千问 Function Calling 完整流程
我们用通义千问官方 SDK 实现完整的工具调用闭环,本地大模型的实现逻辑完全一致,仅参数名略有差异。
核心服务代码
@Service
public class FunctionCallService {
@Value("${ai.qwen.api-key}")
private String apiKey;
@Value("${ai.qwen.model}")
private String model;
@Autowired
private BusinessTools businessTools;
/**
* 带工具调用的对话
*/
public String chatWithTools(String userQuestion) {
DashScope dashScope = new DashScope(apiKey);
// 1. 构建消息列表
List<Message> messages = new ArrayList<>();
messages.add(Message.builder()
.role(Role.SYSTEM)
.content("你是企业内部智能助手,优先使用工具回答用户问题,没有合适工具再直接回答。")
.build());
messages.add(Message.builder().role(Role.USER).content(userQuestion).build());
// 2. 注册所有可用工具,自动读取注解生成工具定义
List<FunctionTool> tools = ToolRegister.getAllToolDefinitions();
// 3. 构建带工具的请求
GenerationRequest request = GenerationRequest.builder()
.model(model)
.input(MessageInput.builder().messages(messages).build())
.tools(tools)
.toolChoice("auto") // 自动判断是否调用工具
.resultFormat(ResultFormat.MESSAGE)
.build();
try {
GenerationResult result = dashScope.call(request);
ChatMessage responseMsg = result.getOutput().getChoices().get(0).getMessage();
// 4. 判断大模型是否要调用工具
if (responseMsg.getToolCalls() != null && !responseMsg.getToolCalls().isEmpty()) {
// 把大模型的工具调用消息加入上下文
messages.add(responseMsg);
// 遍历执行所有工具调用
for (ToolCall toolCall : responseMsg.getToolCalls()) {
String toolName = toolCall.getFunction().getName();
String toolArgs = toolCall.getFunction().getArguments();
// 反射执行对应工具方法
ToolResult toolResult = ToolRegister.executeTool(toolName, toolArgs);
// 把工具执行结果加入消息上下文
messages.add(Message.builder()
.role(Role.TOOL)
.toolCallId(toolCall.getId())
.content(toolResult.getData())
.build());
}
// 5. 把工具执行结果传给大模型,生成最终回答
GenerationRequest secondRequest = GenerationRequest.builder()
.model(model)
.input(MessageInput.builder().messages(messages).build())
.resultFormat(ResultFormat.MESSAGE)
.build();
GenerationResult finalResult = dashScope.call(secondRequest);
return finalResult.getOutput().getChoices().get(0).getMessage().getContent();
}
// 不需要调用工具,直接返回答案
return responseMsg.getContent();
} catch (Exception e) {
e.printStackTrace();
return "系统异常,请稍后再试";
}
}
}
效果验证
- 用户问:“张三的年假还剩多少?”
- 大模型自动调用
query_annual_leave工具,传参employeeName=张三,执行查询后返回 “张三剩余年假 8.5 天” - 用户问:“今天天气怎么样?”
- 没有对应工具,大模型直接回答 “我暂时无法查询天气信息”

四、新手必踩的 5 个坑,提前帮你避了
坑 1:工具描述写得模糊,调用准确率极低
工具描述写 “查询信息”,大模型根本不知道什么时候该调用,乱调或者不调。 解决方案:工具描述要写清楚用途、适用场景、入参含义,越具体准确率越高。
坑 2:工具参数不校验,存在安全风险
大模型生成的参数直接传去执行,可能出现 SQL 注入、越权查询的问题。 解决方案:所有工具入参必须做格式校验、权限校验,禁止直接拼接 SQL,严格控制工具可执行的操作范围。
坑 3:多工具场景混乱,大模型反复调用
工具多了之后,大模型可能循环调用、一次调用多个无关工具。 解决方案:限制单次调用工具数量,增加调用次数上限(最多 3 轮),超过直接返回结果。
坑 4:工具执行结果太长,token 爆炸
工具返回大量数据,直接丢给大模型,token 超限且回答混乱。 解决方案:工具返回结果做摘要精简,只保留核心信息,不要把全量接口返回都塞进去。
坑 5:开放高危操作,造成生产事故
直接开放创建订单、删除数据这类写操作工具,大模型误调用会造成生产事故。 解决方案:初期只开放查询类工具,写操作必须增加人工确认环节,严格控制工具权限。
五、生产环境进阶优化方向
基础版工具调用已经能解决很多重复性查询工作,企业级场景还可以继续扩展:

- 工具注册中心:统一管理所有工具,支持动态新增、下线,不用改核心代码
- 多轮工具调用:支持多步任务,比如 “先查订单再发起退款” 的链式调用
- 人工确认机制:写操作类工具,执行前推送企业微信确认,用户同意后再执行
- 工具权限管控:不同角色可调用的工具不同,普通员工不能调用财务类工具
- 调用统计监控:统计工具调用频率、成功率、耗时,持续优化工具体验
六、本篇小结
今天我们通过 Function Calling 实现了大模型工具调用能力,核心逻辑非常清晰:
- 定义业务工具,写清楚描述和参数
- 大模型识别用户意图,判断是否调用工具、生成参数
- Java 后端执行工具,把结果返回给大模型
- 大模型整理执行结果,输出自然语言回答
AI 系统从此从 “只能问答” 升级为 “可以执行任务”,能落地的业务场景直接翻倍。
下篇预告(下篇已更----https://mp.weixin.qq.com/s/HIAgmtb99t41cDcla34GsA)
现在系统能力越来越强,支持的场景越来越多,但上生产环境首先要解决稳定性问题 —— 流量突增把服务打挂、大模型故障导致全系统不可用,这些都会直接影响业务。 所以下一篇我们进入企业级落地篇,讲:
第 15 篇:企业级 AI 接口怎么设计?限流、降级、熔断全套方案
内容会覆盖:
- Sentinel 对接 AI 接口完整实现
- QPS 限流、并发线程数控制
- 慢调用降级、异常比例熔断
- 多级故障兜底策略
- 保证生产环境 99.9% 可用性
🎁 粉丝福利
本篇完整代码已更新进系列源码包,包含:
- Function Calling 完整闭环实现
- 工具注册与自动扫描框架
- 两个业务工具示例代码
- 安全校验与调用次数控制
关注

,回复 系列源码 即可免费领取。 每更新一篇,我都会往资料包里新增对应源码,跟着系列就能从零搭出完整的企业级 AI 系统。
⭐ 记得星标公众号,每周更新一篇,跟着走不迷路。 觉得文章有用,欢迎点赞、在看、转发给身边的同事,大家一起少踩坑。

浙公网安备 33010602011771号