LLM Engineering2026年5月21日

06 Function Calling&MCP

FunctionCallingMCPSQLAutomation

Function Calling

核心概念

Function Calling是大型语言模型(LLM)与真实世界交互的重要机制,它允许LLM通过调用预设的函数来执行模型本身无法完成的任务。

作用:

  • 扩展模型能力: LLM可以获取实时数据(天气、股价)、执行复杂计算(数学运算、代码执行)或操作外部系统(发送邮件、控制智能设备)。
  • 结构化输出: 将用户的自然语言请求转化为结构化参数,传递给函数。例如,将“明天北京天气如何?”转化为get_weather(location="北京", date="2025-05-06")
  • 动态决策流程: 模型能根据上下文决定何时调用函数,甚至进行链式调用。

Function Calling与MCP的区别

维度 | Function Calling | MCP (Model Context Protocol)

定位 | 模型厂商私有接口(如OpenAI, Qwen) | 开放协议(类似HTTP/USB-C),Anthropic于2024年11月推出

扩展性 | 需为每个模型单独适配 | 一次开发,多模型兼容

复杂性 | 适合简单、单次调用任务 | 支持多轮对话、复杂上下文管理

生态依赖 | 依赖特定模型(如GPT-4) | 跨模型、跨平台(如Claude、Cursor)

安全性 | 依赖云端API 密钥 | 支持本地化数据控制

Function Calling的必要性

尽管MCP可能成为主流,Function Calling作为底层能力仍将存在。对于简单、原子化的任务,Function Calling开发快捷、延迟低,无需MCP Server配置,直接通过模型API调用预定义函数更为方便。

案例:门票助手

此案例展示了如何使用Qwen-Agent结合Function Calling搭建一个门票业务查询助手。

整体搭建流程:

  1. 系统初始化: 设置系统Prompt,描述门票表结构和查询需求,注册SQL查询工具(exc_sql)。
  2. 助手实例化: 使用Qwen-Agent的Assistant类,加载LLM配置、系统Prompt和function_list
  3. 设置交互模式: 选择WebUI模式,用户输入问题,助手自动完成SQL查询并返回结果。
  4. Function Call机制: LLM解析意图生成SQL,exc_sql工具执行SQL并返回结果。

system_prompt 示例:

Python
system_prompt = """我是门票助手,以下是关于门票订单表相关的字段,我可能会编写对应的SQL,对数据进行查询 -- 门票订单表 CREATE TABLE tkt_orders ( order_time DATETIME, -- 订单日期 account_id INT, -- 预定用户ID gov_id VARCHAR(18), -- 商品使用人ID(身份证号) gender VARCHAR(10), -- 使用人性别 age INT, -- 年龄 province VARCHAR(30), -- 使用人省份 SKU VARCHAR(100), -- 商品SKU名 product_serial_no VARCHAR(30), -- 商品ID eco_main_order_id VARCHAR(20), -- 订单ID sales_channel VARCHAR(20), -- 销售渠道 status VARCHAR(30), -- 商品状态 -- ... 省略其他字段 ) """

exc_sql 工具注册示例:

Python
from qwen_agent.tools.base import BaseTool, register_tool import pandas as pd import json # 导入数据库连接(此处省略具体实现) # from sqlalchemy import create_engine # engine = create_engine('mysql+mysqlconnector://user:password@host/database') @register_tool('exc_sql') class ExcSQLTool(BaseTool): """ SQL查询工具,执行传入的SQL语句并返回结果。 """ description = '对于生成的SQL,进行SQL查询' parameters = [{ 'name': 'sql_input', 'type': 'string', 'description': '生成的SQL语句', 'required': True }] def call(self, params: str, **kwargs) -> str: args = json.loads(params) sql_input = args['sql_input'] database = args.get('database', 'ubr') # 假设数据库名为ubr # 创建数据库连接 (实际使用时需要具体实现) engine = None # Placeholder for actual database engine try: df = pd.read_sql(sql_input, engine) # 返回前10行,防止数据过多 return df.head(10).to_markdown(index=False) except Exception as e: return f"SQL执行出错: {str(e)}"

