从零构建AI Agent:LangChain与LangGraph实战指南 30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度如果你正在学习AI Agent开发可能会遇到这样的困惑看了很多教程每个框架都讲一点但真正要动手搭建一个能实际运行的智能体时却发现无从下手。LangChain、LangGraph、OpenClaw……这些名词听起来都很酷但它们之间到底是什么关系我应该从哪个开始学哪个更适合我的项目这篇文章要解决的就是这个核心痛点如何将零散的AI Agent知识串联起来构建一个从理论到实践的完整认知和操作闭环。我不会只告诉你每个框架是什么而是会清晰地告诉你为什么需要组合使用这些工具LangChain负责“零件”LangGraph负责“组装流水线”OpenClaw则是“开箱即用的成品车间”。它们各自解决了什么问题是记忆管理、工具调用还是复杂工作流的编排如何一步步从零搭建一个可运行的智能体从环境准备、核心概念理解到代码实战和部署验证。读完本文你将能清晰地理解AI Agent的技术栈分层并亲手搭建一个具备多步骤推理和工具调用能力的智能体。更重要的是你会知道在未来的项目中如何根据需求选择合适的技术组合。1. 这篇文章真正要解决的问题从“知道”到“做到”的鸿沟当前AI Agent的学习存在一个典型的“知识孤岛”现象。很多资料会单独介绍LangChain的链Chain或者单独演示LangGraph的状态图StateGraph又或者展示OpenClaw的某个炫酷技能Skill。但一个真实的、有用的智能体恰恰是这些组件的有机组合。新手开发者面临的困境往往是概念混淆分不清Agent、Chain、Graph、Tool这些核心概念的边界和层级关系。选择困难面对多个框架不知如何选型担心学了一个另一个就过时了。无法落地看了很多Demo代码但不知道如何集成到自己的业务系统中如何处理身份认证、状态持久化等工程问题。调试困难智能体执行出错了日志一团糟不知道是模型问题、工具问题还是流程逻辑问题。本文的目标就是架设一座桥梁通过一个贯穿始终的实战案例带你走通“智能体需求分析 - 技术栈选型 - 环境搭建 - 核心开发 - 运行调试 - 最佳实践”的全流程。我们将构建一个“智能数据分析助手”Agent它能理解用户用自然语言提出的数据查询需求如“帮我计算上个月销售额最高的三个产品”自动调用工具模拟查询数据库、进行数学计算并给出结构化的回答。2. 基础概念与核心原理理解AI Agent的技术栈在动手之前必须建立清晰的技术地图。AI Agent开发不是单一技术而是一个分层的技术栈。2.1 核心概念定义AI Agent智能体核心目标。一个能感知环境、自主决策、执行动作以实现目标的软件实体。在我们的语境中通常指一个能理解用户意图、规划步骤、调用工具并完成任务的LLM大语言模型应用。LangChain“乐高积木箱”。它是一个用于开发由LLM驱动的应用程序的框架。其核心价值在于提供了大量可复用的“组件”如提示模板PromptTemplate规范化与LLM的对话。模型I/OLLM统一对接不同厂商OpenAI、Anthropic、本地模型等的LLM接口。记忆Memory为会话或智能体提供短期或长期记忆能力。工具Tool封装外部功能如搜索、计算、API调用供智能体使用。链Chain将多个组件按固定顺序组合起来的工作流。但链是线性的难以处理循环、分支等复杂逻辑。LangGraph“乐高组装说明书”或“流程图绘制工具”。它是建立在LangChain之上的一个库用于构建有状态的、多智能体或多步骤应用程序。其核心是状态图StateGraph允许你定义节点Nodes执行单元可以是一个函数、一个Chain或一个Agent。边Edges决定流程走向的条件“如果结果包含X则跳转到节点Y”。状态State在整个图执行过程中传递和更新的共享数据字典。关键优势完美解决了复杂、非线性工作流的编排问题支持循环、并行、条件分支是构建强大Agent的“大脑”。OpenClaw火山引擎“预制厨房”或“企业级智能体工厂”。它是火山引擎推出的开源AI智能体框架。你可以把它理解为一个更上层、更开箱即用的平台。它内置了技能Skill预置的、功能完备的智能体模块如文件处理、网络搜索、数据分析。编排能力提供了可视化或声明式的方式来组合技能构建复杂智能体。企业级特性更注重部署、监控、权限管理等生产环境所需的能力。与LangChain/LangGraph关系OpenClaw可以基于或兼容LangChain生态。你可以用LangGraph编排的智能体作为OpenClaw中的一个自定义Skill。2.2 技术栈分工与选型指南用一个表格来厘清关系组件角色定位解决的核心问题适用场景类比LangChain基础组件库LLM应用开发的标准化、模块化需要快速连接LLM与工具、数据库等外部系统构建简单的线性任务链。汽车零件库发动机、轮胎、方向盘LangGraph工作流编排引擎复杂、有状态、多步骤的任务流程控制需要循环如自我反思、迭代优化、条件分支、多角色协作的Agent。汽车组装流水线图纸OpenClaw企业级智能体平台智能体的快速构建、部署和管理企业内需要快速落地预置技能或对可视化管理、权限管控有强需求的场景。整车制造厂提供不同车型的流水线如何选择学习与深度定制从LangChain LangGraph开始。这是理解Agent底层原理和实现高度自定义的最佳路径。快速业务落地如果OpenClaw的预置技能能满足你80%的需求直接使用OpenClaw会更高效。混合模式用LangGraph编排核心复杂逻辑将其封装为一个Skill再集成到OpenClaw中进行统一管理和部署。本文的实战部分将聚焦于LangChain LangGraph这条路径因为这是掌握AI Agent开发精髓的关键。3. 环境准备与前置条件我们将使用Python作为开发语言。请确保你的环境满足以下要求。3.1 基础环境操作系统Windows 10/11, macOS, 或 Linux (Ubuntu 20.04)。本文命令以macOS/Linux为例Windows用户请在PowerShell或WSL中操作。Python版本Python 3.10 或 3.11。这是当前多数AI框架最稳定的支持版本。避免使用Python 3.12可能存在兼容性问题。包管理工具推荐使用pip也可使用conda或poetry。代码编辑器VS Code (推荐安装Python插件) 或 PyCharm。3.2 安装核心依赖首先创建一个干净的虚拟环境这是管理Python项目依赖的最佳实践。# 1. 创建项目目录并进入 mkdir ai-agent-tutorial cd ai-agent-tutorial # 2. 创建虚拟环境 (以venv为例) python -m venv venv # 3. 激活虚拟环境 # macOS/Linux: source venv/bin/activate # Windows: # venv\Scripts\activate # 激活后命令行提示符前应显示 (venv)接下来安装必要的Python包。我们将安装LangChain、LangGraph以及用于调用OpenAI模型的库。# 安装核心框架 pip install langchain langgraph langchain-openai # 安装可选但常用的工具库 pip install python-dotenv # 用于管理环境变量3.3 配置API密钥我们的智能体需要一个大语言模型作为“大脑”。这里我们使用OpenAI的GPT模型你也可以替换为其他兼容API的模型如Ollama本地模型。前往 OpenAI平台 获取你的API密钥。在项目根目录下创建.env文件用于安全存储密钥。在.env文件中写入# .env 文件 OPENAI_API_KEY你的实际API密钥重要安全提示永远不要将.env文件提交到Git等版本控制系统。请确保它在.gitignore文件中。4. 核心流程拆解构建智能数据分析助手的步骤我们的目标是构建一个“智能数据分析助手”。它的工作流程是接收用户查询自然语言。规划步骤LLM思考需要先查数据库再做计算。执行工具调用调用模拟的“查询数据库”工具。处理结果并判断LLM分析查询结果判断是否需要进一步计算或直接回答。生成最终回复。我们将使用LangGraph来编排这个包含“决策循环”的流程。下图展示了我们将要构建的Agent的核心工作流graph TD A[用户输入: “上个月销售额前三的产品?”] -- B[智能体入口] B -- C{LLM决策: 需要调用工具吗?} C -- 是/需要查询数据 -- D[调用“查询数据库”工具] D -- E[更新状态: 添加工具结果] E -- C C -- 否/已有足够信息 -- F[LLM生成最终答案] F -- G[返回结果给用户]下面我们分步实现这个流程。5. 完整示例与代码实现我们将创建三个主要文件tools.py- 定义智能体可以使用的工具。agent_graph.py- 定义LangGraph状态图和智能体逻辑。main.py- 主程序入口运行智能体。5.1 第一步定义工具Tools工具是智能体与外界交互的手和脚。我们先定义两个简单的工具一个模拟数据库查询一个模拟数学计算。# tools.py from langchain.tools import tool from typing import Dict, List import json # 模拟一个简单的产品销售数据库 _MOCK_DATABASE [ {product_id: P001, product_name: 智能手机X, sales_last_month: 15000}, {product_id: P002, product_name: 无线耳机Y, sales_last_month: 9200}, {product_id: P003, product_name: 智能手表Z, sales_last_month: 7500}, {product_id: P004, product_name: 平板电脑W, sales_last_month: 6200}, {product_id: P005, product_name: 笔记本电脑V, sales_last_month: 4800}, ] tool def query_database(query: str) - str: 根据自然语言描述查询模拟的产品销售数据。 支持查询特定产品、排序、筛选等简单意图。 Args: query: 自然语言查询例如“获取所有产品上个月的销售额” “找出销售额大于8000的产品” Returns: 返回JSON格式的查询结果字符串。 # 这是一个极其简化的模拟。真实场景会解析query转换成SQL或调用API。 # 这里我们根据关键词做简单匹配。 query_lower query.lower() if all in query_lower or 所有 in query_lower: result _MOCK_DATABASE elif top in query_lower or 前三 in query_lower or 前3 in query_lower: # 按销售额降序排序取前三 result sorted(_MOCK_DATABASE, keylambda x: x[sales_last_month], reverseTrue)[:3] elif 大于 in query_lower or 超过 in query_lower: # 提取数字简易版 import re numbers re.findall(r\d, query) threshold int(numbers[0]) if numbers else 5000 result [item for item in _MOCK_DATABASE if item[sales_last_month] threshold] else: # 默认返回所有数据让LLM自己去分析 result _MOCK_DATABASE return json.dumps(result, ensure_asciiFalse, indent2) tool def calculate_math(expression: str) - str: 执行数学计算。支持加减乘除、求平均值、最大值、最小值等。 注意使用eval有安全风险此处仅用于演示。生产环境应用安全的计算库如numexpr。 Args: expression: 数学表达式例如“(15000 9200 7500) / 3”, “max(15000, 9200, 7500)” Returns: 计算结果的字符串表示。 # 警告在实际生产中应对expression进行严格的校验和清洗避免代码注入。 # 这里为了演示直接使用eval并限制在安全范围内。 allowed_names {max: max, min: min, sum: sum, len: len} try: # 使用安全的eval result eval(expression, {__builtins__: {}}, allowed_names) return str(result) except Exception as e: return f计算错误: {e} # 工具列表方便后续导入 ALL_TOOLS [query_database, calculate_math]代码解释我们使用tool装饰器将普通函数转换为LangChain可识别的工具。query_database工具模拟了数据库查询。它接收自然语言返回JSON数据。calculate_math工具模拟了计算能力。请注意安全警告真实项目必须替换eval为安全的计算引擎。工具的描述docstring非常重要LLM会根据描述来决定是否以及如何调用该工具。5.2 第二步构建LangGraph智能体这是最核心的部分。我们将定义一个状态State并创建两个关键节点一个负责决定行动Agent一个负责执行工具Tools。# agent_graph.py from typing import TypedDict, Annotated, List, Union from langgraph.graph import StateGraph, END from langgraph.prebuilt import ToolExecutor, ToolInvocation from langchain_openai import ChatOpenAI from langchain.tools import BaseTool from langchain_core.messages import HumanMessage, AIMessage, ToolMessage import operator from dotenv import load_dotenv import os # 加载环境变量中的API密钥 load_dotenv() # 1. 定义状态结构 class AgentState(TypedDict): 智能体运行过程中的状态字典。 messages: Annotated[List[Union[HumanMessage, AIMessage, ToolMessage]], operator.add] # operator.add 表示这个字段在节点间传递时新的内容会追加到列表末尾。 # 这完美地记录了完整的对话历史。 # 2. 初始化模型和工具 llm ChatOpenAI(modelgpt-4o-mini, temperature0, api_keyos.getenv(OPENAI_API_KEY)) # 导入之前定义的工具 from tools import ALL_TOOLS tools ALL_TOOLS # ToolExecutor 是一个简单的工具调用封装器 tool_executor ToolExecutor(tools) # 3. 将工具绑定到LLM创建具备工具调用能力的“代理” llm_with_tools llm.bind_tools(tools) # 4. 定义节点函数 def agent_node(state: AgentState): “代理”节点分析当前状态对话历史决定下一步是回答问题还是调用工具。 # 从状态中获取最新的消息列表 messages state[messages] # 调用LLM传入完整历史让其决定下一步行动 response llm_with_tools.invoke(messages) # 将LLM的响应可能是普通消息也可能是工具调用请求加入到消息历史中 return {messages: [response]} def tool_node(state: AgentState): “工具”节点执行代理节点要求的工具调用并将结果返回。 # 获取最后一条消息它应该是一个包含工具调用请求的AIMessage last_message state[messages][-1] # 1. 初始化结果列表 tool_messages [] # 2. 遍历LLM请求调用的所有工具 for tool_call in last_message.tool_calls: # 创建工具调用对象 tool_input ToolInvocation( tooltool_call[name], tool_inputtool_call[args] ) # 3. 执行工具调用 output tool_executor.invoke(tool_input) # 4. 创建工具响应消息 tool_message ToolMessage( contentstr(output), tool_call_idtool_call[id] ) tool_messages.append(tool_message) # 将工具执行结果返回追加到状态中 return {messages: tool_messages} # 5. 定义条件边函数 def should_continue(state: AgentState) - str: 根据最新LLM消息判断下一步应该去哪个节点。 如果LLM调用了工具就去tools节点否则流程结束。 last_message state[messages][-1] # 如果最后一条消息包含工具调用则继续执行工具 if last_message.tool_calls: return tools # 否则结束流程 return end # 6. 构建图 workflow StateGraph(AgentState) # 添加节点 workflow.add_node(agent, agent_node) workflow.add_node(tools, tool_node) # 设置入口点 workflow.set_entry_point(agent) # 添加条件边 workflow.add_conditional_edges( agent, # 源节点 should_continue, # 判断函数 { tools: tools, # 如果返回“tools”则跳转到“tools”节点 end: END # 如果返回“end”则结束 } ) # 添加从工具节点回到代理节点的边工具执行完后继续让代理思考 workflow.add_edge(tools, agent) # 编译图生成可执行对象 app workflow.compile()代码解释定义状态StateAgentState是一个类型字典核心是messages列表它记录了所有对话消息用户输入、AI回复、工具结果。Annotated和operator.add确保了消息在节点间传递时是累积的。创建工具化LLMllm.bind_tools(tools)是关键它让LLM知道了有哪些工具可用及其功能描述。代理节点agent_node接收当前对话历史调用LLM。LLM会分析历史然后决定是直接生成回答还是请求调用一个工具返回一个特殊的AIMessage包含tool_calls。工具节点tool_node解析LLM发出的工具调用请求通过ToolExecutor实际执行对应的工具函数并将结果包装成ToolMessage返回。条件边should_continue这是实现“循环”的关键。它检查LLM的最新消息如果消息里有工具调用就路由到tools节点如果没有说明LLM已经准备好最终答案流程结束。构建图我们创建了一个简单的循环图agent- (判断) -tools-agent- ... -end。5.3 第三步主程序与交互现在让我们创建一个主程序来运行这个智能体。# main.py from agent_graph import app from langchain_core.messages import HumanMessage from dotenv import load_dotenv load_dotenv() def run_agent(user_input: str): 运行智能体处理用户输入。 print(f\n用户: {user_input}) print(- * 50) # 初始化状态包含用户的第一条消息 initial_state {messages: [HumanMessage(contentuser_input)]} # 流式输出执行过程可选便于调试 final_state None for event in app.stream(initial_state, stream_modevalues): event_messages event.get(messages, []) if event_messages: latest_message event_messages[-1] # 打印代理的思考或工具调用 if hasattr(latest_message, tool_calls) and latest_message.tool_calls: print(f代理: 我决定调用工具 - {[tc[name] for tc in latest_message.tool_calls]}) elif hasattr(latest_message, content) and latest_message.content: # 如果是工具返回的消息打印结果 if latest_message.type tool: print(f工具结果: {latest_message.content[:200]}...) # 截断长输出 # 如果是代理的最终回答 elif latest_message.type ai and not hasattr(latest_message, tool_calls): print(f\n智能体最终回答: {latest_message.content}) # 获取最终状态和所有消息 final_state app.invoke(initial_state) all_messages final_state[messages] # 提取并打印最终AI回复 for msg in reversed(all_messages): if msg.type ai and not hasattr(msg, tool_calls): print(f\n 最终答案 ) print(msg.content) break return final_state if __name__ __main__: # 示例查询 queries [ 上个月销售额最高的产品是什么, 帮我计算一下上个月所有产品的平均销售额。, 找出销售额超过7000的产品并告诉我它们的总销售额。 ] for query in queries: run_agent(query) print(\n *60 \n)6. 运行结果与效果验证现在让我们运行程序看看智能体是如何工作的。6.1 运行程序在项目根目录下执行python main.py6.2 预期输出与分析你应该能看到类似以下的输出具体内容可能因模型版本略有差异用户: 上个月销售额最高的产品是什么 -------------------------------------------------- 代理: 我决定调用工具 - [query_database] 工具结果: [ { product_id: P001, product_name: 智能手机X, sales_last_month: 15000 }, { product_id: P002, product_name: 无线耳机Y, sales_last_month: 9200 }, ... ]... 智能体最终回答: 根据查询结果上个月销售额最高的产品是**智能手机X**销售额为15,000。 最终答案 根据查询结果上个月销售额最高的产品是**智能手机X**销售额为15,000。用户: 帮我计算一下上个月所有产品的平均销售额。 -------------------------------------------------- 代理: 我决定调用工具 - [query_database] 工具结果: [...]... (返回所有产品数据) 代理: 我决定调用工具 - [calculate_math] 工具结果: 8540.0 智能体最终回答: 上个月所有产品的平均销售额为8,540。 最终答案 上个月所有产品的平均销售额为8,540。用户: 找出销售额超过7000的产品并告诉我它们的总销售额。 -------------------------------------------------- 代理: 我决定调用工具 - [query_database] 工具结果: [...]... (返回销售额7000的产品数据假设是P001, P002, P003) 代理: 我决定调用工具 - [calculate_math] 工具结果: 31700 智能体最终回答: 销售额超过7000的产品有智能手机X15,000、无线耳机Y9,200、智能手表Z7,500。它们的总销售额为31,700。 最终答案 销售额超过7000的产品有智能手机X15,000、无线耳机Y9,200、智能手表Z7,500。它们的总销售额为31,700。6.3 效果验证多步骤推理验证对于第二个和第三个问题智能体成功执行了“规划-执行-再规划-再执行”的循环。它先调用query_database获取数据然后分析数据发现需要计算再主动调用calculate_math工具。工具调用验证智能体正确地根据问题选择了合适的工具并生成了格式正确的工具调用参数。状态管理验证对话历史messages被完整地传递LLM在每次决策时都能看到之前的用户输入、自己的回复以及工具返回的结果。流程终止验证当LLM认为信息足够时它不再调用工具而是直接生成最终答案流程正确结束。7. 常见问题与排查思路在搭建和运行过程中你可能会遇到以下问题问题现象可能原因排查方式解决方案ModuleNotFoundError: No module named langchain依赖未安装或虚拟环境未激活。1. 检查命令行前缀是否有(venv)。2. 运行pip list | grep langchain。1. 激活虚拟环境source venv/bin/activate。2. 重新安装依赖pip install -r requirements.txt。AuthenticationError或Invalid API KeyOpenAI API密钥错误或未设置。1. 检查.env文件是否存在且格式正确。2. 在代码中打印os.getenv(OPENAI_API_KEY)的前几位。1. 确保.env文件在项目根目录且内容为OPENAI_API_KEYsk-...。2. 重启终端或IDE使环境变量生效。智能体不调用工具直接回答“我不知道”1. 工具描述不清晰。2. LLM温度temperature过高。3. Prompt引导不足。1. 检查工具函数的docstring是否清晰描述了功能和输入格式。2. 将LLM的temperature设为0。3. 在初始系统消息中明确要求其使用工具。1. 重写工具描述使用更具体、示例化的语言。2. 确保llm.bind_tools(tools)调用成功。3. 在agent_node中可以在消息列表开头加入一个SystemMessage来引导。工具调用参数格式错误LLM未能正确理解工具所需的输入格式。打印出tool_call[args]查看LLM生成的参数。1. 在工具描述中明确参数类型和示例。2. 使用Pydantic模型来定义更严格的工具输入模式tool(args_schema...)。图编译或执行时报错状态State结构定义与节点函数返回值不匹配。仔细检查AgentState的定义和每个节点函数返回的字典键名。确保节点函数返回的字典键如{messages: [...]}与State中定义的字段名完全一致且类型兼容。流程陷入无限循环should_continue逻辑有误或LLM反复调用同一个工具。在agent_node中打印response观察LLM是否在重复相同的工具调用。1. 在状态中加入步数限制。2. 在should_continue中检查历史如果相同工具调用连续出现多次则强制结束。8. 最佳实践与工程建议将Demo提升到生产可用级别需要考虑以下方面8.1 提示工程Prompt Engineering系统消息在agent_node中可以在消息列表开头插入一个SystemMessage明确设定智能体的角色、能力和目标这能显著提升其表现。from langchain_core.messages import SystemMessage system_prompt SystemMessage(content你是一个专业的数据分析助手。你必须使用提供的工具来查询和计算数据然后基于事实给出答案。) # 在调用LLM时将system_prompt放在messages列表最前面工具描述优化工具的函数文档字符串docstring是LLM理解工具的唯一依据。务必清晰、准确并包含输入输出示例。8.2 状态管理与记忆短期记忆本文使用的messages列表就是对话记忆。对于长对话需注意上下文长度限制可能需要摘要或选择性遗忘。长期记忆可以为智能体集成向量数据库如Chroma, Pinecone用于存储和检索历史对话、知识文档。结构化状态除了messages可以在AgentState中添加更多业务相关的字段如intermediate_data中间计算结果、user_preferences用户偏好等。8.3 错误处理与鲁棒性工具调用容错在tool_node中对每个工具调用进行try-catch将错误信息包装成ToolMessage返回给LLM让其有机会自我纠正。超时与重试为工具调用和LLM调用设置超时和重试机制。验证与过滤对LLM生成的工具调用参数进行有效性验证防止注入攻击或无效请求。8.4 可观测性与调试日志记录使用logging模块详细记录每个节点的输入输出、工具调用详情、LLM的请求和响应。这对于调试复杂工作流至关重要。可视化LangGraph提供了workflow.get_graph().draw_mermaid()方法可以生成Mermaid图来可视化你的工作流。跟踪Tracing集成像LangSmith这样的平台可以可视化跟踪智能体执行的每一步进行性能分析和调试。8.5 性能与成本优化模型选择对于简单工具调用gpt-3.5-turbo可能足够且更便宜。对于复杂推理再使用gpt-4。缓存对LLM响应和工具结果进行缓存例如使用langchain.cache减少重复计算和API调用。异步执行如果图中有可以并行执行的节点使用asyncio进行异步调用以提升性能。8.6 与OpenClaw等平台的集成当你用LangGraph构建了一个稳定可靠的智能体后可以将其封装作为OpenClaw的一个自定义Skill。通常OpenClaw会提供Skill SDK或定义标准的接口规范如一个特定的类或函数入口。你需要了解OpenClaw Skill的开发规范。将你的LangGraph智能体包装成一个符合规范的类。处理OpenClaw平台传入的输入并返回其期望的输出格式。在OpenClaw的管理界面中注册和配置你这个自定义Skill。至此你已经完成了一个具备多步推理和工具调用能力的AI Agent从零到一的构建。我们不仅写出了代码更关键的是理解了LangChain提供组件、LangGraph负责编排的协同工作模式。这套模式是构建复杂智能应用的基石。你可以在此基础上替换更复杂的工具如真实数据库API、外部服务设计更精细的状态图和决策逻辑来应对真实的业务场景。 30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度