乐于分享
好东西不私藏

AI 应用开发入门 05|工具调用,怎么让模型干活

AI 应用开发入门 05|工具调用,怎么让模型干活

导语

很多开发者第一次接触大模型时,都会有一个错觉:模型已经很聪明了,只要把需求说清楚,它就能像程序一样替你完成任务。真正做下来才会发现,事情并不是这样。

我的判断是:只会生成文本的模型,最多算“会说”;接上工具之后,它才开始具备“干活”的能力。

模型默认只会生成下一个最可能的词。它擅长解释、总结、改写、推理,但并不会天然拥有你系统里的订单数据、库存状态,也不会真的帮你发请求、改数据库、创建日程。它会说“我可以帮你查一下”,不代表它真的查了。

这就是函数调用(Function Calling)和工具调用(Tool Use)的意义:让模型不只是“会说”,而是能在受控边界内“真做事”。

这一篇想讲清楚的,就是文本生成和工具调用到底差在哪,以及程序员把这层能力接进系统时最该注意什么。

文本生成,和工具调用,到底差在哪

先把概念分清。

纯文本生成模式下,模型做的事情是:根据上下文预测输出内容。比如你问“用户下单后库存应该怎么扣减”,它可以给你一段流程建议;你问“这个 SQL 为什么慢”,它可以分析可能原因。这类场景里,模型主要承担的是“认知层”的工作。

但如果你问它:

  • • “帮我查一下订单 A20260411001 现在是什么状态”
  • • “看一下 SKU-10086 还有多少库存”
  • • “帮我约一个明天下午 3 点的评审会”

这时候就不只是生成文字了,而是需要访问外部系统。订单状态可能在 OMS,库存数据在 WMS 或数据库,日程要写入企业日历或 Google Calendar。模型本身没有这些权限和连接能力,必须通过你定义好的函数或工具,才能完成真实操作。

一句话概括:

  • • 文本生成:模型负责“想”和“说”
  • • 工具调用:模型负责“判断何时调用”,系统负责“真的执行”

这也是为什么函数调用不是“模型变强了”,而是“模型接入了可执行能力”。

一个接地气的例子:查订单、看库存、排日程

设想你在做一个电商客服 Copilot,用户在聊天框里输入:

“我昨天买的耳机怎么还没发货?顺便帮我看看同款白色还有没有货,有的话下周一提醒我补单。”

如果没有工具调用,模型最多只能回复一段像模像样的话:

“您可以先检查订单状态,如果库存不足可能导致延迟发货……”

听起来挺像回事,但其实什么都没干。

如果接上工具,流程就完全不一样了:

  1. 1. 模型先识别用户意图:查订单、查库存、创建提醒。
  2. 2. 它决定调用哪些函数,比如 getOrderStatusqueryInventorycreateReminder
  3. 3. 你的服务端真正执行这些函数,拿到结果。
  4. 4. 模型再基于真实结果组织自然语言回复。

最后用户看到的可能是:

“订单 A20260411001 当前状态是‘待出库’,仓库预计今晚完成拣货。白色同款当前还有 12 件库存。我已经为你创建了下周一上午 10 点的补单提醒。”

这里最关键的变化不是“回复更像人”,而是“回复建立在真实执行结果之上”。

函数调用的核心设计:让模型会选,但别让模型乱来

很多文章会把函数调用讲得很玄,实际上工程上就三件事:

  1. 1. 给模型一组可用工具及其描述
  2. 2. 让模型输出“我想调用哪个工具、参数是什么”
  3. 3. 由你的后端执行,并把结果再喂回模型

一个极简示意如下:

tools = [
    {
"name""get_order_status",
"description""查询订单当前状态",
"parameters": {
"type""object",
"properties": {
"order_id": {"type""string""description""订单号"}
            },
"required": ["order_id"]
        }
    }
]

user_input = "帮我查一下订单 A20260411001 的状态"

# 1. 把 tools 和 user_input 发给模型
tool_call = llm.chat(user_input, tools=tools)

# 2. 如果模型决定调用工具
if tool_call["name"] == "get_order_status":
    result = get_order_status(order_id=tool_call["arguments"]["order_id"])

# 3. 把执行结果回传给模型,生成最终回复
    final_answer = llm.chat(
        messages=[
            {"role""user""content": user_input},
            {"role""tool""name""get_order_status""content"str(result)}
        ]
    )

