Structured Output、Function Calling 和 MCP

7 天前(已编辑)
2

Structured Output、Function Calling 和 MCP

0. 引言

本文章将会以“天气怎么样”这个话题讲述 Structured Output、Function Calling 和 MCP 这三个概念,通过本地在 LM Studio 上部署的 qwen/qwen3-4b-2507 进行示例展示

1. Function Calling 工具调用

1.1. Tool 工具

1.1.1 Why 为什么

传统的大模型都表现为对话形式,一问一答,只能 chat,无法与现实世界交互
以最常见的「今天天气怎么样」为例,ai 肯定无法给出或者直接编造出一个回答

那么如何解决这种问题呢,如下:

  1. 用户发送消息
    「我明天要在成都上下班通勤,天气怎么样?」
  2. 后端在向 LLM 发送请求前解析消息,发现有「明天」「天气」「成都」这些关键字
  3. 调用已经为这种情况预设好的方法,如 Weather w = weatherService.getWeather("成都", DateUtil.tomorrow()); 获取天气信息
  4. 再将天气信息插入到用户消息中,即
    「成都今天最高 18℃,最低 12℃,小雨,降水概率 70% 。 我明天要在成都上下班通勤,天气怎么样?」
  5. 这时候 AI 就不会编造或者无法回答了,将根据后端插入的信息回答
Mermaid Loading...

上述流程的问题很明显:

  1. 关键词的解析非常脆弱:如果用户发送消息换成
    「我明天要在成都上下班通勤,会下雨吗?」
    那显然就解析失败了,漏判了这个需要获取天气信息的请求
    比如「...又是灰蒙蒙的天气死我了」
    解析成功了,但是没什么用,在请求中增添了无用的天气信息,污染上下文,浪费 AI 调用成本
  2. 需要预设场景:需要后端考虑很多场景,并建立相应的解析规则以提供外部信息源
  3. 不由模型控制,无法与现实世界交互:是后端进行工具的使用,整个表现仍然是一个 chatbox,大语言模型无法主动调用,也就是当模型想获取天气信息时无法主动得到

1.1.2 What 是什么

从上面的示例能看出,LLM 无法自主获取信息,只能被动的在用户的请求中获得
Function Calling 就赋予 LLM 一种与外界交互的能力,通过规定好的格式,让 LLM 告诉后端调用什么工具,并将结果返回进上下文中,以此获取外部信息或是操控外部数据

从概念上看,Function Calling 有三个关键点:

  1. 工具定义 tools
    告诉 LLM:工具名称、工具描述、参数 JSON Schema
"tools": [
  {
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "获取指定城市的天气信息。当用户询问天气、降水、温度等相关问题时使用此工具。",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "城市名称,例如:成都、北京"
          },
          "extensions": {
            "type": "string",
            "enum": [
              "base",
              "all"
            ],
            "description": "气象类型:\n  - base: 返回实况天气,适用于查询\"现在\"、\"当前\"、\"实时\"的天气\n  - all: 返回预报天气(未来3-4天),适用于查询\"明天\"、\"后天\"、\"未来几天\"的天气"
          }
        },
        "required": [
          "location",
          "extensions"
        ]
      }
    }
  }
]
  1. 工具调用 tool_calls: 当模型认为需要执行某个工具时,会生成一条带有 tool_calls 参数的 Aimessage,里面会有这个工具调用的 id name arguments,这个工具调用等价于「获取成都未来的天气」
"tool_calls": [
  {
    "type": "function",
    "id": "606046057",
    "function": {
      "name": "get_weather",
      "arguments": "{\"location\":\"成都\",\"extensions\":\"all\"}"
    }
  }
]
  1. 工具结果消息 ToolExecutionResultMessage: 后端收到 LLM 的消息,发现有 tool_calls,根据里面的工具名和参数执行方法,并将结果包装成一条 "rool": "tool", "id": "对应 tool_call 的那条 id" 的消息,放进消息历史,让模型能够看到

也就是 Function Calling 让 LLM 拥有了规范化的主动获取信息、主动交互的能力

1.1.3 How 使用

Function Calling 的流程很简单

Mermaid Loading...

示例:

请求体:

{
  "model": "qwen3-4b-2507",
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "获取指定城市的天气信息。当用户询问天气、降水、温度等相关问题时使用此工具。",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "城市名称,例如:成都、北京"
            },
            "extensions": {
              "type": "string",
              "enum": [
                "base",
                "all"
              ],
              "description": "气象类型:\n  - base: 返回实况天气,适用于查询\"现在\"、\"当前\"、\"实时\"的天气\n  - all: 返回预报天气(未来3-4天),适用于查询\"明天\"、\"后天\"、\"未来几天\"的天气"
            }
          },
          "required": [
            "location",
            "extensions"
          ]
        }
      }
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": "我明天要在成都上下班通勤,会下雨吗?"
    }
  ]
}

响应体:

{
  "id": "chatcmpl-g23i230saulvl49aru2okl",
  "object": "chat.completion",
  "created": 1763727823,
  "model": "qwen/qwen3-4b-2507",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "",
        "tool_calls": [
          {
            "type": "function",
            "id": "606046057",
            "function": {
              "name": "get_weather",
              "arguments": "{\"location\":\"成都\",\"extensions\":\"all\"}"
            }
          }
        ]
      },
      "logprobs": null,
      "finish_reason": "tool_calls"
    }
  ],
  "usage": {
    "prompt_tokens": 275,
    "completion_tokens": 26,
    "total_tokens": 301
  },
  "stats": {},
  "system_fingerprint": "qwen/qwen3-4b-2507"
}

上面的响应体中可以看到 id 为 606046057 的 tool_call 调用,后端读取后,即调用工具,获取天气信息,随后加入到消息历史中,并再次调用 LLM

请求体:

{
  "model": "qwen/qwen3-4b-2507",
  "messages": [
    {
      "role": "user",
      "content": "我明天要在成都上下班通勤,天气怎么样?"
    },
    {
      "content": "",
      "role": "assistant",
      "tool_calls": [
        {
          "id": "398625313",
          "function": {
            "arguments": "{\"location\":\"成都\",\"extensions\":\"all\"}",
            "name": "get_weather"
          },
          "type": "function"
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "398625313",
      "name": "get_weather",
      "content": "{\"status\": \"1\", \"count\": \"1\", \"info\": \"OK\", \"infoc... <Truncated in logs> ... \"nighttemp_float\": \"8.0\"}]}], \"_city_name\": \"成都\"}"
    }
  ]
}

需要注意的是,添加的 ToolExecutionResultMessage 里有一个 tool_call_id 参数需要与 AiMessagetool_calls 中的 id 对应

2. 结构化输出 Structured Output

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...