Skip to content

Tool、Function Calling 与 Structured Output

只把模型接口接通,系统通常还只是“能生成”。

但只要一进业务,后面很快就会冒出来两个很现实的需求:

  1. 让模型去查外部数据、调外部能力
  2. 让模型别再乱飘,稳定按结构返回结果

这时最常遇到的就是这 3 个词:

  1. Tool
  2. Function Calling
  3. Structured Output

它们经常一起出现,但不是同一层概念。

1. 把这 3 个词分开

把最外层分开:

  1. Tool:系统里准备好的一个动作
  2. Function Calling:模型表达“我想调用哪个动作,参数是什么”
  3. Structured Output:模型按约定结构返回结果

把它们压成最短的一层关系,就是:

  1. Tool 是能力本身
  2. Function Calling 是调用意图
  3. Structured Output 是输出约束

如果这三层不先分开,后面很容易把“能调用工具”和“按 JSON 返回”混成一回事。

2. Tool 到底是什么

Tool 可以理解成:

应用提供给模型使用的一个具体动作入口。

它最适合承载的是清晰、边界明确的动作,例如:

  1. 查订单
  2. 查天气
  3. 搜文档
  4. 读文件
  5. 调内部接口

2.1 Tool 在项目里主要解决什么问题

模型本身能理解、能生成,但它不能直接:

  1. 查数据库
  2. 调你公司的内部系统
  3. 访问你的文件系统
  4. 执行真实业务动作

Tool 的价值就在这里:

把“模型想做某个动作”变成“系统里真的有一个动作可以执行”。

2.2 一个典型 Tool 长什么样

一个极简示意可以看成这样:

json
{
  "name": "get_order_summary",
  "description": "根据订单号查询订单状态和关键时间点",
  "parameters": {
    "type": "object",
    "properties": {
      "orderNo": { "type": "string" }
    },
    "required": ["orderNo"]
  }
}

这里最关键的不是 JSON 长什么样,而是它在表达 3 件事:

  1. 这个动作叫什么
  2. 它是做什么的
  3. 调它时需要什么参数

2.3 Tool 最容易踩的坑

最常见的问题有:

  1. 把一个 Tool 设计成完整业务流程
  2. 把底层能力裸暴露给模型
  3. 以为 Tool 越多系统越强

🌟 Tool 更适合表达一个清晰动作,不适合直接承载一整条复杂流程。流程编排通常应该放到 WorkflowAgent 那一层。

3. Function Calling 到底在干什么

当模型判断“只靠文本回答不够,需要外部能力”时,它不会自己直接去调数据库,而是先输出一个结构化调用意图。

例如:

json
{
  "name": "get_order_summary",
  "arguments": {
    "orderNo": "A001"
  }
}

这一步最关键的不是执行,而是表达:

我现在需要哪个 Tool,参数应该是什么。

3.1 Function Calling 主要解决什么问题

它解决的是:

模型如何把“我要查外部信息”这件事稳定表达出来。

没有这一层,模型就只能在自然语言里模糊地说:

  1. “你去帮我查一下订单”
  2. “也许应该调用某个接口”

但系统很难从这种自由文本里稳定解析出真正的调用动作。

有了 Function Calling 之后,模型就能把调用意图收成更稳定的结构。

3.2 一条典型链路怎么走

mermaid
sequenceDiagram
    participant U as 用户
    participant A as 应用
    participant M as 模型
    participant T as Tool

    U->>A: 查订单 A001
    A->>M: 用户问题 + tools 描述
    M-->>A: 调用 getOrder(orderNo=A001)
    A->>T: 执行 Tool
    T-->>A: 返回订单数据
    A->>M: 追加 tool 结果
    M-->>A: 生成最终回答

这条线里要先分清两件事:

  1. 模型负责表达要不要调工具
  2. 应用负责真正执行工具

也就是说,Function Calling 不是“模型自己动手了”,而是“模型把调用意图说清楚了”。

3.3 Function Calling 最容易被误解成什么

最常见的误解是:

  1. 以为它等于工具本身
  2. 以为模型拿到 Tool 就一定会调用
  3. 以为调用意图出来之后执行就天然安全

这些都不太准。

是否真的执行、能不能执行、该不该执行,最后都还是应用系统负责。

4. Structured Output 又在干什么

有些场景并不需要模型调工具,只是希望它稳定返回一个结构。

例如:

  1. 分类结果
  2. 表单抽取
  3. 审核结论
  4. 风险评分
  5. 报告字段提取

这时更适合用的是 Structured Output

例如:

json
{
  "category": "refund",
  "confidence": 0.92,
  "reason": "用户主要在询问退款流程"
}

它解决的问题不是“去做动作”,而是:

让模型别只返回一段自由文本,而是按约定结构把结果交出来。

4.1 Structured Output 在项目里为什么这么重要

因为只要输出要继续进入系统后续环节,例如:

  1. 存库
  2. 分流
  3. 审批
  4. 前端表单回填

自然语言就会变得很不稳。

系统真正需要的往往不是“说得像不像人”,而是:

  1. 字段有没有
  2. 结构稳不稳
  3. 能不能继续被程序消费

4.2 Structured OutputFunction Calling 的区别

这两个词最容易混。

可以用一句话分开:

  • Function Calling 更偏“我要调谁”
  • Structured Output 更偏“我要按什么结构返回”

前者强调调用意图,后者强调输出约束。

5. 这 3 者放在一起怎么配合

把它们放在同一条线上看,会更容易理解:

mermaid
flowchart LR
    A[用户问题] --> B{是否需要外部能力}
    B -- 否 --> C[Structured Output / 普通文本输出]
    B -- 是 --> D[Function Calling]
    D --> E[调用 Tool]
    E --> F[回传结果]
    F --> G[模型生成最终结果]

这条线里:

  1. Tool 是能力入口
  2. Function Calling 是调用表达
  3. Structured Output 是结果约束

它们会一起出现,但并不总是一起出现。

例如:

  1. 分类任务可能只需要 Structured Output
  2. 查订单任务通常会涉及 Tool + Function Calling

6. 真实项目里最容易踩的几个边界

6.1 不是所有结构化输出都是 Tool Calling

模型只要按 JSON 返回,就已经是结构化输出。

但只有当它在表达:

  1. 要调哪个工具
  2. 参数是什么

这才更接近 Function Calling

6.2 不是有 Tool 就一定要调用

很多系统会给模型挂很多 Tool,但模型不一定每次都需要调用。

是否调用,本质上取决于:

  1. 当前问题能不能直接回答
  2. 外部数据是不是必须
  3. 调用成本和值不值得

6.3 调用意图不等于执行安全

模型能把调用意图表达出来,不代表执行就一定安全。

应用层通常还要继续负责:

  1. 参数校验
  2. 权限控制
  3. 风险动作拦截
  4. 幂等和审计

7. 一段更稳的总结

如果把这 3 个词压成一句话,可以记成:

Tool 解决“系统里有什么动作可以调”,Function Calling 解决“模型如何把调用意图表达清楚”,Structured Output 解决“模型怎么稳定地按结构返回结果”。它们经常一起出现,但分别站在能力、调用和输出这 3 个不同层次。

8. 继续展开看

基于 VitePress 构建的个人技术笔记。