ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Tool Calling 是什么?用后端接口的思路讲清楚

Tool Calling 是什么?用后端接口的思路讲清楚

最近看 Agent 相关内容时,Tool Calling 这个词出现得挺频繁。

刚开始看到它,我也有点抽象。什么工具调用、函数调用、让模型使用工具,听起来像是大模型自己真的会操作系统、调用接口一样。

后来我换成后端开发的思路去理解,发现它其实没有那么神秘。

对 Java 后端来说,Tool Calling 可以先简单理解成一句话:

让 Agent 根据用户的问题,选择合适的后端接口去调用。

以前是用户点页面按钮,前端调用接口;现在是用户说一句自然语言,Agent 判断要调用哪个接口。

调用方变了,但后端接口本身还是后端接口。


为什么需要 Tool Calling

如果 AI 助手只会聊天,它能做的事情其实有限。

比如用户问:

Redis 缓存穿透是什么?

这种问题直接让模型回答就可以。

但如果用户问:

帮我查一下订单 10086 现在是什么状态?

这个问题就不能让模型自己回答。

因为模型不知道真实订单状态。订单有没有支付、有没有出库、库存是否充足、物流单号是什么,这些数据都在业务系统里,不在模型脑子里。

这时候就需要 Tool Calling。

Agent 先理解用户想查订单,然后调用 Java 后端提供的订单查询接口,拿到真实数据后,再组织成自然语言返回给用户。

所以 Tool Calling 解决的不是“让模型更会聊天”,而是让模型能够连接外部系统,拿到真实业务数据,或者触发某些业务动作。


工具可以理解成后端能力的一层包装

在 Java 后端项目里,我们本来就会提供很多接口。

比如:

GET /api/orders/{orderId} GET /api/inventory/{sku} POST /api/tickets GET /api/users/{userId}

这些接口以前主要是给前端页面用的。

用户点“查询订单”,前端调用订单接口;用户点“创建工单”,前端调用工单接口。

到了 AI 助手里,用户不一定点按钮,而是直接说:

帮我看下这个订单为什么没发货

Agent 要做的,就是把这句话转换成一次工具调用。

比如调用:

query_order(orderId = 10086)

从本质上看,query_order这个工具背后还是 Java 的订单查询接口。只是我们给它加了一层描述,让 Agent 知道这个工具什么时候该用、需要哪些参数、返回什么结果。


一个工具至少要描述清楚三件事

我现在理解,一个后端接口想变成 Agent 可用的工具,至少要描述清楚三件事。

第一,工具是干什么的。

比如:

query_order:根据订单号查询订单状态、支付状态、发货状态和预计发货时间。

第二,工具需要什么参数。

比如:

orderId:订单号,字符串类型,必填。

第三,什么时候应该调用它。

比如:

当用户询问订单状态、发货情况、是否支付、预计发货时间时,可以调用这个工具。

这三件事看起来简单,但很重要。

因为 Agent 面对的是自然语言,不是固定表单。用户可能说“订单 10086 发了吗”,也可能说“我买的东西怎么还没动静”。工具描述越清楚,Agent 越容易判断该不该调用。

如果描述太模糊,Agent 就可能选错工具。


Tool Calling 不等于让模型直接操作数据库

这个边界我觉得特别重要。

有些人一听 Tool Calling,可能会觉得是不是可以让模型直接查数据库、直接改订单、直接操作业务表。

我不太建议这样做。

对真实业务系统来说,模型不应该直接碰核心数据库。它应该通过后端接口获取数据或发起操作。

比如用户想取消订单,Agent 可以调用 Java 后端的取消订单接口,但真正能不能取消,必须由 Java 后端判断。

后端要检查:

  • 用户有没有权限

  • 订单是否存在

  • 订单是否已经发货

  • 是否允许取消

  • 是否需要退款

  • 操作是否幂等

  • 日志是否记录

这些都是确定性业务逻辑,不能交给模型猜。

所以我的理解是:Agent 负责理解意图和选择工具,Java 后端负责执行规则和保证数据正确。


