我终于搞懂了 Tool、Function Calling 和 MCP:大模型到底怎么知道该调哪个接口?

最近学习 Agent、Tool Calling、Function Calling 和 MCP 时,我一直有一个疑问:

用户只是问了一句话,大模型到底怎么知道系统里有哪些 Tool?
又是怎么知道哪个 Tool 是查订单、哪个 Tool 是查库存的?

真正搞懂以后,核心其实只有一句话:

不是把所有接口说明手工写进 Prompt,而是在每次调用模型 API 时,把当前可用的 Tool 定义通过专门的 tools 参数一起传给模型。

下面用一个“业务系统问答助手查询订单”的例子,从头讲清楚。


1. 先看最终效果

业务系统原来有一个订单接口:

GET /api/orders/123

用户在问答助手里说:

帮我查一下订单 123 现在什么状态

我们希望最终变成:

用户问题
↓
大模型判断应该调用 query_order
↓
业务系统真正执行 query_order("123")
↓
query_order 调订单接口
↓
返回“已发货”
↓
结果重新交给大模型
↓
大模型回答:订单 123 已发货

这里最关键的就是:

大模型为什么知道有一个叫 query_order 的 Tool?


2. Tool 到底是什么

对于业务系统来说,Tool 可以先理解成:

一个普通后端函数 + 一份给大模型看的函数说明。

例如我们先写一个普通 Python 函数:

def query_order(order_no: str):
    # 实际项目中,这里可以调用订单 Service 或 HTTP API
    return {
        "order_no": order_no,
        "status": "已发货"
    }

这只是一个普通函数。

此时大模型还完全不知道:

query_order 是什么
它有什么参数
什么时候应该调用它

所以还要再给模型一份 Tool 定义。


3. Tool 定义到底长什么样

例如:

tools = [
    {
        "type": "function",
        "name": "query_order",
        "description": "根据订单号查询订单当前状态。",
        "parameters": {
            "type": "object",
            "properties": {
                "order_no": {
                    "type": "string",
                    "description": "订单号,例如 123"
                }
            },
            "required": ["order_no"]
        }
    }
]

可以把它翻译成人话:

name
=
这个 Tool 叫 query_order


description
=
这个 Tool 是用来查询订单状态的


parameters
=
调用这个 Tool 时,需要传哪些参数


order_no
=
订单号,字符串类型

所以真正让模型理解 Tool 的,不是 Python 函数代码本身,而是:

name
description
parameters / Schema

这些结构化信息。


4. 最关键:这些 Tool 说明到底怎么给到大模型

不是你每次手工写:

你现在有三个工具:
query_order 是查订单的……
query_inventory 是查库存的……

而是你的程序调用模型 API 时,同时传:

用户问题
+
tools

例如使用 OpenAI Responses API,可以写成:

from openai import OpenAI

client = OpenAI()

tools = [
    {
        "type": "function",
        "name": "query_order",
        "description": "根据订单号查询订单当前状态。",
        "parameters": {
            "type": "object",
            "properties": {
                "order_no": {
                    "type": "string",
                    "description": "订单号,例如 123"
                }
            },
            "required": ["order_no"]
        }
    }
]

response = client.responses.create(
    model="gpt-6-astra",
    input="帮我查一下订单 123 现在什么状态",
    tools=tools,
    tool_choice="auto"
)

注意这一段:

tools=tools

这就是关键。

程序实际向模型服务发送的内容,可以简单理解成:

input:
帮我查一下订单 123 现在什么状态


tools:
- name: query_order
  description: 根据订单号查询订单当前状态
  parameters:
    order_no: string

所以:

模型确实拿到了 Tool 的说明,只是它不是普通 Prompt 文字,而是模型 API 请求里的结构化 tools 字段。


5. Tool 定义是不是每次调用模型都要传

从概念上说:

模型这一轮要使用哪些 Tool,这一轮调用时就必须让模型知道这些 Tool。

但不是开发人员每次手工复制粘贴。

实际程序通常这样写:

TOOLS = [
    # 所有 Tool 定义
]

程序启动时就已经准备好了。

以后每次用户提问:

response = client.responses.create(
    model="gpt-6-astra",
    input=user_question,
    tools=TOOLS
)

也就是说:

开发一次 Tool 定义
↓
程序保存 Tool 定义
↓
用户每次提问
↓
程序自动把当前允许的 Tool 一起传给模型

用户完全感知不到这一过程。


6. 模型收到 Tool 后会怎么做

假设模型看到:

用户:
帮我查一下订单 123 现在什么状态


可用 Tool:

query_order
作用:根据订单号查询订单状态
参数:order_no

模型会判断:

这个问题需要真实订单数据
↓
我不能自己编
↓
有 query_order 可以用
↓
应该调用 query_order
↓
order_no = 123

