工具调用全景解析从Function Calling到MCP协议的完整实践

🎁个人主页:我滴老baby

🎉欢迎大家点赞👍评论📝收藏⭐文章

🔍系列专栏:AI


文章目录:

  • [工具调用全景解析:从Function Calling到MCP协议,让智能体真正动手干活的完整实践](#工具调用全景解析:从Function Calling到MCP协议,让智能体真正动手干活的完整实践)
    • [一、Tool Use:Agent的核心能力](#一、Tool Use:Agent的核心能力)
    • [二、Function Calling详解](#二、Function Calling详解)
      • [2.1 原理](#2.1 原理)
      • [2.2 完整实现](#2.2 完整实现)
    • 三、并行工具调用
    • 四、自定义工具最佳实践
      • [4.1 工具设计原则](#4.1 工具设计原则)
      • [4.2 工具质量评分表](#4.2 工具质量评分表)
    • 在这里插入图片描述
    • [五、从Function Calling到MCP协议](#五、从Function Calling到MCP协议)
      • [5.1 MCP(Model Context Protocol)简介](#5.1 MCP(Model Context Protocol)简介)
      • [5.2 MCP vs Function Calling](#5.2 MCP vs Function Calling)
      • [5.3 创建MCP工具服务器](#5.3 创建MCP工具服务器)
    • 六、工具安全性深度防护
      • [6.1 常见安全威胁](#6.1 常见安全威胁)
      • [6.2 安全工具包装器](#6.2 安全工具包装器)
    • 总结

工具调用全景解析:从Function Calling到MCP协议,让智能体真正动手干活的完整实践

不会用工具的AI只是个聊天机器人。本文全面解析Agent工具调用的技术演进与实践。


一、Tool Use:Agent的核心能力

AI Agent之所以从"聊天机器人"进化为"智能体",关键在于能够使用工具。Tool Use让Agent从被动回答变为主动执行。

Agent工具使用能力演进

阶段 时间 特点 代表
纯文本生成 2022前 只能生成文本建议 GPT-3
插件系统 2023初 预定义的插件接口 ChatGPT Plugins
Function Calling 2023中 结构化函数调用 GPT-4
多模态工具 2024 图片/音频/视频处理 GPT-4V
MCP协议 2025+ 标准化工具接口 Claude MCP

二、Function Calling详解

2.1 原理

Function Calling的工作流程:

复制代码
1. 开发者定义工具描述(JSON Schema)
2. 将工具描述和用户消息一起发送给LLM
3. LLM判断是否需要调用工具
4. 如果需要,返回工具名和参数(JSON格式)
5. 开发者执行工具,将结果返回给LLM
6. LLM基于工具结果生成最终回答

2.2 完整实现

python 复制代码
# tool_use/function_calling.py
import json
from openai import OpenAI

client = OpenAI(api_key="your-api-key")

# ===== 步骤1:定义工具 =====
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_stock_price",
            "description": "获取指定股票的实时价格信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "symbol": {
                        "type": "string",
                        "description": "股票代码,如 AAPL, TSLA, 600519"
                    },
                    "include_history": {
                        "type": "boolean",
                        "description": "是否包含历史数据",
                        "default": False
                    }
                },
                "required": ["symbol"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "calculate_portfolio",
            "description": "计算投资组合的预期收益率和风险指标",
            "parameters": {
                "type": "object",
                "properties": {
                    "holdings": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "symbol": {"type": "string"},
                                "weight": {"type": "number",
                                          "description": "权重(0-1)"}
                            }
                        },
                        "description": "持仓列表"
                    },
                    "risk_free_rate": {
                        "type": "number",
                        "description": "无风险利率",
                        "default": 0.03
                    }
                },
                "required": ["holdings"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "send_notification",
            "description": "向用户发送通知消息",
            "parameters": {
                "type": "object",
                "properties": {
                    "message": {"type": "string", "description": "通知内容"},
                    "priority": {
                        "type": "string",
                        "enum": ["low", "medium", "high"],
                        "description": "优先级"
                    }
                },
                "required": ["message"]
            }
        }
    }
]

# ===== 步骤2:工具实现 =====
def get_stock_price(symbol: str, include_history: bool = False) -> str:
    # 模拟数据
    stocks = {
        "AAPL": {"price": 198.50, "change": "+2.3%", "volume": "52M"},
        "TSLA": {"price": 245.20, "change": "-1.1%", "volume": "89M"},
        "600519": {"price": 1680.00, "change": "+0.8%", "volume": "12M"},
    }
    data = stocks.get(symbol, {"error": f"未找到股票 {symbol}"})
    return json.dumps(data, ensure_ascii=False)

def calculate_portfolio(holdings: list, risk_free_rate: float = 0.03) -> str:
    # 模拟计算
    expected_return = sum(h["weight"] * 0.12 for h in holdings)
    risk = sum(h["weight"] ** 2 * 0.25 for h in holdings) ** 0.5
    sharpe = (expected_return - risk_free_rate) / risk if risk > 0 else 0
    return json.dumps({
        "expected_return": f"{expected_return*100:.1f}%",
        "volatility": f"{risk*100:.1f}%",
        "sharpe_ratio": round(sharpe, 2)
    }, ensure_ascii=False)

def send_notification(message: str, priority: str = "medium") -> str:
    return json.dumps({
        "status": "sent",
        "message": message,
        "priority": priority,
        "timestamp": "2026-04-26 15:00:00"
    })

tool_map = {
    "get_stock_price": get_stock_price,
    "calculate_portfolio": calculate_portfolio,
    "send_notification": send_notification
}

# ===== 步骤3:Agent主循环 =====
def agent_chat(user_message: str) -> str:
    messages = [
        {"role": "system", "content": "你是一个专业的投资顾问AI助手。"},
        {"role": "user", "content": user_message}
    ]

    # 第一次调用:LLM决定是否需要工具
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,
        tool_choice="auto"
    )

    message = response.choices[0].message

    # 如果不需要工具,直接返回
    if not message.tool_calls:
        return message.content

    # 执行工具调用
    messages.append(message)
    for tool_call in message.tool_calls:
        func_name = tool_call.function.name
        func_args = json.loads(tool_call.function.arguments)

        print(f"🔧 调用: {func_name}({func_args})")
        result = tool_map[func_name](**func_args)
        print(f"📤 结果: {result}")

        messages.append({
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": result
        })

    # 第二次调用:LLM基于工具结果生成回答
    final_response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages
    )
    return final_response.choices[0].message.content

# 运行
print(agent_chat("帮我看看苹果和特斯拉的股价,然后分析如果我50%持有苹果、50%特斯拉的组合表现如何"))

三、并行工具调用

python 复制代码
# tool_use/parallel_calls.py

def agent_chat_parallel(user_message: str) -> str:
    """支持并行工具调用的Agent"""

    messages = [
        {"role": "system", "content": "你是投资顾问AI。"},
        {"role": "user", "content": user_message}
    ]

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,
        tool_choice="auto",
        parallel_tool_calls=True  # 启用并行调用
    )

    message = response.choices[0].message

    if message.tool_calls:
        messages.append(message)
        # 并行执行所有工具调用
        import concurrent.futures

        def execute_tool(tc):
            func_name = tc.function.name
            func_args = json.loads(tc.function.arguments)
            result = tool_map[func_name](**func_args)
            return {
                "tool_call_id": tc.id,
                "result": result,
                "func_name": func_name
            }

        with concurrent.futures.ThreadPoolExecutor() as executor:
            futures = [executor.submit(execute_tool, tc)
                      for tc in message.tool_calls]
            for future in concurrent.futures.as_completed(futures):
                tool_result = future.result()
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_result["tool_call_id"],
                    "content": tool_result["result"]
                })

    final_response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages
    )
    return final_response.choices[0].message.content

四、自定义工具最佳实践

4.1 工具设计原则

原则 说明 示例
单一职责 每个工具只做一件事 search_web 而非 search_and_summarize
描述精确 让LLM准确理解工具用途 详细的description和参数说明
错误友好 返回有用的错误信息 "未找到股票AAPL"而非"Error"
幂等性 相同输入返回相同结果 GET请求应可重复调用
安全边界 限制危险操作 数据库工具禁止DROP操作

4.2 工具质量评分表

python 复制代码
# tool_use/tool_quality.py

class ToolQualityChecker:
    """评估工具定义的质量"""

    @staticmethod
    def check(tool_definition: dict) -> dict:
        issues = []
        score = 100

        func = tool_definition["function"]

        # 检查描述
        desc = func.get("description", "")
        if len(desc) < 20:
            issues.append("描述太短,LLM可能无法准确理解")
            score -= 20
        if len(desc) > 300:
            issues.append("描述过长,可能影响token效率")
            score -= 10

        # 检查参数
        params = func.get("parameters", {}).get("properties", {})
        for pname, pdef in params.items():
            if "description" not in pdef:
                issues.append(f"参数 '{pname}' 缺少描述")
                score -= 15

        # 检查必要性
        if not func.get("parameters", {}).get("required"):
            issues.append("未定义required参数列表")
            score -= 10

        return {
            "score": max(0, score),
            "issues": issues,
            "quality": "优秀" if score >= 80 else "良好" if score >= 60 else "需改进"
        }

五、从Function Calling到MCP协议

5.1 MCP(Model Context Protocol)简介

MCP是Anthropic提出的开放标准协议,旨在统一AI模型与外部工具/数据源的交互方式。

5.2 MCP vs Function Calling

特性 Function Calling MCP
标准化 各厂商自定义 开放标准协议
工具发现 手动定义 自动发现
跨模型 不通用 统一接口
安全性 依赖开发者 内置权限模型
生态 封闭 开源社区

5.3 创建MCP工具服务器

python 复制代码
# tool_use/mcp_server.py
from mcp.server import Server
from mcp.types import Tool, TextContent

app = Server("financial-tools")

@app.list_tools()
async def list_tools():
    return [
        Tool(
            name="get_stock_price",
            description="获取股票实时价格",
            inputSchema={
                "type": "object",
                "properties": {
                    "symbol": {"type": "string", "description": "股票代码"}
                },
                "required": ["symbol"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name, arguments):
    if name == "get_stock_price":
        symbol = arguments["symbol"]
        price_data = get_stock_price(symbol)
        return [TextContent(type="text", text=price_data)]

# 启动服务器
if __name__ == "__main__":
    import asyncio
    asyncio.run(app.run())

六、工具安全性深度防护

6.1 常见安全威胁

威胁 攻击方式 防御措施
Prompt注入 在用户输入中嵌入恶意指令 输入验证、角色分离
工具滥用 诱导Agent调用危险工具 权限分级、确认机制
数据泄露 通过工具调用泄露敏感信息 输出过滤、访问控制
拒绝服务 大量无意义工具调用 频率限制、预算控制

6.2 安全工具包装器

python 复制代码
# tool_use/secure_tool.py

class SecureToolWrapper:
    """安全工具包装器"""

    def __init__(self, tool_func, max_calls=10, timeout=30):
        self.tool_func = tool_func
        self.max_calls = max_calls
        self.timeout = timeout
        self.call_count = 0

    def __call__(self, **kwargs):
        # 频率检查
        if self.call_count >= self.max_calls:
            raise PermissionError(f"工具调用次数超过限制({self.max_calls})")

        # 输入验证
        for key, value in kwargs.items():
            if isinstance(value, str) and len(value) > 10000:
                raise ValueError(f"参数 {key} 过长")

        self.call_count += 1
        return self.tool_func(**kwargs)

总结

Tool Use是Agent从"聊天"到"执行"的关键跨越:

  1. Function Calling是目前最成熟的工具调用方式
  2. 并行调用可以显著提升多工具场景的效率
  3. MCP协议代表着工具调用的未来方向------标准化和互操作
  4. 安全性 不容忽视------任何工具都应该有防护措施

相关推荐
小李子呢02112 小时前
前端八股JS---Map / Set / WeakMap / WeakSet
开发语言·前端·javascript
小白学大数据2 小时前
抖音搜索页数据批量爬取,多关键词同步采集实现
爬虫·python·数据分析
人工智能AI技术2 小时前
一文讲透程序员转大模型,学习路线+就业方向
人工智能
zhangfeng11332 小时前
宝塔服务器完全可以安装 Git,进行版本管理,而且非常简单
运维·服务器·人工智能·git·编程
rainbow7242442 小时前
周末提升避坑指南:这些低成本方式2026年真不踩雷
人工智能
feifeigo1232 小时前
自适应大邻域搜索(ALNS)算法的MATLAB 实现
开发语言·算法·matlab
Vertira3 小时前
opencv 和opencv_contrib官网 不同版本的下载地址
人工智能·opencv·计算机视觉
2301_787312433 小时前
Vue.js中Patch过程处理Teleport组件挂载位置的特殊逻辑
jvm·数据库·python
繁星蓝雨3 小时前
Qt多界面创建的优化问题(main函数或主界面中创建?)—————附带详细方法
c++·qt·架构·多界面管理