在工程实践中,大模型不再只是一个“会聊天的接口”,而是需要作为业务系统的一部分,去访问数据库、调用 HTTP API、触发内部服务。 要做到这一点,必须有一层清晰的“调用抽象”,把模型输出安全、可靠地映射为函数调用和系统操作——这层抽象就是 Function Calling,以及在更复杂场景下的 MCP。
1、Function Calling 在大模型中的作用是什么?
从典型的“查天气”场景看,一个简单的问题背后往往包含两类能力:
- 访问外部数据源(例如实时天气接口);
- 基于数据生成自然语言响应。
这正是 Function Calling 发挥价值的地方:让模型既能理解用户意图,又能驱动底层能力。
- 扩展模型能力
大模型本身无法直接访问外部世界(数据库、HTTP API、本地程序等),但通过 Function Calling,可以把这些能力“接”到模型身上,例如:
- 结构化输出
模型不仅输出“文本”,还可以输出结构化参数,作为函数调用的入参。 例如,用户说:“明天北京天气如何?” 模型可以生成一条函数调用:
get_weather(location="北京", date="2025-05-06")
这条调用就是“自然语言 → 结构化参数 → 真正函数执行”的桥梁。
- 动态决策流程
模型可以根据上下文,自主决定要不要调用函数、调用哪个函数、按什么顺序调用:
一句话总结:Function Calling 是大模型与真实世界交互的“桥梁”,负责把“自然语言意图”转换为“可执行的函数调用”。
2、Function Calling 与 MCP 的区别?
| 维度 | Function Calling | MCP |
|---|---|---|
| 定位 | 模型厂商私有接口(如 OpenAI, Qwen) | 开放协议(类似统一“USB-C 接口”) |
| 扩展性 | 需为每个模型单独适配 | 一次开发,多模型兼容 |
| 复杂性 | 适合简单、单次调用任务 | 支持多轮对话、复杂上下文管理 |
| 生态依赖 | 依赖特定模型(如 GPT-4、Qwen) | 跨模型、跨平台(如 Claude、Cursor) |
| 安全性 | 依赖云端 API 密钥 | 更易做本地化部署与数据控制 |
可以简单理解为:
- Function Calling更像是“某个模型厂商提供的函数调用接口规范”,偏向模型内部实现;
- MCP更像是“跨模型通用的工具协议”,偏向系统集成与架构层,一次实现,可以被多个模型客户端消费。
3、已经有了 MCP,还需要 Function Calling 吗?
需要,而且会长期共存。
- 对于简单、原子化任务,直接用 Function Calling 往往更轻量:
- 优势:
可以把 MCP 看作“更通用、更工程化的上层方案”,而 Function Calling 是“大模型底层能力的一部分”,两者并不互斥。
4、CASE:用 Qwen3 + 高德天气 Function Calling 查天气
这一节基于一个完整的示例项目,从“环境与依赖 → 工具实现 → 智能体初始化 → 交互入口(TUI/GUI)”,串起一个可在本地直接运行的 Function Calling + MCP 天气助手。
Step1:环境与依赖准备
在实现任何基于 Function Calling 的应用前,推荐先把依赖和运行环境标准化,确保各端一致可复现。
示例项目的依赖在requirements.txt中已经列出,例如:
dashscope==1.22.1
pandas==2.3.0
qwen_agent==0.0.25
Requests==2.32.4
说明:qwen_agent只需保留一个版本即可,实际安装时建议选择最新稳定版,避免多版本共存带来的依赖冲突。
- 安装依赖(以 conda / pip 为例):
pip install -r requirements.txt
- 配置必要环境变量:
在 Windows PowerShell 中可以临时设置(当前会话),用于本地开发调试:
$env:DASHSCOPE_API_KEY = "你的DashScopeKey"
$env:AMAP_MAPS_API_KEY = "你的高德Key"
Step2:配置大模型与工具系统(DashScope + Qwen Agent)
这一层主要是把“大模型服务”与“智能体框架”串起来,形成一个可扩展的调用入口。 在示例代码中,首先完成大模型 SDK 和工具框架的基础配置:
import os
import requests
import dashscope
from qwen_agent.agents import Assistant
from qwen_agent.gui import WebUI
from qwen_agent.tools.base import BaseTool, register_tool
# 配置 DashScope
dashscope.api_key = os.getenv("DASHSCOPE_API_KEY")
print("dashscope.api_key:" + dashscope.api_key)
dashscope.timeout = 30 # 设置超时时间为 30 秒
- 使用
qwen_agent作为代理框架,负责:
在后面的初始化里,会通过Assistant把模型配置和工具列表串起来。
Step3:实现天气查询工具(Function Calling + 高德 API)
这一层对应“能力封装”,把具体的天气查询逻辑封装成一个可被模型安全调用的工具。
示例中通过继承BaseTool+@register_tool,实现了一个完整的天气查询工具WeatherTool,供 Qwen 调用:
@register_tool('get_current_weather')
class WeatherTool(BaseTool):
"""
天气查询工具,通过高德地图API查询指定位置的天气情况。
"""
description = '获取指定位置的当前天气情况'
parameters = [{
'name': 'location',
'type': 'string',
'description': '城市名称,例如:北京',
'required': True
}, {
'name': 'adcode',
'type': 'string',
'description': '城市编码,例如:110000(北京)',
'required': False
}]
def call(self, params: str, **kwargs) -> str:
import json
args = json.loads(params)
location = args['location']
adcode = args.get('adcode', None)
return self.get_weather_from_gaode(location, adcode)
- 关键点:
真正访问高德天气 API 的逻辑在get_weather_from_gaode中:
def get_weather_from_gaode(self, location: str, adcode: str = None) -> str:
"""调用高德地图API查询天气"""
gaode_api_key = os.getenv("AMAP_MAPS_API_KEY") # 高德API Key
base_url = "https://restapi.amap.com/v3/weather/weatherInfo"
params = {
"key": gaode_api_key,
"city": adcode if adcode else location,
"extensions": "base", # 可改为 "all" 获取预报
}
try:
response = requests.get(base_url, params=params)
if response.status_code == 200:
data = response.json()
if data.get('status') == '1'and data.get('lives'):
weather_info = data['lives'][0]
result = (
f"天气查询结果:\n"
f"城市:{weather_info.get('city')}\n"
f"天气:{weather_info.get('weather')}\n"
f"温度:{weather_info.get('temperature')}°C\n"
f"风向:{weather_info.get('winddirection')}\n"
f"风力:{weather_info.get('windpower')}\n"
f"湿度:{weather_info.get('humidity')}%\n"
f"发布时间:{weather_info.get('reporttime')}"
)
return result
else:
returnf"获取天气信息失败:{data.get('info', '未知错误')}"
else:
returnf"请求失败:HTTP状态码 {response.status_code}"
except Exception as e:
returnf"获取天气信息出错:{str(e)}"
这里做了几件事:
- 从环境变量读取高德
AMAP_MAPS_API_KEY; - 调用实时天气接口
/v3/weather/weatherInfo; - 对返回 JSON 进行检查与格式化,生成用户可读的中文天气描述。
Step4:初始化助手服务(Qwen Agent + MCP 集成)
init_agent_service这一层可以理解为“Agent 装配层”,把模型配置、工具列表(包括自定义工具 + MCP Server)组装成一个真正可对话、可扩展的“天气助手”:
def init_agent_service():
"""初始化助手服务"""
llm_cfg = {
'model': 'qwen-turbo-2025-04-28',
'timeout': 30,
'retry_count': 3,
}
tools = [
'get_current_weather', # 上面注册的天气查询工具
{
"mcpServers": {
"amap-maps": {
"command": "npx",
"args": [
"-y",
"@amap/amap-maps-mcp-server"
],
"env": {
# 从环境变量中读取高德地图 API Key
"AMAP_MAPS_API_KEY": os.getenv("AMAP_MAPS_API_KEY", "")
}
}
}
}
]
try:
bot = Assistant(
llm=llm_cfg,
name='天气助手',
description='天气助手,查询天气',
system_message="你是一名有用的助手",
function_list=tools, # 增加天气工具 + MCP
)
print("助手初始化成功!")
return bot
except Exception as e:
print(f"助手初始化失败: {str(e)}")
raise
- 亮点:
这一步完成后,我们就拥有了一个具备天气查询能力的“智能体对象”bot。
Step5:终端交互模式(app_tui)
命令行模式适合开发和调试阶段,便于观察原始输入输出和日志。
可以直接使用app_tui在终端中与助手连续对话:
def app_tui():
"""终端交互模式
提供命令行交互界面,支持:
- 连续对话
- 文件输入
- 实时响应
"""
try:
# 初始化助手
bot = init_agent_service()
# 对话历史
messages = []
whileTrue:
try:
# 获取用户输入
query = input('user question: ')
# 获取可选的文件输入
file = input('file url (press enter if no file): ').strip()
# 输入验证
ifnot query:
print('user question cannot be empty!')
continue
# 构建消息
ifnot file:
messages.append({'role': 'user', 'content': query})
else:
messages.append({'role': 'user', 'content': [{'text': query}, {'file': file}]})
print("正在处理您的请求...")
# 运行助手并处理响应(流式)
response = []
for response in bot.run(messages):
print('bot response:', response)
messages.extend(response)
except Exception as e:
print(f"处理请求时出错: {str(e)}")
print("请重试或输入新的问题")
except Exception as e:
print(f"启动终端模式失败: {str(e)}")
- 支持连续对话:
messages里累计上下文; - 支持简单的“文本 + 文件 URL”混合输入;
bot.run(messages)内部会自动处理 Function Calling / MCP 调用,无需手动拼接tool_calls。
Step6:GUI 图形界面模式(app_gui)
在实际 demo、内部培训或与非技术角色协作时,Web GUI 能显著降低使用门槛。
示例中的app_gui使用WebUI快速构建了一个 Web 聊天界面:
def app_gui():
"""图形界面模式,提供 Web 图形界面"""
try:
print("正在启动 Web 界面...")
# 初始化助手
bot = init_agent_service()
# 配置聊天界面,列举典型提问
chatbot_config = {
'prompt.suggestions': [
'北京今天的天气怎么样?',
]
}
print("Web 界面准备就绪,正在启动服务...")
# 启动 Web 界面
WebUI(
bot,
chatbot_config=chatbot_config
).run()
except Exception as e:
print(f"启动 Web 界面失败: {str(e)}")
print("请检查网络连接和 API Key 配置")
配合入口:
if __name__ == '__main__':
# 运行模式选择
app_gui() # 图形界面模式(默认)
运行方式非常简单:配置好依赖和环境变量后,直接运行该示例脚本即可。
启动后终端会提示本地地址(如http://127.0.0.1:7860),在浏览器中打开即可开始用中文对话查天气。
小结:从 Function Calling 底层能力到可交付的天气助手
从工程视角看,这个示例覆盖了一个典型 Agent 应用的完整链路:
- 依赖和运行环境:通过
requirements.txt与环境变量约定,确保可复现性与密钥安全; - 领域工具封装:使用
WeatherTool封装高德天气 API,统一参数与返回格式; - Agent 装配与集成:在初始化阶段组合 Qwen 模型、自定义工具与 MCP Server;
- 多种交互入口:同时支持终端
app_tui与 Web GUIapp_gui,便于调试与演示。
相比很多只停留在“单次 Function 调用”的示例,这个案例更接近真实项目形态, 展示了如何把Function Calling + MCP + Agent 框架落在一个可以直接运行、可扩展的 AI 天气助手上,为后续接更多业务系统打下基础。