于是模型可能返回一个 Function Call:

{
  "type": "function_call",
  "name": "query_order",
  "arguments": "{\"order_no\":\"123\"}"
}

注意:

这时候大模型并没有真的执行 query_order()

它只是告诉你的后端:

“我决定调用 query_order,参数是 123。”


7. 真正执行 Tool 的是你的业务系统后端

你的程序拿到模型返回的 Function Call 后:

import json

for item in response.output:
    if item.type == "function_call":
        arguments = json.loads(item.arguments)

        if item.name == "query_order":
            result = query_order(
                order_no=arguments["order_no"]
            )

真正执行的是这一句:

result = query_order(...)

也就是说:

大模型
=
决定“调用谁、传什么参数”


业务系统后端
=
真正执行函数

大模型本身不能直接进入你的数据库,也不会自动执行你的 Python 函数。


8. Tool 函数再调用真正的业务接口

实际项目里,query_order() 可能是:

import httpx

def query_order(order_no: str):
    response = httpx.get(
        f"http://business-system/api/orders/{order_no}",
        timeout=10
    )

    response.raise_for_status()

    return response.json()

完整关系就是:

用户
↓
问答助手
↓
大模型
↓
Function Call:query_order("123")
↓
问答助手后端
↓
query_order()
↓
GET /api/orders/123
↓
业务系统

9. 接口结果怎么再告诉模型

假设 Tool 执行结果是:

{
  "order_no": "123",
  "status": "已发货"
}

还需要把这个结果再次交给模型。

例如:

tool_output = json.dumps(
    result,
    ensure_ascii=False
)

final_response = client.responses.create(
    model="gpt-6-astra",
    previous_response_id=response.id,
    tools=tools,
    input=[
        {
            "type": "function_call_output",
            "call_id": item.call_id,
            "output": tool_output
        }
    ]
)

print(final_response.output_text)

模型这次看到的意思相当于:

你刚才调用的:

query_order("123")

执行结果:

{
  "order_no": "123",
  "status": "已发货"
}

于是模型最后回答:

订单 123 当前已经发货。

10. 把完整过程串起来

整个 Function Calling / Tool Calling 流程其实就是:

第一步
用户:
“帮我查订单 123”
↓


第二步
问答助手后端调用模型:

用户问题
+
Tool 定义
↓


第三步
模型判断:

应该调用 query_order
参数 order_no=123
↓


第四步
模型返回 Function Call:

query_order("123")
↓


第五步
业务系统后端真正执行:

query_order("123")
↓


第六步
Tool 调业务接口:

GET /api/orders/123
↓


第七步
接口返回:

已发货
↓


第八步
把 Tool Result 再交给模型
↓


第九步
模型生成最终回答:

“订单 123 当前已经发货。”

这就是最基本的 Agent Tool Calling。


11. 如果有很多 Tool,模型怎么选

假设系统里定义了:

query_order
= 查询订单


query_inventory
= 查询库存


create_ticket
= 创建工单

调用模型时:

tools = [
    query_order 的定义,
    query_inventory 的定义,
    create_ticket 的定义
]

用户问:

ABC001 还有多少库存?

模型会根据:

Tool 名称
Tool description
参数说明
用户当前问题

进行匹配。

所以它选择:

query_inventory

而不是:

query_order

因此 Tool 的 description 写得是否准确,非常重要。


12. Tool 很多时,是不是全部都传给模型

小系统只有十几个 Tool 时,可以直接全部传。

但是如果以后有:

500 个 Tool
1000 个 Tool

就不适合每次全部给模型。

通常会增加一层 Tool Router,例如:

用户:
“查一下订单”
↓
先判断属于:
订单领域
↓
只取:
query_order
query_order_logistics
cancel_order
↓
把这几个 Tool 给模型

这样可以减少:

Context 占用
Tool 选择干扰
错误调用概率

13. Function Calling 和 Tool Calling 到底是什么关系

小白阶段可以先理解为:

Function Calling 是 Tool Calling 最常见的一种实现方式。

例如:

Tool:
query_order

实际上就是:

让模型输出:

函数名
+
函数参数

所以经常会看到:

Function Calling
Tool Calling

两个词一起出现。

现在更常用 Tool Calling 这个更大的概念,因为 Tool 不一定只有普通 Function,还可能包括:

Web Search
File Search
MCP
Shell
Computer
……

14. 那 MCP 和这种普通 Tool Calling 有什么区别

普通 Tool Calling:

你的问答助手
↓
你自己在代码中维护 tools
↓
模型

例如:

tools = [
    {
        "name": "query_order",
        ...
    }
]

Tool 定义是你的问答助手自己写、自己维护的。


