上篇:LangChain Agent 智能体从入门到实战(一)—— 概念、工具定义与 MCP 协议
从“固定流程”到“自主决策”,让 LLM 自己决定下一步做什么。
在前面的课程中,我们学会了用 Chain(链)来编排固定的 LLM 调用流程。但现实世界的问题往往是开放的、动态的——你无法预先知道用户会问什么,也无法提前写好所有分支逻辑。
Agent(智能代理)应运而生。它把 LLM 当作“大脑”,让模型自己决定调用哪些工具、按什么顺序执行,直到完成任务。本文将带你理解 Agent 的核心思想,学会用@tool定义工具,并通过 MCP 协议接入外部服务,最终构建出第一个可用的 Agent。
一、Agent 是什么?为什么需要它?
1.1 从 Chain 到 Agent
Chain 的工作方式是预先定义好一条固定的处理流程,输入数据按顺序流经每一步,最终得到输出。这适合翻译、摘要等确定性任务。
但有些任务无法预知路径。比如:
“帮我查查北京明天会不会下雨,如果下雨,帮我取消明天的户外预约。”
要完成这个任务,程序需要:
先查天气 API;
根据结果(下雨/不下雨)判断;
如果下雨,再调用日程 API 取消预约;如果不下雨,直接回复。
步骤 2 和 3 在编写代码时无法确定。你不能硬编码成一条 Chain,因为每次用户输入不同,路径也不同。
Agent 的核心思想:把 LLM 当作大脑,让它自己决定下一步做什么。
Chain:开发者编排流程,LLM 负责执行 → “你告诉它怎么做”
Agent:LLM 自主编排流程,工具负责执行 → “你告诉它要做什么,它自己想怎么做”
1.2 核心组件与工作机制
Agent 有四大核心组件,但并非每个都必须具备。最简单的 Agent 只需要LLM + Tools即可工作。
| 组件 | 角色 | 说明 |
|---|---|---|
| ① LLM(大脑) | 理解意图,做出每一步决策 | 中枢驱动 |
| ② Tools(工具) | 执行 LLM 的决策,与外部世界交互 | LLM“想”,工具“做” |
| ③ Memory(记忆) | 存储上下文,让 Agent“记住”对话历史 | 为决策提供历史信息 |
| ④ Planning(规划) | 分解复杂任务为可执行步骤 | 隐含在推理过程和提示词中 |
工作机制:Agent 通过“感知 → 推理 → 行动”的循环来逐步完成任务。每轮循环,LLM 都会判断“任务完成了吗?”,如果没完成就继续调用工具、观察结果、再推理,直到给出最终答案。
以“查天气并取消预约”为例:
第 1 轮:LLM 推理 → 需要查天气 → 调用
get_weather→ 返回“小雨”第 2 轮:LLM 推理 → 明天下雨,需要取消预约 → 调用
cancel_appointment→ 返回“已取消”第 3 轮:LLM 推理 → 任务完成 → 直接回复用户
整个过程中,没有任何代码预先规定“先查天气再取消预约”。执行路径是 LLM 动态决定的。
1.3 什么时候用 Agent?
| 对比维度 | Chain | Agent |
|---|---|---|
| 谁决定流程 | 开发者在代码中预定义 | LLM 在运行时自主决定 |
| 执行路径 | 线性的、固定的 | 循环的、动态的 |
| 工具调用 | 在固定位置调用固定工具 | LLM 按需选择,调用次数不定 |
| 适合任务 | 结构明确、步骤固定 | 开放式、需要判断和决策 |
| 开发复杂度 | 低 | 较高 |
实际建议:任务流程固定用 Chain(简单可靠),任务需要动态判断和多步决策时用 Agent。
二、工具定义:让 Agent 拥有“手脚”
Agent 的工具是它唯一能与外部世界交互的通道。LLM 负责“想”,工具负责“做”。工具的描述写得好不好,直接决定了 LLM 能不能正确地选择和调用它。
2.1 工具调用的本质(Function Calling)
当我们给 Agent 配置工具时,实际发生的事情是:
你定义工具(函数名 + 参数说明 + 功能描述);
LangChain 将工具信息转换成 JSON Schema,随提示词发给 LLM;
LLM 阅读工具描述,决定“要调用哪个工具、传什么参数”;
LLM 返回“工具调用指令”(不是执行,而是指令);
LangChain 框架接收指令,在本地执行对应的函数;
执行结果返回给 LLM,LLM 继续推理。
关键理解:LLM 自身不能执行任何工具,它只是“调度员”。真正执行的是你的代码。
2.2 LangChain 的 @tool 装饰器
LangChain 提供@tool装饰器,只需写一个普通 Python 函数,加类型注解和 docstring,LangChain 会自动生成 JSON Schema。
python
from langchain.tools import tool @tool def get_weather(city: str, date: str) -> str: """获取指定城市在指定日期的天气。 Args: city: 城市名称,如“北京”、“上海” date: 日期,格式为 YYYY-MM-DD """ # 实际调用天气 API,这里用模拟数据 return f"{city} 在 {date} 天气多云,有下雨的可能性。"三个影响 LLM 调用准确性的关键点:
| 要素 | 作用 | 写法建议 |
|---|---|---|
| 函数名 | LLM 初步判断工具用途 | 用清晰的动词+名词,如get_weather |
| docstring | LLM 理解工具具体功能 | 写清楚“做什么”,越具体越好 |
| 参数类型注解 | LLM 决定传什么值 | 每个参数都要有类型注解和说明 |
当参数复杂时,可以用 Pydantic 模型定义参数结构:
python
from pydantic import BaseModel, Field class GetWeatherArgs(BaseModel): city: str = Field(description="城市名称,如'北京'") date: str = Field(description="日期,格式 YYYY-MM-DD") @tool(args_schema=GetWeatherArgs) def get_weather(city: str, date: str) -> str: """获取天气预报""" return f"{city} {date} 天气多云"2.3 构建并调用 Agent
使用create_agent函数将 LLM 和工具组装起来:
python
from langchain.agents import create_agent from langchain.chat_models import init_chat_model from langchain_tavily import TavilySearch llm = init_chat_model(model="gpt-4o-mini", model_provider="openai") search = TavilySearch(max_results=5) tools = [get_weather, search] # 自定义 + 第三方工具 agent = create_agent( model=llm, tools=tools, system_prompt="你是一个智能助手,请根据用户需求调用合适的工具。" ) # 一次性调用 result = agent.invoke({"messages": [{"role": "user", "content": "今天北京天气怎么样?"}]}) print(result["messages"][-1].content) # 流式调用(观察每一步) for step in agent.stream({"messages": [{"role": "user", "content": "今天北京天气怎么样?"}]}): print(step, end="\n\n")流式调用会依次展示:LLM 推理 → 工具调用 → 工具返回 → 最终回复,非常适合调试。
2.4 LangSmith 调试
设置环境变量即可启用 LangSmith 追踪,可视化每一步的执行细节:
python
import os os.environ["LANGSMITH_TRACING"] = "true" os.environ["LANGSMITH_API_KEY"] = "你的 API Key" os.environ["LANGSMITH_PROJECT"] = "my-agent-project"
三、MCP 协议:标准化工具接入
3.1 为什么需要 MCP?
本地工具虽然灵活,但当你需要使用别人封装好的服务(如查火车票、操作数据库)时,每个服务的接入方式都不同(REST、WebSocket、gRPC...),如果每接入一个都要写适配代码,太繁琐。
MCP(模型上下文协议)是 AI 领域的“USB-C 标准”,它统一了 LLM 与外部工具之间的通信方式。
3.2 MCP 架构与工作流程
MCP 采用客户端-服务器架构,三个角色:
MCP Host:你的 LangChain Agent 程序
MCP Client:LangChain 的 MCP 适配器
MCP Server:提供工具能力的远程服务
工作流程:
握手:Agent 启动时连接 Server,获取工具列表;
注入:工具描述和用户问题一起发给 LLM(LLM 不关心工具是本地的还是远程的);
决策:LLM 决定调用哪个工具、传什么参数;
路由执行:Host 通过 MCP 协议将调用请求发给 Server,Server 执行并返回;
继续推理:Host 将结果返回给 LLM。
对 LLM 来说,MCP 工具和本地工具没有区别——它看到的都是“工具名 + 描述 + 参数”。MCP 只改变了接入方式,对 LLM 完全透明。
3.3 编写 MCP Server(Stdio 方式)
本地开发调试最常用 Stdio 传输(通过标准输入输出通信)。
python
# mcp_server_stdio.py from mcp.server.fastmcp import FastMCP mcp = FastMCP("MyTools") @mcp.tool() def add(a: int, b: int) -> int: """计算两个整数的和""" return a + b @mcp.tool() def multiply(a: int, b: int) -> int: """计算两个整数的乘积""" return a * b if __name__ == "__main__": mcp.run(transport="stdio")除了@mcp.tool(),MCP 还支持:
@mcp.resource:提供可读取的静态数据(如系统日志、配置文件),类似只读 API。@mcp.prompt:提供预定义的提示词模板,让 Server 自带“使用说明书”。
3.4 编写 MCP Server(HTTP 方式)
当 Server 需要部署在远程供多个 Client 调用时,使用 Streamable HTTP:
python
# mcp_server_http.py from mcp.server.fastmcp import FastMCP mcp = FastMCP("MyTools") @mcp.tool() def add(a: int, b: int) -> int: return a + b if __name__ == "__main__": mcp.run(transport="streamable-http") # 默认 127.0.0.1:8000对应的 Client 连接方式不同,但调用工具的 API 完全一致。
3.5 LangChain 接入 MCP
使用langchain-mcp-adapters库,可将 MCP Server 的工具直接转换成 Agent 可用的工具:
python
from langchain_mcp_adapters.client import MultiServerMCPClient from langchain.agents import create_agent from langchain_openai import ChatOpenAI client = MultiServerMCPClient({ "my-local-tools": { "transport": "stdio", "command": "python", "args": ["mcp_server_stdio.py"], } }) async def main(): tools = await client.get_tools() # 自动获取所有工具 llm = ChatOpenAI(model="gpt-4o-mini") agent = create_agent(llm, tools) result = await agent.ainvoke({"messages": [("user", "10加20等于多少?")]}) print(result["messages"][-1].content)核心价值:通过MultiServerMCPClient可同时接入任意数量 MCP Server,对 Agent 来说,MCP 工具和本地@tool工具用起来没有任何区别。
3.6 本地工具 vs MCP 工具
| 对比维度 | 本地工具(@tool) | MCP 工具 |
|---|---|---|
| 定义位置 | 写在项目代码中 | 运行在独立的 Server 上 |
| 适合场景 | 业务逻辑简单、不需要复用 | 通用能力、跨项目/跨团队复用 |
| 维护方式 | 和主项目一起维护 | 独立部署、独立维护 |
| 生态复用 | 无(只有自己能用) | 强(任何支持 MCP 的应用都能接入) |
实际建议:项目早期或工具逻辑简单时,直接用@tool最快;当工具需要被多个项目复用,或想接入社区已有的服务时,用 MCP。两者可以混合使用。
小结(上篇)
Agent 是什么:LLM + 自主决策 + 工具调用,通过“感知→推理→行动”循环完成动态任务。
工具定义:用
@tool装饰器将普通函数转为 Agent 工具,写好 docstring 和类型注解是关键。MCP 协议:统一了 LLM 与外部工具的通信方式,让 Agent 能像“插 USB”一样接入各种服务。
有了工具和 MCP,Agent 已经能调用外部能力了。但它还有一个明显的不足——每次调用都是“失忆”的,不记得之前说过什么。下一章我们将学习如何给 Agent 加上记忆,以及如何用中间件优化长对话和增加人工审核。敬请关注下篇!