AI Agent工具调用机制深度解析:从Function Calling到MCP协议
前言
AI Agent(智能体)正在改变我们与AI交互的方式。工具调用(Tool Calling)是AI Agent的核心能力,让大语言模型能够与外部世界交互。本文将深入解析AI Agent工具调用机制,从基础的Function Calling到最新的MCP协议。
1. 工具调用基础
1.1 什么是工具调用?
工具调用是指大语言模型(LLM)能够:
- 理解用户请求需要调用外部工具
- 生成正确的工具调用参数
- 处理工具返回的结果
用户请求 → LLM理解 → 工具调用 → 结果处理 → 响应生成1.2 Function Calling基础
OpenAI的Function Calling是最早的标准化工具调用方式:
# OpenAI Function Calling示例importopenaiimportjson# 定义工具tools=[{"type":"function","function":{"name":"get_weather","description":"获取指定城市的天气信息","parameters":{"type":"object","properties":{"city":{"type":"string","description":"城市名称"}},"required":["city"]}}}]# 调用示例response=openai.chat.completions.create(model="gpt-4",messages=[{"role":"user","content":"北京今天天气怎么样?"}],tools=tools,tool_choice="auto")# 解析响应ifresponse.choices[0].message.tool_calls:tool_call=response.choices[0].message.tool_calls[0]function_name=tool_call.function.name arguments=json.loads(tool_call.function.arguments)print(f"调用工具:{function_name}")print(f"参数:{arguments}")2. LangChain Agent架构
2.1 Agent核心组件
LangChain是最流行的AI Agent开发框架,其核心组件包括:
LangChain Agent架构 ├── 模型层 (LLM) │ ├── OpenAI GPT系列 │ ├── Anthropic Claude │ └── 本地模型 (Ollama) ├── 工具层 (Tools) │ ├── 内置工具 (搜索、计算) │ ├── 自定义工具 │ └── 工具包 (Toolkits) ├── 记忆层 (Memory) │ ├── 短期记忆 (对话历史) │ ├── 长期记忆 (向量数据库) │ └── 工作记忆 (当前任务状态) └── 执行层 (Executor) ├── ReAct推理引擎 ├── Plan-and-Execute引擎 └── 自适应引擎2.2 工具定义最佳实践
错误做法:工具描述不清晰
# ❌ 错误:工具描述过于简单@tooldefsearch_database(query:str)->str:"""搜索数据库"""# 实现pass正确做法:详细的工具描述
# ✅ 正确:详细的工具描述fromlangchain.toolsimporttoolfromtypingimportOptional@tooldefsearch_database(query:str,table:str="users",limit:int=10,filters:Optional[dict]=None)->str:"""在数据库中搜索信息。 这个工具用于在指定的数据库表中搜索符合条件的数据。 支持模糊搜索和精确匹配。 Args: query: 搜索关键词,支持多个关键词用空格分隔 table: 要搜索的表名,可选值:users, products, orders limit: 返回结果的最大数量,默认10条 filters: 可选的过滤条件,格式为 {"字段名": "值"} Returns: JSON格式的搜索结果,包含匹配的记录和总数 Examples: >>> search_database("John", table="users", limit=5) '{"results": [...], "total": 42}' >>> search_database("laptop", filters={"price": {"$gt": 1000}}) '{"results": [...], "total": 15}' """# 实现搜索逻辑results=perform_search(query,table,limit,filters)returnjson.dumps(results,ensure_ascii=False)2.3 工具调用链
复杂任务通常需要多个工具协同工作:
# 工具调用链示例fromlangchain.agentsimportAgentExecutor,create_react_agentfromlangchain.promptsimportPromptTemplate# 定义多个工具tools=[search_database,calculate_statistics,generate_report,send_email,]# 创建Agentprompt=PromptTemplate.from_template(""" Answer the following questions as best you can. You have access to the following tools: {tools} Use the following format: Question: the input question you must answer Thought: you should always think about what to do Action: the action to take, should be one of [{tool_names}] Action Input: the input to the action Observation: the result of the action ... (this Thought/Action/Action Input/Observation can repeat N times) Thought: I now know the final answer Final Answer: the final answer to the original input question Begin! Question: {input} Thought:{agent_scratchpad} """)agent=create_react_agent(llm,tools,prompt)agent_executor=AgentExecutor(agent=agent,tools=tools,verbose=True)# 执行复杂任务result=agent_executor.invoke({"input":"找出过去30天销售额超过10万的客户,计算他们的平均消费额,并生成报告发送给销售经理"})3. MCP协议深度解析
3.1 MCP协议概述
Model Context Protocol (MCP) 是Anthropic推出的开放标准,旨在统一AI模型与外部工具的交互方式:
MCP协议架构 ├── 客户端 (Client) │ ├── AI模型 (Claude, GPT等) │ ├── MCP客户端库 │ └── 传输层 (stdio, HTTP) ├── 服务器 (Server) │ ├── 工具提供者 │ ├── 资源提供者 │ └── 提示词模板 └── 协议层 (Protocol) ├── 工具调用 (Tools) ├── 资源访问 (Resources) ├── 提示词 (Prompts) └── 采样 (Sampling)3.2 MCP服务器实现
# MCP服务器示例importasynciofrommcpimportServer,Toolfrommcp.typesimportTextContent# 创建服务器server=Server("my-mcp-server")# 定义工具@server.tool()asyncdefget_weather(city:str)->str:"""获取指定城市的天气信息"""# 模拟天气API调用weather_data={"北京":{"temp":25,"condition":"晴"},"上海":{"temp":28,"condition":"多云"},}ifcityinweather_data:data=weather_data[city]returnTextContent(type="text",text=f"{city}天气:温度{data['temp']}°C,{data['condition']}")else:returnTextContent(type="text",text=f"未找到{city}的天气信息")@server.tool()asyncdefcalculate(expression:str)->str:"""计算数学表达式"""try:# 安全计算(限制可用函数)allowed_names={