MCP 则是:

问答助手 / Codex
↓
MCP Client
↓
MCP Server

MCP Client 连接 MCP Server 后,会从 Server 获取:

有哪些 Tool
Tool 名称
Tool description
inputSchema

例如 MCP Server 返回:

query_order
= 查询订单

query_inventory
= 查询库存

于是 Harness / MCP Client 再把这些 Tool 提供给模型。

所以最终模型看到的东西其实还是:

Tool 名称
Tool 说明
Tool 参数

区别只是:

普通 Tool Calling
=
Tool 定义由你的应用自己维护


MCP
=
Tool 定义由 MCP Server 按统一标准提供

15. MCP 为什么不需要手工维护 tools 数组

普通方式可能写:

tools = [
    query_order_schema,
    query_inventory_schema,
    create_ticket_schema
]

如果用了 MCP:

MCP Client
↓
连接 MCP Server
↓
获取 Tool 列表
↓
得到 name / description / inputSchema
↓
自动转成模型可以使用的 Tool 定义
↓
交给模型

所以:

MCP 帮你解决了 Tool 的标准化发现和接入问题。

不是说用了 MCP 后模型不需要 Tool 描述。

而是:

Tool 描述由 MCP Server 自动提供,而不是业务问答助手自己硬编码维护。


16. 什么时候不用 MCP

如果你的场景是:

一个业务系统
+
系统内部自己的问答助手
+
只有这个问答助手会调用这些接口

例如:

业务系统
├── 订单模块
├── 库存模块
└── 问答助手

最简单的方案就是:

问答助手
↓
普通 Tool Calling
↓
Tool 函数
↓
内部 Service / HTTP API

完全没有必要为了 MCP 而 MCP。

这样:

开发简单
链路短
调试方便

17. 什么时候应该用 MCP

如果以后希望同一套能力给:

业务问答助手
Codex
OpenClaw
DSH
其他 Agent

一起使用,就比较适合 MCP。

例如:

                ERP MCP Server
               /      |       \
              /       |        \
             ↓        ↓         ↓
          Codex    OpenClaw   内部助手

ERP MCP Server 统一提供:

query_order
query_inventory
create_purchase_request

所有支持 MCP 的 Agent 都按统一方式接入。

所以 MCP 更适合:

多 Agent 复用
跨系统接入
企业统一能力平台
Tool 数量持续增长
希望降低重复适配开发

18. Tool 和 MCP 不是二选一

这一点特别重要。

不是:

用了 MCP
就不用 Tool

而是:

MCP Server
里面提供的核心能力
本身仍然是 Tool

可以理解成:

Tool
=
具体能力


MCP
=
把这些 Tool 标准化提供出去的协议

例如:

query_order

始终是 Tool。

只给自己系统使用:

内部问答助手
↓
直接 Tool Calling
↓
query_order

提供给多个 Agent:

Codex
↓
MCP
↓
ERP MCP Server
↓
query_order

19. 最终把几个词放在一起

HTTP API
=
业务系统原来的接口


Tool 函数
=
真正执行某项业务能力的后端函数


Tool Schema
=
告诉模型 Tool 名称、用途和参数


Function Calling / Tool Calling
=
模型根据 Tool Schema 决定调用哪个 Tool


MCP
=
标准化发现和调用这些 Tool 的协议


MCP Server
=
按 MCP 标准提供 Tool 的服务

20. 最后记住这张图

不使用 MCP

用户
↓
业务系统问答助手
↓
把用户问题 + tools 参数交给模型
↓
模型选择 query_order
↓
问答助手后端执行 query_order
↓
业务 API
↓
返回结果
↓
再次交给模型
↓
最终回答

使用 MCP

MCP Server
↓
提供 Tool Schema
↓
MCP Client 自动获取 Tool
↓
Harness 把 Tool 提供给模型
↓
模型选择 Tool
↓
MCP Client 调 MCP Server
↓
执行业务能力
↓
返回结果
↓
模型最终回答

最后总结

最需要搞懂的其实就是这一点:

大模型并不会天然知道你的业务系统有哪些接口。

普通 Tool Calling 的做法是:

开发人员定义 Tool Schema
↓
程序调用模型时通过 tools 参数一起传进去
↓
模型根据 name / description / parameters 选择 Tool

MCP 的做法是:

MCP Server 提供 Tool Schema
↓
MCP Client 自动发现
↓
再提供给模型

所以:

只给一个业务系统自己的问答助手使用时,直接 Tool Calling 往往最简单;当同一批 Tool 需要被 Codex、OpenClaw、DSH 等多个 Agent 统一复用时,再使用 MCP。

posted @ 2026-09-04 15:19  人艰不拆_zmc  阅读(17)  评论(0)    收藏  举报