Function Calling vs MCP:AI工具生态的架构演进与选型指南2026
·
Function Calling是LLM调用工具的基础能力,MCP是工具生态标准化的新尝试。两者不是竞争关系,而是不同层次的解决方案。本文深度解析二者的本质区别、适用场景与架构选型。
一、Function Calling的本质Function Calling(也称Tool Use)是2023年OpenAI引入的能力,本质上是:让LLM输出结构化的"调用指令",再由外部程序执行。用户: "帮我查下明天北京的天气" ↓LLM判断需要调用工具,输出:{ "tool": "get_weather", "parameters": { "city": "北京", "date": "2026-05-12" }} ↓应用层执行工具调用 → 获取真实天气数据 ↓将结果传回LLM → LLM生成最终回复关键理解:LLM本身不执行任何代码,它只是"宣布打算调用什么",真正的执行权在应用层。### 1.1 Function Calling的实现pythonfrom openai import OpenAIimport jsonclient = OpenAI()# 定义工具tools = [ { "type": "function", "function": { "name": "get_weather", "description": "获取指定城市和日期的天气信息", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,如:北京、上海" }, "date": { "type": "string", "description": "日期,格式:YYYY-MM-DD" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位" } }, "required": ["city", "date"] } } }, { "type": "function", "function": { "name": "send_notification", "description": "发送通知消息", "parameters": { "type": "object", "properties": { "recipient": {"type": "string"}, "message": {"type": "string"}, "channel": { "type": "string", "enum": ["email", "slack", "sms"] } }, "required": ["recipient", "message", "channel"] } } }]def run_tool(tool_name: str, tool_args: dict) -> str: """工具执行层""" if tool_name == "get_weather": # 实际调用天气API return json.dumps({ "city": tool_args["city"], "date": tool_args["date"], "temperature": 22, "condition": "晴天", "humidity": 45 }, ensure_ascii=False) elif tool_name == "send_notification": # 实际发送通知 return json.dumps({"status": "sent", "message_id": "msg_12345"}) return json.dumps({"error": "Unknown tool"})def agent_loop(user_message: str) -> str: """基础Agent循环""" messages = [{"role": "user", "content": user_message}] while True: response = client.chat.completions.create( model="gpt-4o", messages=messages, tools=tools, tool_choice="auto" ) message = response.choices[0].message messages.append(message.model_dump()) # 没有工具调用,直接返回 if not message.tool_calls: return message.content # 执行所有工具调用 for tool_call in message.tool_calls: tool_name = tool_call.function.name tool_args = json.loads(tool_call.function.arguments) print(f"[调用工具] {tool_name}({tool_args})") result = run_tool(tool_name, tool_args) messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": result })## 二、MCP(Model Context Protocol)的本质MCP是Anthropic在2024年底提出并开源的协议,解决的是一个不同层次的问题:工具生态的标准化与互操作性。### 2.1 MCP解决了什么Function Calling的痛点:- 每个应用都要自己实现工具层(天气API、数据库、文件系统…)- 工具实现无法复用——A公司写的GitHub工具,B公司无法直接用- 工具与应用强耦合,迁移成本高MCP的解决思路:定义一套标准协议,让工具服务器(MCP Server)与AI应用(MCP Client)解耦。传统架构:AI应用 ────────────── 直接调用 ──────────── 各种API/工具MCP架构:AI应用(MCP Client) ↕ 标准MCP协议MCP Server(工具实现) ↕ 实际服务(GitHub/DB/FileSystem...)### 2.2 MCP核心概念三种原语:1. Tools(工具):可执行的函数,等同于Function Calling2. Resources(资源):可读取的数据源(文件、数据库记录、API响应)3. Prompts(提示模板):预定义的提示词模板,可参数化两种传输方式:1. stdio:本地进程间通信(适合本地工具)2. SSE/HTTP:网络通信(适合远程服务)### 2.3 构建一个MCP Serverpython# 使用官方Python MCP SDKfrom mcp.server.fastmcp import FastMCPfrom mcp.types import TextContent# 创建MCP服务器mcp = FastMCP("company-tools")@mcp.tool()async def search_employee_database( name: str = None, department: str = None, employee_id: str = None) -> str: """搜索员工数据库 Args: name: 员工姓名(支持模糊搜索) department: 部门名称 employee_id: 员工工号 Returns: 符合条件的员工信息JSON字符串 """ results = db.query( "SELECT * FROM employees WHERE " "(:name IS NULL OR name LIKE :name) AND " "(:dept IS NULL OR department = :dept) AND " "(:eid IS NULL OR employee_id = :eid)", name=f"%{name}%" if name else None, dept=department, eid=employee_id ) return json.dumps(results, ensure_ascii=False)@mcp.resource("file://{path}")async def read_document(path: str) -> str: """读取公司内部文档""" # 安全检查:只允许读取指定目录 allowed_base = "/company/docs" full_path = os.path.normpath(os.path.join(allowed_base, path)) if not full_path.startswith(allowed_base): raise PermissionError("Access denied: path traversal detected") with open(full_path, 'r', encoding='utf-8') as f: return f.read()@mcp.prompt()def hr_query_prompt(employee_name: str, query_type: str) -> str: """HR查询提示模板""" return f"""你是一个HR助手。用户想要查询员工「{employee_name}」的{query_type}信息。请使用search_employee_database工具获取信息,并以友好的方式回复。注意遵守数据隐私规定,不要泄露薪资等敏感信息(除非明确授权)。"""# 启动服务器if __name__ == "__main__": mcp.run(transport="stdio") # 本地进程模式 # 或: mcp.run(transport="sse", port=8080) # HTTP SSE模式### 2.4 在Claude应用中使用MCPpythonimport anthropicimport asynciofrom mcp import ClientSession, StdioServerParametersfrom mcp.client.stdio import stdio_clientasync def chat_with_mcp_tools(user_message: str): # 连接到MCP Server server_params = StdioServerParameters( command="python", args=["company_mcp_server.py"], env={"DATABASE_URL": "postgresql://..."} ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: # 初始化 await session.initialize() # 获取可用工具列表 tools_result = await session.list_tools() # 转换为Anthropic工具格式 claude_tools = [] for tool in tools_result.tools: claude_tools.append({ "name": tool.name, "description": tool.description, "input_schema": tool.inputSchema }) client = anthropic.Anthropic() messages = [{"role": "user", "content": user_message}] while True: response = client.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=4096, tools=claude_tools, messages=messages ) if response.stop_reason == "end_turn": # 提取文本响应 return next( b.text for b in response.content if b.type == "text" ) # 执行工具调用 messages.append({"role": "assistant", "content": response.content}) tool_results = [] for block in response.content: if block.type == "tool_use": # 通过MCP协议调用工具 result = await session.call_tool( block.name, arguments=block.input ) tool_results.append({ "type": "tool_result", "tool_use_id": block.id, "content": result.content[0].text }) messages.append({"role": "user", "content": tool_results})## 三、核心区别对比| 维度 | Function Calling | MCP ||------|-----------------|-----|| 本质 | LLM能力(输出结构化工具调用) | 工具互操作协议 || 层次 | 模型层 | 应用架构层 || 工具实现 | 与应用代码耦合 | 独立Server,可复用 || 跨应用复用 | ❌ 需要重复实现 | ✅ MCP Server开箱即用 || 跨模型支持 | 各厂商API不同 | ✅ 统一协议 || 部署复杂度 | 低(直接在应用内) | 中(需要运行Server进程) || 安全控制 | 应用层自己管 | Server端统一权限管理 || 适合场景 | 简单工具、快速开发 | 工具多、需复用、多应用共享 |## 四、架构选型指南### 4.1 何时用纯Function Calling✅ 适合场景:- 工具数量少(<10个)- 工具与业务逻辑紧密耦合- 快速原型,不考虑复用- 工具只在单一应用中使用- 对延迟极度敏感(MCP有进程间通信开销)典型例子:- 客服机器人(只调用自己公司的CRM、工单系统)- 个人助手应用(调用用户日历、Todo、邮件)- 专项工具(代码分析工具,工具固定)### 4.2 何时引入MCP✅ 适合场景:- 工具需要被多个AI应用复用- 工具需要独立部署和版本管理- 企业希望建立工具中台- 工具由不同团队维护- 需要对外开放工具给合作伙伴典型例子:- 企业AI平台(多个业务线共用同一套工具)- AI IDE插件(Cursor等复用社区MCP Server)- 开放工具生态(开发者发布自己的MCP Server供他人使用)### 4.3 混合架构pythonclass HybridToolSystem: """混合工具架构:简单工具直接调用,复杂工具走MCP""" DIRECT_TOOLS = { "get_current_time": lambda: datetime.now().isoformat(), "calculate": lambda expr: str(eval(expr)), # 简单计算 } MCP_SERVERS = { "github": {"command": "npx", "args": ["@modelcontextprotocol/server-github"]}, "postgres": {"command": "npx", "args": ["@modelcontextprotocol/server-postgres"]}, "company-tools": {"command": "python", "args": ["company_mcp_server.py"]}, } async def execute_tool(self, tool_name: str, tool_args: dict) -> str: # 直接工具:本地执行,零延迟 if tool_name in self.DIRECT_TOOLS: return str(self.DIRECT_TOOLS[tool_name](**tool_args)) # MCP工具:通过协议调用 server_name = self._find_mcp_server(tool_name) if server_name: return await self._call_mcp_tool(server_name, tool_name, tool_args) raise ValueError(f"Unknown tool: {tool_name}") def _find_mcp_server(self, tool_name: str) -> Optional[str]: """根据工具名找到对应的MCP Server""" # 可以通过工具名前缀、注册表等方式路由 tool_server_map = { "github_": "github", "db_": "postgres", "hr_": "company-tools", } for prefix, server in tool_server_map.items(): if tool_name.startswith(prefix): return server return None## 五、MCP生态现状(2026)### 5.1 主流MCP Server官方维护的服务器:- @modelcontextprotocol/server-github — GitHub操作- @modelcontextprotocol/server-postgres — PostgreSQL查询- @modelcontextprotocol/server-filesystem — 文件系统访问- @modelcontextprotocol/server-brave-search — Brave搜索社区热门服务器:- Playwright MCP — 浏览器自动化- Qdrant MCP — 向量数据库操作- Notion MCP — Notion内容管理支持MCP的客户端(2026):Claude Desktop、Cursor、Zed、VS Code(通过扩展)、Continue### 5.2 MCP的局限性当前已知问题:1. 安全模型尚不完善(恶意MCP Server可能读取敏感数据)2. 工具发现机制依赖预配置(无动态发现)3. 跨Server的工具组合没有标准4. 版本管理和向后兼容性尚需完善5. 生产稳定性仍在验证中## 六、总结Function Calling和MCP解决的是不同层次的问题:- Function Calling = 如何让LLM调用工具(能力层)- MCP = 如何让工具生态标准化和可复用(协议层)两者是互补关系,不是替代关系。成熟的AI应用架构通常是:用MCP组织工具,用Function Calling触发执行。对于2026年的AI工程师,建议:1. 掌握Function Calling基础,这是所有AI工具调用的根基2. 关注MCP生态,企业级工具复用场景下MCP是未来方向3. 不要为了用MCP而用MCP,简单场景直接实现即可4. 重点关注安全性,无论哪种方案都需要严格的权限控制
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)