AI Agent:从工具调用到自主任务执行(实战篇)
导读:理论再完美,代码跑不通也是白搭。本文是《AI 智能体全景指南》的实战续篇。我们将抛弃繁琐的理论,直接上手,用 Python + LangChain 1.0 + MCP 构建一个能自主规划、多工具协作的“旅行规划助手”。
你将学到:
如何手写一个标准的 MCP Server(让 AI 拥有新技能)。 如何使用 LangChain 1.0 最新语法构建 Agent。 如何实现 ReAct 模式,让 AI 自动拆解任务、循环调用工具。 完整可运行代码,复制粘贴即可体验。
🎯 实战目标:打造“智能旅行规划师”
场景描述: 用户只需输入:“我想去北京玩 3 天,预算 5000 元,帮我查下天气、推荐景点并计算总花费。”
Agent 需要自主完成:
-
思考:识别出需要“查天气”、“搜景点”、“算账”三个步骤。 -
行动: -
调用 get_weather(MCP 工具) 查询北京天气。 -
调用 search_attractions(MCP 工具) 获取景点列表。 -
调用 calculate_budget(本地函数) 计算花费。 -
反思:如果天气不好,自动调整推荐(如推荐室内景点)。 -
交付:输出一份完整的行程单。
🛠️ 环境准备
确保你的 Python 版本为 3.10+,并安装以下核心库(基于 2026 年最新生态):
pip install langchain langchain-openai mcp uvicorn fastmcp
注意:
langchain: 核心编排框架(使用 1.0+ 新版语法)。mcp&fastmcp: 用于快速构建 MCP 服务器。uvicorn: 用于运行 MCP 服务(如果使用 SSE 模式)。
你需要一个 OpenAI API Key (或兼容的 LLM Key),并在终端导出:
export OPENAI_API_KEY="sk-..."
第一步:构建 MCP Server(制造工具)
在旧模式下,我们需要为每个工具写适配代码。现在,我们利用 MCP 协议,将工具标准化。我们将创建一个包含“天气查询”和“景点搜索”的 MCP 服务。
新建文件 travel_mcp_server.py:
# travel_mcp_server.pyfrom mcp.server.fastmcp import FastMCPimport random# 初始化 MCP 服务器mcp = FastMCP("TravelAssistantServer")@mcp.tool()def get_weather(city: str) -> str:"""查询指定城市的天气情况。Args:city: 城市名称,例如 '北京', '上海'Returns:天气描述字符串"""# 模拟真实 API 调用weathers = ["晴朗", "多云", "小雨", "大雨", "雪"]temp = random.randint(10, 30)status = random.choice(weathers)return f"{city}今天天气{status},气温{temp}摄氏度。"@mcp.tool()def search_attractions(city: str, preference: str = "自然风光") -> list:"""搜索指定城市的旅游景点。Args:city: 城市名称preference: 偏好类型,如 '自然风光', '历史人文', '室内娱乐'Returns:景点列表"""# 模拟数据库查询逻辑db = {"北京": {"自然风光": ["颐和园", "香山公园"],"历史人文": ["故宫", "长城", "天坛"],"室内娱乐": ["国家博物馆", "环球影城"]},"上海": {"自然风光": ["外滩", "世纪公园"],"历史人文": ["豫园", "中共一大会址"],"室内娱乐": ["上海迪士尼", "海洋水族馆"]}}# 简单的容错处理if city not in db:return ["未知城市,无法推荐具体景点,建议查询通用攻略。"]# 如果偏好不匹配,默认返回第一项attractions = db[city].get(preference, list(db[city].values())[0])return attractionsif __name__ == "__main__":# 启动 MCP 服务器 (使用 stdio 模式,适合本地调试)# 生产环境通常使用 SSE (http) 模式mcp.run()
💡 代码解析:
-
使用 @mcp.tool()装饰器,普通 Python 函数瞬间变成符合 MCP 协议 的标准工具。 -
函数文档字符串(Docstring)会被自动提取,作为 LLM 理解工具用法的 Schema。 -
无需关心 HTTP 请求细节,MCP 库会自动处理序列化。
第二步:构建 Agent 客户端(组装大脑)
现在,我们要创建一个 Agent,它能连接到刚才写的 MCP 服务器,并自主使用这些工具。我们将使用 LangChain 1.0 的 create_agent 和 ToolNode 模式。
新建文件 agent_runner.py:
# agent_runner.pyimport asynciofrom langchain_openai import ChatOpenAIfrom langchain.agents import create_tool_calling_agent, AgentExecutorfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_mcp import MCPToolkit # 假设 langchain-mcp 集成包已可用,或使用标准加载方式from mcp.client.stdio import stdio_clientfrom langchain.tools import Tool# --- 1. 连接 MCP Server 并加载工具 ---async def load_mcp_tools():"""连接到本地运行的 MCP Server 并转换为 LangChain Tools"""tools = []# 这里模拟通过 stdio 连接到我们刚才写的 server# 在实际生产中,你可能需要配置具体的 command 和 argsfrom mcp.client.stdio import StdioServerParametersserver_params = StdioServerParameters(command="python",args=["travel_mcp_server.py"])async with stdio_client(server_params) as (read, write):from mcp.client.session import ClientSessionasync with ClientSession(read, write) as session:await session.initialize()# 获取工具列表response = await session.list_tools()langchain_tools = []for tool_def in response.tools:# 将 MCP 工具定义转换为 LangChain 可调用的对象# 这里为了演示简化了转换逻辑,实际需封装调用 session.call_toolasync def make_func(t_name, t_desc):async def func(**kwargs):async with stdio_client(server_params) as (r, w):async with ClientSession(r, w) as s:await s.initialize()result = await s.call_tool(t_name, kwargs)return str(result.content)return functool = Tool(name=tool_def.name,description=tool_def.description,coroutine=make_func(tool_def.name, tool_def.description))langchain_tools.append(tool)return langchain_tools# --- 2. 定义 Agent 核心逻辑 ---async def run_agent():# 加载工具print("🔌 正在连接 MCP 服务器加载工具...")tools = await load_mcp_tools()print(f"✅ 成功加载 {len(tools)} 个工具: {[t.name for t in tools]}")# 初始化 LLM (大脑)llm = ChatOpenAI(model="gpt-4o", temperature=0)# 定义 Prompt (赋予角色)prompt = ChatPromptTemplate.from_messages([("system", "你是一个专业的旅行规划助手。你需要根据用户的需求,自主调用工具查询天气和景点,并给出合理的建议。如果天气不好,请优先推荐室内活动。"),("human", "{input}"),("placeholder", "{agent_scratchpad}") # 用于存放思考过程])# 构建 Agent (ReAct 模式)# LangChain 1.0 推荐使用 create_tool_calling_agentagent = create_tool_calling_agent(llm, tools, prompt)# 创建执行器 (Executor)agent_executor = AgentExecutor(agent=agent,tools=tools,verbose=True, # 开启详细日志,观察思考过程handle_parsing_errors=True)# --- 3. 执行任务 ---user_query = "我想去北京玩,帮我查下天气,如果下雨就推荐室内景点,否则推荐自然风光,并简单估算一下门票花费(假设每个景点 50 元)。"print(f"\n👤 用户指令:{user_query}\n")print("🤖 Agent 开始思考与执行...\n")response = await agent_executor.ainvoke({"input": user_query})print("\n" + "="*50)print("📝 最终回复:")print(response["output"])print("="*50)if __name__ == "__main__":asyncio.run(run_agent())
⚠️ 注意: 上面的
load_mcp_tools函数展示了最核心的连接逻辑。在 2026 年的成熟生态中,langchain-mcp包通常会提供类似MCPToolkit.from_server(...)的一行代码加载方式。上述代码为了展示原理,手动实现了连接过程,确保你在任何环境下都能理解底层发生了什么。
🚀 运行效果演示
在终端运行:
python agent_runner.py
你将看到类似以下的输出(verbose 模式):
🔌 正在连接 MCP 服务器加载工具...✅ 成功加载 2 个工具: ['get_weather', 'search_attractions']👤 用户指令:我想去北京玩,帮我查下天气,如果下雨就推荐室内景点,否则推荐自然风光,并简单估算一下门票花费(假设每个景点 50 元)。🤖 Agent 开始思考与执行...--- [Thought Step 1] ---Agent 思考: 用户想去北京。我需要先查天气,根据天气决定推荐什么类型的景点。Action: get_weatherAction Input: {"city": "北京"}--- [Observation] ---Tool Output: 北京今天天气小雨,气温 18 摄氏度。--- [Thought Step 2] ---Agent 思考: 天气是"小雨",根据指令,我应该推荐"室内娱乐"类的景点。Action: search_attractionsAction Input: {"city": "北京", "preference": "室内娱乐"}--- [Observation] ---Tool Output: ["国家博物馆", "环球影城"]--- [Thought Step 3] ---Agent 思考: 找到了两个室内景点。用户要求估算花费,假设每个 50 元。总共 2 个景点,花费 = 2 * 50 = 100 元。现在可以生成最终回答了。Final Answer:您好!为您查询到北京今天有**小雨**,气温 18℃。考虑到天气因素,我为您推荐以下**室内景点**:1. **国家博物馆**2. **环球影城**💰 **预算估算**:按每个景点门票约 50 元计算,两个景点总计约 **100 元**。祝您在北京旅途愉快,记得带伞哦!☔️==================================================📝 最终回复:您好!为您查询到北京今天有**小雨**,气温 18℃... (同上)==================================================
💡 核心原理解析
这个简单的 Demo 展示了 Agent 自主性 的三个关键点:
-
感知与规划 (Perception & Planning):
-
Agent 没有硬编码“先查天气再查景点”的逻辑。 -
它是通过 LLM 的推理能力,自己意识到“不知道天气就没法决定推荐什么”,从而自主决定第一步调用 get_weather。 -
动态分支 (Dynamic Branching):
-
当观察到天气是“小雨”时,Agent 自动调整了下一步策略,将 preference参数设为“室内娱乐”。 -
如果是“晴朗”,它会自动改为“自然风光”。这就是 ReAct (Reasoning + Acting) 模式的威力。 -
标准化连接 (MCP):
-
travel_mcp_server.py和agent_runner.py是完全解耦的。 -
如果你想增加一个“查酒店”的功能,只需在 Server 端加一个 @mcp.tool()函数,客户端代码完全不用改,Agent 会自动发现新工具并学会使用它。
🌟 进阶:如何扩展到生产级?
这个 Demo 只是起点。在 2026 年的生产环境中,你还需要考虑:
-
记忆模块 (Memory): -
引入 ConversationBufferMemory或向量数据库,让 Agent 记住用户之前的偏好(如“我不喜欢爬山”)。 -
多 Agent 协作 (Multi-Agent): -
使用 LangGraph 编排多个 Agent。例如:一个“搜索 Agent”负责查资料,一个“财务 Agent”负责算账,一个“写作 Agent”负责生成报告。 -
人类反馈 (Human-in-the-loop): -
在执行敏感操作(如“支付退款”)前,暂停执行,请求人类确认。 -
部署 MCP Server: -
将 MCP Server 部署为 SSE (Server-Sent Events) 模式,挂在 Docker 容器中,供多个 Agent 实例远程调用。
📝 总结
通过这篇实战,我们完成了从 0 到 1 的突破:
-
✅ 理解了 MCP 如何让工具开发变得像写普通函数一样简单。 -
✅ 掌握了 LangChain 构建自主 Agent 的核心流程。 -
✅ 见证了 AI 从“被动问答”到“主动规划”的质变。
夜雨聆风