查询类工具和操作类工具要分开看

做 Tool Calling 时,我觉得查询类工具可以先做,操作类工具要谨慎。

查询类工具风险相对低,比如:

  • 查询订单

  • 查询库存

  • 查询工单状态

  • 查询知识库文档

  • 查询用户基础信息

这些接口主要是读数据,只要权限控制做好,比较适合作为第一批工具。

操作类工具就要小心一些,比如:

  • 取消订单

  • 修改地址

  • 创建工单

  • 发起退款

  • 删除数据

  • 修改用户资料

这类工具最好加确认机制。

比如用户说:

帮我取消订单 10086

Agent 不应该马上执行取消。更稳妥的方式是先查询订单状态,然后告诉用户:

这个订单目前还没有发货,可以取消。是否确认取消?

用户确认后,再调用取消订单接口。

这和传统业务系统里的二次确认很像,只是交互方式从按钮变成了自然语言。


Tool Calling 的返回结果最好结构化

后端接口返回给 Agent 的内容,我更倾向于结构化 JSON,而不是一段自然语言。

比如订单查询工具返回:

{ "orderId": "10086", "payStatus": "已支付", "orderStatus": "待出库", "warehouseStatus": "部分商品缺货", "estimatedShipTime": "2026-08-15" }

然后 Agent 再根据这个结果回答:

这个订单已经支付,目前处于待出库状态。仓库显示部分商品缺货,预计 8 月 15 日可以发货。

这样设计有两个好处。

第一,后端返回的数据清楚,方便排查问题。

第二,模型只负责表达,不负责编业务事实。

如果回答错了,我们可以看日志判断:是 Java 后端返回的数据有问题,还是 Agent 理解和表达时出了问题。


日志和链路追踪不能省

Tool Calling 会让一次请求链路变长。

以前一个接口可能就是:

前端 -> Java 后端 -> MySQL -> 返回

现在可能变成:

用户提问 -> Python Agent -> 判断意图 -> 调用 Java 工具接口 -> 查询 MySQL 或 Redis -> 返回结构化数据 -> 调用大模型整理回答 -> 返回用户

中间任何一步出问题,用户看到的都可能是“AI 回答不对”。

所以日志必须留。

我觉得至少要记录:

  • 用户原始问题

  • Agent 判断的意图

  • 调用了哪个工具

  • 工具入参

  • Java 后端返回值

  • 模型最终回答

  • 请求耗时

  • 异常信息

这些记录后面非常有用。否则系统上线后,用户反馈一句“这个助手乱回答”,排查起来会很痛苦。


怎么实践

如果让我做一个最小 Demo,我会先从最简单的 Tool Calling 开始。

第一步,用 Spring Boot 写一个订单查询接口,先返回模拟数据。

第二步,在 Python Agent 里定义一个query_order工具,描述它的用途、参数和返回值。

第三步,让 Agent 从用户问题里提取订单号。

第四步,Agent 调用 Java 接口,拿到订单数据。

第五步,把订单数据交给模型,让它组织成自然语言回答。

第六步,把完整链路记录下来,包括用户问题、工具调用、接口返回和最终回答。

等这个链路跑通后,再加库存查询、工单创建、知识库检索这些工具。

不要一开始就把工具做得太多。工具越多,Agent 选择错误的可能性也越高。先把一个工具跑稳,比堆很多工具更重要。


最后

Tool Calling 听起来像是一个 AI 概念,但用后端接口的思路理解,其实很容易落地。

它本质上就是让 Agent 能够调用外部能力,而这些外部能力,很多时候就是我们 Java 后端已经写过的业务接口。

Python Agent 负责理解用户问题、选择工具、组织回答;Spring Boot 负责提供稳定接口、校验权限、执行规则、返回准确数据。

对 Java 后端来说,Tool Calling 不是一个完全陌生的东西。它更像是把原来的接口能力,换一种方式暴露给 AI 助手使用。

下一篇我准备继续聊一个更容易踩坑的问题:AI 应用里的数据边界,哪些交给 Agent,哪些必须留在后端?

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进