真正落地时,函数描述比代码本身还重要。因为模型不是靠类型系统理解你的意图,而是靠描述文本和参数 schema 做决策。

一个好工具定义,至少要做到两点:

  • • 名字和描述足够清晰,让模型知道“什么时候该用”
  • • 参数边界足够明确,让模型知道“该传什么、不该传什么”

比如 query_data 这种万能函数,对模型很不友好;而 get_order_statusquery_inventory_by_skuschedule_meeting 这类语义清晰的函数,更容易被正确调用。

真正的工程重点,不在“调起来”,而在“控得住”

很多 Demo 都能跑通,但一到生产环境就出问题。原因通常不是模型不会调用,而是调用链路没有工程化。

第一层是权限控制。模型不应该因为“用户说了”就能执行敏感操作。比如“取消订单”“批量退款”“删除日程”这类动作,必须由业务系统再次鉴权。模型只能提出调用意图,真正的授权判断必须在你的服务端。

第二层是结果约束。工具返回什么,决定了模型后续能说什么。不要把内部异常、数据库原始报错、敏感字段直接回传给模型。应该返回结构化、最小必要的信息,比如状态码、业务描述、可展示字段。

第三层是调用编排。实际业务里,一个请求往往不是一次函数调用就结束。比如“查订单并解释为什么没发货”,可能要串行调用订单服务、物流服务、库存服务。这里更像一个受控 agent:模型负责决策,业务代码负责 orchestrate。

第四层是可观测性。你至少要记下这些日志:

  • • 用户原始请求
  • • 模型选择了哪个工具
  • • 工具参数是什么
  • • 工具执行结果是什么
  • • 最终返回给用户的内容是什么

没有这些日志,线上问题几乎没法排查。你会分不清是模型理解错了,还是工具描述写坏了,还是后端接口本身异常。

常见坑:权限、校验、幂等、超时

这是最容易踩坑的一组问题,也是 AI 应用和普通聊天机器人拉开差距的地方。

1. 权限

不要让模型越权操作。用户说“帮我把这个订单直接退款”,不代表当前账号真的有退款权限。工具层必须做 RBAC、租户隔离、资源归属校验。模型只能“建议执行”,不能替代权限系统。

2. 参数校验

模型会犯错,哪怕 schema 写了,也可能传出缺字段、错类型、模糊值。比如把“下周一下午”解析成错误时区,把商品名当 SKU。服务端必须做严格校验,必要时返回可恢复错误,再让模型向用户追问。

3. 幂等性

凡是可能修改状态的操作,都要考虑重复执行。网络抖动、用户重复点击、模型重试,都可能导致“重复创建提醒”“重复下单”“重复发消息”。创建类接口最好带幂等键,更新类接口要明确状态机约束。

4. 超时

工具调用不是无限快的。库存服务 300ms,订单服务 800ms,第三方日历 API 2s,加起来用户体验很容易崩。要给每个工具设置超时、降级和失败策略。查不到就明确告诉用户“系统暂时未返回结果”,不要让模型编一个答案补上。

什么时候该上函数调用,什么时候不该上

并不是所有场景都要上工具。

如果你的需求只是:

  • • 改写文案
  • • 总结日志
  • • 生成 SQL 草稿
  • • 解释报错原因

那纯文本生成通常就够了,系统简单、成本更低。

但只要涉及以下任意一种,就应该认真考虑函数调用:

  • • 需要读取真实业务数据
  • • 需要触发外部动作
  • • 需要跨多个系统编排流程
  • • 需要可审计、可回放、可控制的执行链路

判断标准很简单:用户要的是“答案”,还是“结果”。
如果要的是结果,就不能只靠模型说。

小结

如果只记住一个结论:函数调用解决的不是“模型会不会聊天”,而是“模型能不能安全、可靠地接入你的系统能力”。

你可以把它理解为一种新的交互层:

  • • 模型负责理解意图和选择工具
  • • 你的后端负责鉴权、校验、执行和审计
  • • 最终由模型把机器结果翻译成人能理解的话

对程序员来说,这一步很关键。因为当你把这层搭起来,AI 应用才真正从“会回答问题”,走向“能完成任务”。

再往后走,你就会自然碰到更复杂的话题:多步任务什么时候需要,Agent 什么时候有价值,什么时候其实只是把简单问题复杂化。

如果你也在关注 AI、Agent 和最新开源趋势,欢迎关注我的微信公众号:碳基生物观察局。
我会持续分享值得跟踪的 AI 项目、产品观察和实战解读。