Assistant 初始化与 function_list

Python
from qwen_agent.agents import Assistant from qwen_agent.gui import WebUI def init_agent_service(): """初始化门票助手服务""" llm_cfg = { 'model': 'qwen-turbo-2025-04-28', 'timeout': 30, 'retry_count': 3, } try: bot = Assistant( llm=llm_cfg, name='门票助手', description='门票查询与订单分析', system_message=system_prompt, function_list=['exc_sql'], # 只传工具名字符串 ) print("助手初始化成功!") return bot except Exception as e: print(f"助手初始化失败: {str(e)}") raise # WebUI 启动示例 # if __name__ == '__main__': # bot = init_agent_service() # chatbot_config = { # 'prompt.suggestions': [ # '2023年4、5、6月一日门票,二日门票的销量多少?帮我按照周进行统计', # '2023年7月的不同省份的入园人数统计', # '帮我查看2023年10月1-7日销售渠道订单金额排名', # ] # } # WebUI(bot, chatbot_config=chatbot_config).run()

可视化图表呈现

为了在SQL查询结果后自动生成可视化图表,可以将数据查询和可视化集成到同一个工具中。

实现步骤(集成到exc_sql工具中):

  1. SQL查询获取数据: 执行SQL,获取DataFrame,生成Markdown表格。
  2. 自动推断图表字段: x轴优先选择第一个字符串类型列,y轴选择所有数值类型列。
  3. 柱状图绘制: 使用matplotlib绘制柱状图,支持多系列数据并自动调整柱宽和位置。
  4. 图表样式设置: 设置标签、标题、旋转x轴标签、添加图例等。
  5. 图表保存与返回: 保存图表为PNG文件,生成Markdown格式的图片引用,返回“表格+图片”组合结果。

示例代码片段(集成到call方法中,在df获取后):

Python
# ... (inside ExcSQLTool.call method after df is obtained) ... import matplotlib.pyplot as plt import os import time # ... (Step 1: SQL查询及markdown生成已完成) ... # Step 2: 自动推断图表字段 x_candidates = df.select_dtypes(include=['object']).columns.tolist() x = x_candidates[0] if x_candidates else (df.columns.tolist()[0] if not df.empty else None) y_candidates = df.select_dtypes(include=['number']).columns.tolist() y_fields = y_candidates if y_candidates else (df.columns.tolist()[1:] if not df.empty and len(df.columns) > 1 else []) if x and y_fields and not df.empty: plt.figure(figsize=(8, 5)) bar_width = 0.35 if len(y_fields) > 1 else 0.6 x_labels = df[x].astype(str) x_pos = range(len(df)) # Step 3: 柱状图绘制 for idx, y_col in enumerate(y_fields): plt.bar([p + idx * bar_width for p in x_pos], df[y_col], width=bar_width, label=y_col) # Step 4: 图表样式设置 plt.xlabel(x) plt.ylabel(','.join(y_fields)) plt.title(f"{' & '.join(y_fields)} by {x}") plt.xticks([p + bar_width * (len(y_fields) - 1) / 2 for p in x_pos], x_labels, rotation=45, ha='right') plt.legend() plt.tight_layout() # Step 5: 图表保存与返回 save_dir = os.path.join(os.path.dirname(__file__), 'image_show') os.makedirs(save_dir, exist_ok=True) filename = f'bar_{int(time.time()*1000)}.png' save_path = os.path.join(save_dir, filename) plt.savefig(save_path) plt.close() img_path = os.path.join('image_show', filename) img_md = f'!柱状图({img_path})' return f"{md}\n\n{img_md}" else: return md # 如果无法绘图,只返回markdown

版本更新:

  • assistant_ticket_bot-1: 实现Function Calling调用exc_sql
  • assistant_ticket_bot-2: 添加基本的图表绘制功能。
  • assistant_ticket_bot-3: 完善图表功能,支持多类别变量的透视图可视化(通过pd.pivot_table)。

实践练习

利用LLM/Agent + Function Calling,基于本地MySQL数据进行业务查询(例如:月销量、环比增长、省份销售额、Top渠道等)。

MCP使用

什么是MCP

Model Context Protocol (MCP) 是Anthropic公司于2024年11月推出的开放协议标准,旨在标准化LLM与外部数据源、工具及服务之间的交互方式。它被广泛类比为“AI领域的USB-C接口”,目标是实现统一接口和互操作性。

MCP的核心概念

  1. 架构与组件: 采用客户端-服务器(Client-Server)架构。

    Code
    _MCP Host:_* 运行AI模型的环境(如Claude Desktop, Cursor IDE)。 _MCP Client:_* 嵌入在Host中,负责发起请求并与MCP Server通信。 _MCP Server:_* 轻量级服务,提供特定功能(数据查询、API调用)。
  2. 核心功能:

    Code
    _Resources(知识扩展):_* 提供结构化数据以增强AI上下文理解。 _Tools(工具调用):_* 允许AI执行外部操作(如发送邮件、查询GitHub)。 _Prompts(提示模板):_* 预定义的指令模板,优化AI任务执行。

案例:旅游攻略MCP (高德地图)

此案例演示如何将高德地图MCP服务集成到支持MCP的客户端中,生成旅游攻略。

步骤:

  1. 获取高德地图MCP使用授权 (lbs.amap.com)。
  2. 注册开发者,创建应用并获取API KEY。
  3. 配置MCP客户端(如Cursor, Cherry Studio, GitHub Copilot)的mcp.json文件。

mcp.json 配置示例 (适用于Cursor/Cherry Studio/GitHub Copilot):

JSON
{ "mcpServers": { "amap-maps": { "command": "npx", "args": [ "-y", "@amap/amap-maps-mcp-server" ], "env": { "AMAP_MAPS_API_KEY": "你的key" } } } }

配置完成后,在客户端的Agent模式下提问即可,如“用高德MCP,做上海一天旅游攻略”。

Cherry Studio中的MCP配置:

  • 确保UV, Bun工具安装。
  • 搜索@amap并添加MCP服务,保存并打开服务。
  • 配置LLM(如qwen-turbo),选择模型并打开MCP服务器,然后提问。

案例:Tavily 搜索MCP

此案例展示如何集成Tavily实时网络搜索MCP。

步骤:

  1. 添加Tavily MCP配置到客户端的mcpServers中。

mcpServers 配置示例:

JSON
{ "mcpServers": { "tavily-mcp": { "args": [ "-y", "tavily-mcp@0.1.4" ], "autoApprove": [], "command": "npx", "disabled": false, "env": { "TAVILY_API_KEY": "your-api-key-here" } } } }
  1. 使用客户端调用,如“用Tavily MCP,查找黄金相关的新闻”。

Qwen-Agent + Tavily集成:

通过调整chatbot_configprompt.suggestions,引导LLM使用Tavily工具进行搜索。

Tavily提供了tavily-search(实时网络搜索)和tavily-extract(网页内容智能提取)两个主要工具。

tavily-search参数:

  • query (必填,字符串):搜索关键词。
  • max_results (可选,整数):返回结果条数。
  • search_depth (可选,枚举basic/advanced):搜索深度。
  • include_domains/exclude_domains (可选,数组):限定或排除域名。
  • time_range (可选,字符串):时间过滤。
  • include_answer (可选,布尔):是否要求直接返回答案。
  • include_raw_content (可选,布尔):是否携带原始HTML。

tavily-extract参数:

  • urls (必填,字符串或数组):要提取的页面地址。
  • extract_depth (可选,枚举basic/advanced):提取深度。
  • format (可选,枚举text/markdown/json):返回格式。
  • include_images (可选,布尔):是否同时提取图片链接。

案例:桌面TXT统计器(MCP SDK使用)

此案例演示如何使用Python MCP SDK(FastMCP)搭建一个本地桌面文件统计器。

MCP SDK功能:

  • pip install mcp
  • 创建MCP Server: 提供标准化API。
  • 注册工具: 通过@mcp.tool()装饰器将Python函数暴露给AI模型。
  • 安全交互: 支持权限控制。
  • 跨平台兼容: 与OpenAI、Anthropic Claude等LLM集成。

FastMCP功能:

  • Python MCP SDK中的轻量级服务器框架。
  • 简单易用,几行代码即可启动。
  • 支持多种传输方式(stdio、HTTP)。
  • 通过@mcp.tool()自动工具发现。

桌面TXT统计器代码示例:

Python
import os from pathlib import Path from mcp.server.fastmcp import FastMCP # 创建MCP Server mcp = FastMCP("桌面TXT 文件统计器") @mcp.tool() def count_desktop_txt_files() -> int: """统计桌面上.txt 文件的数量""" # 获取桌面路径 desktop_path = Path(os.path.expanduser("~/Desktop")) # 统计.txt 文件 txt_files = list(desktop_path.glob("*.txt")) return len(txt_files) @mcp.tool() def list_desktop_txt_files() -> str: """获取桌面上所有.txt 文件的列表""" # 获取桌面路径 desktop_path = Path(os.path.expanduser("~/Desktop")) # 获取所有.txt 文件 txt_files = list(desktop_path.glob("*.txt")) # 返回文件名列表 if not txt_files: return "桌面上没有找到.txt 文件。" # 格式化文件名列表 file_list = "\n".join([f"- {file.name}" for file in txt_files]) return f"在桌面上找到{len(txt_files)} 个.txt 文件:\n{file_list}" if __name__ == "__main__": # 初始化并运行服务器 mcp.run()

运行与测试:

  1. 在终端使用mcp dev txt_counter.py命令启动服务器。

  2. 打开浏览器访问http://localhost:5173/,即可使用MCP Inspector测试工具。

    • 点击Connect。

    • 在Tools中选择count_desktop_txt_fileslist_desktop_txt_files

    • 点击Run Tool查看结果。

    • 在History中可查看请求情况。

MCP Inspector

MCP Inspector是专为MCP Server设计的开源调试工具,用于测试和优化MCP Server功能。

  • 服务器连接管理: 支持本地和远程MCP服务器连接,可配置传输方式(STDIO或HTTP+SSE),方便调试。
  • 服务浏览与调用: 提供可视化界面(默认http://localhost:5173),展示MCP服务器提供的工具、资源、提示等服务。可以直接在UI中调用工具并查看执行记录。

UV工具

在MCP协议中,uv工具常用于启动和管理MCP服务器,例如通过uv命令指定运行的Python脚本来启动MCP服务器。

实践练习

使用Qwen-Agent或其他具有Agent能力的客户端(如Cursor, Cherry Studio),集成MCP服务并通过自然语言调用(例如:规划自驾游、获取网页内容、检索新闻、统计桌面文件数量)。

关键要点

  • Function Calling 扩展LLM与外部系统的交互能力,实现结构化输出和动态决策,适用于简单原子化任务。
  • MCP (Model Context Protocol) 是一个开放协议标准,旨在统一LLM与多数据源、工具和服务的交互,提升跨模型兼容性。
  • Function Calling和MCP各有侧重,Function Calling作为底层能力仍不可或缺,而MCP更关注跨平台和复杂场景的标准化。
  • MCP SDK和FastMCP 简化了自定义MCP Server的开发和工具注册,使得本地功能也能被LLM调用。
  • MCP Inspector 是调试和测试MCP Server的强大可视化工具。

embed