尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于LangChain与MCP协议构建AI Agent:从原理到实战

基于LangChain与MCP协议构建AI Agent:从原理到实战 最近在尝试将大模型能力集成到实际业务中时发现单纯调用API生成文本已经不够用了。我们常常需要模型能“思考”能“行动”能根据目标调用工具、处理数据、完成复杂任务。这正是AI Agent智能体要解决的问题。然而从零开始构建一个稳定、高效的Agent往往会遇到工具调用混乱、状态管理困难、错误处理复杂等挑战网上资料要么过于理论要么代码片段零散不成体系。本文将以实战为导向手把手带你从零构建一个具备规划与执行能力的AI Agent。我们将以当前主流的LangChain框架为核心结合最新的MCPModel Context Protocol协议搭建一个能联网搜索、处理文件、进行数学计算的智能体。无论你是想入门Agent开发的学生还是寻求项目落地的工程师这篇涵盖环境搭建、核心概念、代码实战、避坑指南的完整教程都能让你快速上手避开我踩过的那些坑。1. 背景与核心概念为什么需要AI Agent在深入代码之前我们有必要厘清几个核心概念理解Agent技术演进的脉络和要解决的根本问题。1.1 从大模型到智能体能力的延伸大型语言模型LLM如GPT-4、Claude、通义千问等本质上是强大的“下一个词预测器”。它们拥有海量的知识能进行流畅的对话、创作和推理。然而它们存在几个关键限制信息滞后性知识截止于训练数据无法获取实时信息如今天天气、股价。缺乏行动力无法直接操作外部系统如发送邮件、查询数据库、控制智能家居。精确计算能力弱不擅长进行精确的数学运算或逻辑判断。AI Agent智能体就是为了突破这些限制而生的架构。它以大模型为“大脑”决策核心赋予其“感官”感知环境和“手脚”执行工具。一个典型的Agent工作流程是接收用户目标 - 大模型进行规划决定步骤 - 调用合适的工具执行 - 观察工具返回的结果 - 根据结果决定下一步行动直至任务完成或无法继续。1.2 关键组件与框架生态构建一个Agent通常涉及以下组件LLM Core智能体的决策中心负责理解指令、规划步骤、解析工具输出。Tools智能体可以调用的外部函数或API如搜索引擎、计算器、代码执行器、数据库客户端等。Memory使智能体拥有短期或长期的记忆能记住对话历史、中间结果实现多轮连贯交互。Agent Executor驱动整个循环思考-行动-观察的运行时引擎负责调度工具、管理状态、处理错误。为了简化开发社区涌现了多个优秀的Agent框架LangChain目前最流行、生态最丰富的Python框架提供了构建Agent所需的全套高级抽象Agent、Tool、Chain、Memory支持多种大模型是快速原型和生产的首选。LlamaIndex更侧重于数据连接和检索增强生成RAG但其Agent能力也在不断增强。Spring AI为Java生态提供的AI应用开发框架同样包含了Agent概念。Dify、FastGPT等低代码/无代码平台通过可视化方式组装Agent工作流降低了使用门槛。本文将选择LangChain作为主要框架因为它功能全面、文档丰富、社区活跃最适合学习和深度定制。1.3 MCP工具连接的新标准在开发Agent时一个常见痛点是如何让Agent方便、安全、标准化地使用成千上万种不同的工具传统方式需要为每个工具编写适配代码非常繁琐。MCPModel Context Protocol正是为了解决这一问题而提出的开放协议。你可以把它想象成智能体世界的“USB标准”。它定义了一套标准接口任何工具如数据库、文件系统、API服务只要实现为一个MCP Server就能被任何兼容MCP的客户端如你的Agent发现和调用。它的核心优势在于标准化统一的工具发现、调用和结果返回格式。安全性工具运行在独立的Server中与主Agent进程隔离。可扩展性轻松接入新的工具无需修改核心Agent代码。在本文的实战部分我们将使用MCP来为我们的Agent接入一个标准的“计算器”工具体验这种解耦带来的便利。2. 环境准备与版本说明工欲善其事必先利其器。让我们先搭建好开发环境。以下环境为本文撰写时的主流选择请根据你的实际情况调整。2.1 基础环境操作系统Windows 10/11, macOS, 或 Linux (Ubuntu 20.04)。本文命令以macOS/Linux的bash为例Windows用户可在PowerShell或WSL中运行。Python版本Python 3.10 或 3.11。这是LangChain等库兼容性最好的版本。强烈建议使用conda或pyenv管理Python环境避免包冲突。包管理工具pip(最新版)。2.2 创建虚拟环境并安装核心库首先创建一个独立的项目目录和虚拟环境。# 创建项目目录并进入 mkdir ai-agent-tutorial cd ai-agent-tutorial # 创建Python虚拟环境使用venv python -m venv venv # 激活虚拟环境 # macOS/Linux: source venv/bin/activate # Windows: # venv\Scripts\activate # 升级pip pip install --upgrade pip接下来安装LangChain及其相关依赖。我们将安装langchain-core、langchain-community以及OpenAI的官方集成包因为我们使用GPT作为大脑。同时为了示例中的网页搜索功能我们安装duckduckgo-search。为了使用MCP我们安装mcp客户端库。# 安装LangChain核心及OpenAI集成 pip install langchain langchain-openai # 安装社区工具包含很多预置工具 pip install langchain-community # 安装DuckDuckGo搜索工具免费无需API Key pip install duckduckgo-search # 安装MCP客户端库 pip install mcp # 安装Jupyter notebook可选用于交互式实验 pip install jupyter2.3 获取并配置API密钥我们的Agent需要一个“大脑”。这里我们使用OpenAI的GPT模型例如gpt-4o-mini或gpt-4-turbo你需要一个OpenAI的API Key。访问 OpenAI Platform 并登录。点击右上角个人头像选择 “View API keys”。点击 “Create new secret key” 创建一个新的密钥并妥善保存。安全提示永远不要将API Key直接硬编码在代码中或提交到版本控制系统如Git。我们将使用环境变量来管理密钥。在项目根目录创建一个名为.env的文件# .env 文件 OPENAI_API_KEY你的OpenAI_API_Key然后在Python代码中使用python-dotenv库来加载它。先安装这个库pip install python-dotenv3. 核心组件拆解LangChain中的Agent是如何工作的在写代码前我们需要理解LangChain中构建Agent的几个核心抽象。这将帮助你不仅知其然更知其所以然。3.1 工具ToolAgent的“手脚”Tool是一个可调用的函数它有一个名称name、描述description和参数模式args_schema。描述至关重要因为LLM会根据描述来决定在什么情况下调用这个工具。LangChain提供了大量预置工具在langchain_community.tools中也支持轻松自定义。一个自定义Tool的示例# custom_tool.py from langchain.tools import BaseTool from pydantic import BaseModel, Field from typing import Optional, Type class CalculatorInput(BaseModel): 输入两个数字进行运算。 a: float Field(description第一个数字) b: float Field(description第二个数字) operation: str Field(description运算类型可选add, subtract, multiply, divide) class CustomCalculatorTool(BaseTool): name calculator description 用于执行两个数字之间的基本算术运算加、减、乘、除。 args_schema: Type[BaseModel] CalculatorInput return_direct: bool False # 是否直接返回结果不经过LLM思考 def _run(self, a: float, b: float, operation: str) - str: 执行工具逻辑。 if operation add: return str(a b) elif operation subtract: return str(a - b) elif operation multiply: return str(a * b) elif operation divide: if b 0: return 错误除数不能为零 return str(a / b) else: return f未知操作{operation} async def _arun(self, a: float, b: float, operation: str): 异步执行可选。 return self._run(a, b, operation) # 使用工具 if __name__ __main__: tool CustomCalculatorTool() print(tool.name) # calculator print(tool.description) result tool.run({a: 10, b: 5, operation: multiply}) print(result) # 503.2 智能体类型AgentType与执行器AgentExecutorLangChain提供了多种预设的Agent类型它们本质上是不同的“提示词模板”告诉LLM如何思考、如何选择工具。常见的类型有ZERO_SHOT_REACT_DESCRIPTION最常用的类型基于ReAct范式Reason Act。LLM会以“Thought: ... Action: ... Observation: ...”的格式逐步推理。OPENAI_FUNCTIONS/OPENAI_TOOLS专为OpenAI模型设计利用其原生的函数调用Function Calling能力格式更规范性能更好。STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION适合工具参数复杂结构化的场景。AgentExecutor是驱动Agent运行的核心类。它接收一个Agent实例和一组Tools并循环执行以下步骤将用户输入、历史对话、工具描述传递给AgentLLM。Agent返回一个包含下一步Action调用哪个工具及参数的响应。Executor调用对应的Tool得到Observation工具执行结果。将Observation加入到上下文中再次传递给Agent进行下一步思考。重复此过程直到Agent返回一个最终答案Final Answer或达到最大迭代次数。3.3 记忆Memory让对话有连续性默认情况下Agent是“无状态”的它不会记住之前的对话。通过引入Memory我们可以实现多轮对话。LangChain提供了多种Memory如ConversationBufferMemory简单缓存、ConversationSummaryMemory总结式记忆等。4. 完整实战案例构建一个多功能AI Agent现在让我们整合以上知识构建一个能联网搜索、进行数学计算、并尝试通过MCP使用文件系统工具的智能体。4.1 项目结构与初始化创建以下文件结构ai-agent-tutorial/ ├── .env # 存放API密钥 ├── requirements.txt # 依赖列表可选 ├── main.py # 主程序 ├── mcp_calculator_server.py # MCP服务器示例 └── README.md确保你的.env文件已配置好OPENAI_API_KEY。4.2 编写主程序基于LangChain的智能体在main.py中我们将完成以下步骤加载环境变量。初始化LLM使用OpenAI。准备工具集搜索工具、自定义计算器工具。创建Agent并运行。# main.py import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain_community.tools import DuckDuckGoSearchRun from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser # 1. 加载环境变量 load_dotenv() openai_api_key os.getenv(OPENAI_API_KEY) if not openai_api_key: raise ValueError(请在 .env 文件中设置 OPENAI_API_KEY) # 2. 初始化LLM使用较新的gpt-4o-mini性价比高 llm ChatOpenAI( modelgpt-4o-mini, temperature0, # 降低随机性让Agent更稳定 api_keyopenai_api_key ) # 3. 准备工具 # 工具1 DuckDuckGo 搜索免费 search_tool DuckDuckGoSearchRun(nameweb_search) search_tool.description 一个在互联网上搜索最新信息的工具。当问题涉及实时事件、新闻、未知事实或需要最新数据时使用此工具。 # 工具2 自定义计算器工具使用之前定义的CustomCalculatorTool # 这里我们直接使用一个简化的版本避免引入之前的类定义 from langchain.tools import Tool def simple_calculator(a: float, b: float, operation: str) - str: if operation add: return str(a b) elif operation subtract: return str(a - b) elif operation multiply: return str(a * b) elif operation divide: if b 0: return 错误除数不能为零 return str(a / b) else: return f未知操作{operation} calculator_tool Tool( namecalculator, funcsimple_calculator, description执行两个数字之间的基本算术运算。输入应是一个包含a(数字), b(数字), operation(字符串可选值add, subtract, multiply, divide)的JSON对象。 ) tools [search_tool, calculator_tool] # 4. 构建Agent提示词模板 # 这个模板告诉LLM它的角色、可用的工具以及如何格式化输出 prompt ChatPromptTemplate.from_messages([ (system, 你是一个乐于助人的AI助手。你可以使用工具来获取信息或进行计算。 请严格遵循以下规则 1. 如果用户的问题需要实时信息或你不知道的事实请使用搜索工具。 2. 如果涉及精确计算请使用计算器工具。 3. 仔细思考一步一步来。 4. 你的最终回答应该清晰、完整。 可用工具{tools}), MessagesPlaceholder(variable_namechat_history), # 预留位置给对话历史 (user, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), # 预留位置给Agent的思考过程 ]) # 5. 绑定LLM和工具创建Agent llm_with_tools llm.bind_tools(tools) agent ( { input: lambda x: x[input], chat_history: lambda x: x.get(chat_history, []), # 处理记忆 agent_scratchpad: lambda x: format_to_openai_tool_messages(x[intermediate_steps]), tools: lambda x: \n.join([f{tool.name}: {tool.description} for tool in tools]) } | prompt | llm_with_tools | OpenAIToolsAgentOutputParser() ) # 6. 创建Agent执行器 agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, # 开启详细日志方便调试 handle_parsing_errorsTrue, # 处理解析错误 max_iterations5, # 防止无限循环 early_stopping_methodgenerate, # 达到最大迭代次数时让LLM生成一个最终答案 ) # 7. 运行Agent if __name__ __main__: print( AI Agent 已启动输入 quit 退出 ) chat_history [] # 简单的对话历史存储 while True: try: user_input input(\n你: ) if user_input.lower() quit: print(再见) break # 执行Agent result agent_executor.invoke({ input: user_input, chat_history: chat_history }) # 输出结果 print(f\n助手: {result[output]}) # 更新对话历史简单实现生产环境需更复杂的管理 chat_history.append((user, user_input)) chat_history.append((assistant, result[output])) except KeyboardInterrupt: print(\n程序被中断。) break except Exception as e: print(f\n发生错误: {e})4.3 运行与验证在终端中确保虚拟环境已激活然后运行python main.py你会看到类似以下的输出verboseTrue会让你看到Agent内部的思考过程Thought/Action/Observation AI Agent 已启动输入 quit 退出 你: 今天的北京天气怎么样 进入新的Agent执行链... 我无法直接获取实时信息需要使用搜索工具来查询今天的北京天气。 Action: web_search Action Input: 北京 今天 天气 Observation: 北京今天晴转多云最高气温25°C最低气温15°C南风3-4级。 Thought: 我已经搜索到了北京的天气信息可以回答用户的问题了。 Final Answer: 根据搜索结果显示北京今天指查询当天的天气是晴转多云最高气温大约25摄氏度最低气温大约15摄氏度风力为南风3到4级。 助手: 根据搜索结果显示北京今天指查询当天的天气是晴转多云最高气温大约25摄氏度最低气温大约15摄氏度风力为南风3到4级。 你: 那如果我要买3件单价是25.5元的商品加上8%的税总共需要支付多少钱 ... Action: calculator Action Input: {a: 76.5, b: 1.08, operation: multiply} Observation: 82.62 Thought: 计算器给出了含税总价。我需要将这个结果以清晰的格式呈现给用户。 Final Answer: 3件单价25.5元的商品不含税总价为76.5元。加上8%的税后你需要支付的总金额是82.62元。 助手: 3件单价25.5元的商品不含税总价为76.5元。加上8%的税后你需要支付的总金额是82.62元。4.4 引入MCP体验标准化工具调用上面的计算器工具是内嵌在代码中的。现在我们将其改造成一个独立的MCP Server让Agent通过MCP协议来调用它。这模拟了在复杂环境中工具由不同团队以服务形式提供的场景。首先创建一个MCP服务器文件mcp_calculator_server.py# mcp_calculator_server.py import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client # 1. 定义我们的计算器工具模拟一个独立的服务 class CalculatorServer: async def add(self, a: float, b: float) - float: return a b async def subtract(self, a: float, b: float) - float: return a - b async def multiply(self, a: float, b: float) - float: return a * b async def divide(self, a: float, b: float) - float: if b 0: raise ValueError(除数不能为零) return a / b # 注意一个完整的MCP Server实现需要遵循MCP协议包括初始化握手、列出工具、调用工具等。 # 这里是一个极度简化的概念性示例用于说明MCP的思想。 # 在实际开发中你会使用 mcp 库提供的 Server 类来构建标准服务器。 # 例如 # from mcp.server import Server # from mcp.server.models import TextContent # server Server(calculator-server) # server.list_tools() # async def handle_list_tools(): # return [ToolDescription(...)] # server.call_tool() # async def handle_call_tool(name: str, arguments: dict): # if name add: # result calc.add(arguments[a], arguments[b]) # return [TextContent(typetext, textstr(result))] # ... print(概念演示MCP Server 将计算器功能封装为独立服务通过标准协议暴露add, subtract等工具。) print(LangChain Agent 可以通过 MCP Client 连接到这个Server并调用其工具就像调用本地工具一样。) print(这实现了工具与Agent核心逻辑的解耦。)然后我们需要修改main.py使其能够通过MCP客户端调用这个“远程”计算器。由于完整实现一个MCP Server和Client需要较多代码这里我们聚焦于概念在LangChain中你可以将任何符合BaseTool接口的对象作为工具。一个MCP Client适配器就可以被包装成这样一个Tool。思路是创建一个MCPCalculatorTool类在其_run方法内部通过MCP客户端协议与mcp_calculator_server通信。这样对Agent来说它只是在调用一个普通的工具而底层通信已经标准化了。5. 常见问题与排查思路在开发和使用Agent过程中你一定会遇到各种问题。下面是一些典型问题及其解决方案。问题现象可能原因排查思路与解决方案Agent stopped due to iteration limit or time limit.代理因迭代次数或时间限制而停止。1. 任务过于复杂超过了max_iterations默认15。2. Agent陷入循环无法找到解决方案。3. 工具描述不清晰导致LLM错误选择工具。1.增加迭代次数在AgentExecutor中设置max_iterations20或更高。2.优化提示词在系统提示中强调“逐步思考”和“在无法进展时给出最终答案”。3.检查工具描述确保每个工具的description准确描述了其功能和适用场景避免歧义。4.启用handle_parsing_errorsTrue并设置early_stopping_methodgenerate。OpenAI API 错误 (如 invalid_api_key, rate_limit, context_length)1. API Key错误或过期。2. 请求速率超限。3. 输入上下文过长。1.检查API Key确认.env文件配置正确且环境变量已加载。2.处理速率限制实现重试机制可使用tenacity库或升级API套餐。3.管理上下文使用ConversationSummaryMemory或ConversationBufferWindowMemory来限制历史长度或对长文档进行分块摘要。Tool with name X not found.找不到名为X的工具。1. 工具列表tools中没有包含该工具。2. 工具名称在绑定或传递过程中出错。1.检查工具列表确认tools变量中包含了所有需要的工具实例。2.检查工具名称确保工具实例的name属性与LLM尝试调用的名称一致区分大小写。Agent频繁调用错误工具或无法理解何时使用工具。1. 工具描述 (description) 写得太差。2. 系统提示词 (prompt) 没有清晰指导。3. LLM的temperature参数过高导致决策不稳定。1.重写工具描述描述应简洁、具体说明何时使用和输入输出格式。例如“当用户需要计算两个数字的和、差、积、商时使用。输入应为JSON如{\a\: 5, \b\: 3, \operation\: \add\}”。2.强化系统提示明确列出工具和各自的使用条件。3.降低temperature尝试设置为0或0.1让Agent更确定性。MCP Server连接失败或调用超时。1. MCP Server进程未启动或崩溃。2. 网络或Stdio通信故障。3. 协议版本不匹配。1.检查Server状态确保MCP Server进程正在运行并且Stdio通道正常。2.查看日志检查Server和Client的日志输出寻找错误信息。3.验证协议确保Client和Server使用的MCP协议版本兼容。Agent输出无关内容或“幻觉”。1. 提示词约束力不够。2. 工具返回的结果格式LLM无法理解。3. 任务超出LLM或工具的能力范围。1.在提示词中加强约束例如“你必须使用工具来获取实时信息不要凭空编造。”2.规范化工具输出确保工具返回的是简洁、结构化的文本便于LLM解析。3.任务分解对于复杂任务可以设计一个“规划Agent”先拆分子任务再由“执行Agent”调用工具完成。6. 最佳实践与工程建议将Agent从Demo推向生产环境需要考虑更多工程化因素。6.1 提示词工程清晰的角色与规则在系统提示词开头明确Agent的角色、职责和必须遵守的规则。结构化工具描述为每个工具提供格式统一的描述模板例如“工具名称用于[场景]。输入格式[示例]。输出格式[示例]。”少样本示例Few-Shot在提示词中提供1-2个用户问题及Agent正确调用工具并回答的完整示例Thought/Action/Observation/Final Answer能极大提升Agent的可靠性。迭代优化将提示词存储在版本控制系统如Git中像管理代码一样管理它根据测试结果持续迭代。6.2 工具设计与治理单一职责每个工具应只做一件事并把它做好。避免创建功能臃肿的“瑞士军刀”式工具。健壮性工具内部必须有完善的错误处理try-except并返回对LLM友好的错误信息如“查询失败网络超时”而不是抛出未处理的异常。安全性这是重中之重。任何执行写操作删除文件、发送邮件、修改数据库、访问敏感信息或执行代码的工具都必须进行严格的权限校验和输入验证。永远不要允许用户通过自然语言直接调用os.system或eval这样的危险函数。MCP化对于团队协作或复杂系统积极考虑使用MCP协议将工具服务化。这有利于权限隔离、独立部署和版本管理。6.3 性能与成本优化选择性记忆不要无限制地存储完整对话历史。使用ConversationSummaryMemory或ConversationBufferWindowMemory来控制上下文长度避免不必要的Token消耗和模型性能下降。缓存对于耗时或消耗API调用的工具如某些搜索、复杂计算可以考虑实现结果缓存避免重复执行。模型选择并非所有任务都需要GPT-4。对于工具调用逻辑清晰的任务gpt-4o-mini或gpt-3.5-turbo可能更具性价比。进行A/B测试来确定。设置超时与限制在AgentExecutor中合理设置max_execution_time和max_iterations防止任务卡死或成本失控。6.4 可观测性与调试开启Verbose日志在开发阶段务必设置verboseTrue这是理解Agent思维链条、定位问题的最直接方式。结构化日志在生产环境将Agent的执行步骤输入、工具调用、输出、耗时记录到结构化日志系统如JSON格式便于监控和分析。评估与测试建立自动化测试集覆盖常见问题、边界情况和危险指令确保Agent更新的行为符合预期。构建AI Agent是一个将大语言模型的认知能力与外部工具的行动能力相结合的过程。通过本文你应该已经掌握了使用LangChain框架搭建一个基础智能体的全流程从理解核心概念工具、执行器、记忆到环境搭建再到编写一个具备搜索和计算能力的可运行Agent并了解了通过MCP协议标准化工具调用的未来方向。记住一个成功的Agent项目三分靠框架七分靠设计。精心设计的工具、清晰明确的提示词、周全的安全考虑和持续的测试优化远比追求最复杂的模型更重要。下一步你可以尝试为你的Agent接入更多工具如数据库查询、邮件发送、内部API或者探索更高级的架构如多智能体协作Multi-Agent、具备长期记忆的自主智能体等。
返回列表