本文深入解析了 AI Agent 的核心价值在于判断与决策而非简单回答问题。LangGraph 作为图式工作流框架通过 State共享状态、Node处理节点、Router决策分支的设计完美契合 Agent 的有状态、分支、循环特性。文章以最小天气查询 Agent 为例详细展示了如何利用 LangGraph 实现用户输入→模型判断→工具调用→状态更新→最终回复的完整闭环并对比了 LangGraph 与普通链式调用的差异强调其在复杂流程、循环交互、持久化等方面的优势。通过搭建可运行的示例帮助读者直观理解 LangGraph 的核心概念和 Agent 的构建逻辑为进阶设计复杂 Agent 提供了清晰的实践路径。如果你刚开始学 AI Agent很容易把它理解成“让大模型回答问题”。但真正的 Agent关键不只是“回答”而是它会先判断再决定要不要调用工具拿到工具结果后继续往下走最后再输出答案。这类流程如果只靠普通链式调用来写通常会越来越乱输入进来先调用模型如果模型说要查天气就再调一次工具工具结果回来再调一次模型如果工具失败可能还要重试如果用户没说城市还得补问。流程一复杂代码就会开始到处塞 if/else。这正是 LangGraph 的价值所在。根据 LangGraph 官方文档它本质上是一个“图式工作流框架”State共享状态保存当前运行快照Node处理逻辑节点读取状态并返回状态更新Edge决定接下来执行哪个节点StateGraph把这些节点和边编译成可执行图图编译后可以invoke()、stream()、异步执行并且天然适合有循环、分支、工具调用、持久化和人工介入的 Agent 流程官方文档还特别强调LangGraph 是面向有状态、可循环、可恢复执行的 Agent 编排运行时而不只是把多个步骤简单串起来。这也是它比普通链更适合 Agent 的核心原因。这篇文章我们就从零开始搭一个最小可运行的天气查询 Agent让你真正理解什么是State什么是Node什么是Router为什么 Agent 天然适合用LangGraph一个“用户问天气 → Agent 决策 → 调用工具 → 返回答案”的完整执行流程是怎么跑起来的一、先理解LangGraph 到底在解决什么问题先看一个最简单的用户请求““北京今天天气怎么样”对于这个问题一个真正的 Agent 不应该一上来就瞎答而应该经历下面的过程接收用户消息判断这是不是一个需要工具的问题如果需要提取城市名比如“北京”调用天气工具拿到天气结果再组织成自然语言回复用户LangGraph 天气查询 Agent 的完整执行流程图注意这里面不是单次“输入→输出”而是一个带状态的多步决策过程。如果以后再扩展一下需求比如如果用户没说城市要追问如果天气接口报错要重试如果用户还问“顺便告诉我穿衣建议”还要继续推理如果要支持多轮对话还得保留消息历史这已经明显不是简单 Prompt 能优雅解决的问题了。LangGraph 的思路是把 Agent 看成一个状态机state machine或图graph。每一个步骤是一个节点每一次跳转由边来控制而所有节点共享同一个状态。二、新手最容易混淆的 3 个概念State、Node、Router这是初学 LangGraph 最容易绕晕的地方我们先讲透。1. State当前运行过程中的“共享记忆”你可以把 State 理解成 Agent 在这一轮执行中随身带着的一份工作记录。例如我们的天气 AgentState 里可以放这些信息messages对话消息列表city解析出的城市tool_result天气工具返回的数据final_answer最终输出给用户的答案在 LangGraph 官方 Graph API 中State 的核心特点是所有节点都能读它节点执行后返回的是Partial State也就是“我只更新其中一部分字段”图运行时会把这些更新合并回共享状态中也就是说Node 不是直接“打印结果”而是“修改状态”。2. Node一个处理步骤Node 本质就是一个函数。它接收当前状态做一些逻辑处理然后返回要更新的字段。例如agent_node让大模型判断是否需要调用工具tool_node真正执行天气查询respond_node根据工具结果生成最终答案所以你可以把 Node 理解成“Agent 工作流中的一个“处理站”3. Router决定下一步去哪Router 不是一个独立的官方类名而是开发中常见的说法。通常指的是根据当前状态决定图接下来走哪条边的函数。例如如果模型已经发起了工具调用 → 去tool_node如果模型已经可以直接回答 → 去respond_node如果执行结束了 → 去END在 LangGraph 里这类逻辑一般通过add_conditional_edges()来实现。所以最直白的理解是State现在手里有哪些信息Node当前这一步要做什么Router下一步该去哪里State、Node、Router 三个概念的对比关系图三、为什么 LangGraph 适合 Agent而不只是普通链式调用很多人第一次接触 LangGraph 时会问““我直接写一个链不也能先 LLM、再工具、再 LLM 吗”可以但两者适合的场景不同。普通链式调用更像流水线链式调用通常适合步骤固定基本没有分支不需要循环不需要状态长期保存不需要失败恢复例如用户输入 → 提取关键词 → 总结结果 → 输出这种很适合链。Agent 更像“动态决策流程”Agent 的特点是是否调用工具运行时才知道调用哪个工具运行时才知道可能会循环多轮思考 → 调工具 → 再思考可能需要中断、恢复、回放可能需要保留复杂状态而 LangGraph 官方文档强调的优势正是这些Durable execution长流程可以持久化与恢复Human-in-the-loop中途人工介入Stateful天然管理状态Streaming / Debugging / Observability适合生产级 Agent 追踪和调试一句话总结“普通链擅长“固定步骤”LangGraph 擅长“会分支、会循环、会调用工具的有状态 Agent”。LangGraph 与普通链式调用的对比图四、先搭一个最小版天气 Agent下面我们用 Python LangGraph 搭一个完整示例。为了聚焦 LangGraph 核心概念这里天气工具先用模拟数据不接真实天气 API。等你跑通流程后再把工具替换成真实接口即可。五、安装依赖pip install -U langgraph langchain langchain-openai如果你用 OpenAI 模型还需要配置环境变量export OPENAI_API_KEY你的_keyWindows PowerShell:setx OPENAI_API_KEY 你的_key六、定义天气工具先定义一个最简单的工具。LangChain 官方 Tools 文档中推荐使用tool装饰器定义工具这也是 LangGraph 里最常见的工具接入方式。from langchain.tools import tooltooldef get_weather(city: str) - str: 查询指定城市的天气。输入必须是城市名。 mock_weather_data { 北京: 晴22°C东北风 2 级, 上海: 多云26°C东南风 3 级, 广州: 小雨29°C南风 2 级, 深圳: 阴28°C微风, } return mock_weather_data.get(city, f暂时没有 {city} 的天气数据)这里先不追求真实而是先把“工具调用”这个动作建立起来。七、定义 StateLangGraph 官方 Graph API 文档推荐使用TypedDict或 Pydantic 来定义状态。如果你的工作流围绕消息展开还可以使用MessagesState。我们的例子正好是聊天场景所以直接继承MessagesState最省事。from typing import Annotated, TypedDict, Optionalfrom langgraph.graph import MessagesStatefrom langgraph.graph.message import add_messagesfrom langchain.messages import AnyMessageclass WeatherAgentState(MessagesState): city: Optional[str] tool_result: Optional[str] final_answer: Optional[str]这里要注意MessagesState已经帮你准备好了messagesmessages会以适合消息场景的方式合并我们额外补充了city、tool_result、final_answer你也可以不继承MessagesState手写class WeatherAgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] city: Optional[str] tool_result: Optional[str] final_answer: Optional[str]这两种写法都可以。对新手来说继承MessagesState更直观。八、定义模型from langchain_openai import ChatOpenAIllm ChatOpenAI(modelgpt-4o-mini, temperature0)llm_with_tools llm.bind_tools([get_weather])这里的关键是bind_tools([get_weather])。绑定后模型就具备了“按工具 schema 发起工具调用”的能力。九、定义第一个节点Agent 决策节点这个节点的职责是读取当前消息让模型判断要不要调用get_weather把模型输出追加回messagesfrom langchain.messages import SystemMessagedef agent_node(state: WeatherAgentState): system_prompt SystemMessage( content( 你是一个天气查询助手。 如果用户在询问天气并且提供了城市优先调用 get_weather 工具。 如果用户没有提供城市不要调用工具直接礼貌追问用户想查询哪个城市。 当已经拿到工具结果后请基于结果生成最终回答。 ) ) response llm_with_tools.invoke([system_prompt] state[messages]) return {messages: [response]}LangGraph 天气 Agent 最小代码结构示意图这里很多新手会疑惑“为什么这里只返回{messages: [response]}没有直接返回最终答案因为这个节点还只是“决策节点”。它的工作是让模型先决定要不要调工具还是直接回答真正执行工具是下一个节点的事情。这就是 LangGraph 的好处把“思考”和“行动”拆开。十、定义工具节点LangGraph 里处理工具调用最方便的方式是使用预置的ToolNode。from langgraph.prebuilt import ToolNodetool_node ToolNode([get_weather])它会自动读取上一条 AIMessage 里的 tool calls执行对应工具并把结果写回消息流。不过为了让新手更容易理解“发生了什么”我们再额外写一个节点把工具结果从消息里提取出来存进显式状态字段tool_result。十一、定义结果整理节点from langchain.messages import ToolMessagedef collect_tool_result_node(state: WeatherAgentState): last_message state[messages][-1] if isinstance(last_message, ToolMessage): return { tool_result: last_message.content } return {}这个节点的作用是从消息列表里取出最后一条消息如果它是ToolMessage说明刚刚执行过工具把工具返回值同步到tool_result这一步不是必须的但对新手理解 State 很有帮助消息流是一种状态显式字段也是一种状态。十二、定义最终回答节点工具结果拿到了接下来就让模型把它组织成对用户友好的回答。def respond_node(state: WeatherAgentState): tool_result state.get(tool_result, ) user_question state[messages][0].content if state[messages] else prompt [ SystemMessage(content你是一个简洁、友好的天气助手请基于工具结果回答用户不要编造。), *state[messages] ] response llm.invoke(prompt) return { messages: [response], final_answer: response.content }这个节点会生成最终用户看到的内容并写入messagesfinal_answer十三、定义 Router决定下一步去哪这是 LangGraph 最关键的部分之一。我们希望流程是Agent 决策后如果模型发起工具调用 → 去工具节点如果模型没有工具调用 → 直接结束工具执行后 → 去收集结果节点收集完结果 → 再回到回答节点回答完成 → 结束先写判断函数def route_after_agent(state: WeatherAgentState): last_message state[messages][-1] if hasattr(last_message, tool_calls) and last_message.tool_calls: return tools return end这个 router 的逻辑非常简单如果 AIMessage 里有tool_calls说明模型决定调用工具那么下一步就走到tools否则直接结束注意这里的tools、end不是随便写的它们会映射到图里配置的节点或终点。十四、把整个图组装起来现在开始真正使用StateGraph。from langgraph.graph import StateGraph, START, ENDbuilder StateGraph(WeatherAgentState)builder.add_node(agent, agent_node)builder.add_node(tools, tool_node)builder.add_node(collect_tool_result, collect_tool_result_node)builder.add_node(respond, respond_node)builder.add_edge(START, agent)builder.add_conditional_edges( agent, route_after_agent, { tools: tools, end: END })builder.add_edge(tools, collect_tool_result)builder.add_edge(collect_tool_result, respond)builder.add_edge(respond, END)graph builder.compile()到这里一个最小可运行的天气 Agent 图就搭完了。十五、完整流程图解我们用文字流程图把它画出来START ↓agent让模型判断直接回答 or 调用工具 ├── 如果需要工具 → tools执行 get_weather │ ↓ │ collect_tool_result提取工具结果写入 state │ ↓ │ respond基于工具结果生成最终回答 │ ↓ │ END │ └── 如果不需要工具 → END如果你想把这个流程理解得更“运行时”一些可以看成这样用户发来“北京今天天气怎么样”agent节点读到消息模型判断这是天气问题需要调用get_weather(city北京)Router 检查到存在tool_calls图跳转到toolstools执行get_weather工具返回“晴22°C东北风 2 级”collect_tool_result把结果写入state[tool_result]respond基于工具结果生成自然语言答案图到达END这就是一个标准的“先判断再行动再生成答案”的 Agent 闭环。十六、运行示例from langchain.messages import HumanMessageresult graph.invoke({ messages: [HumanMessage(content北京今天天气怎么样)], city: None, tool_result: None, final_answer: None,})print(result[final_answer])print(result[messages][-1].content)你大概率会得到类似结果北京今天天气晴气温 22°C东北风 2 级。整体天气不错适合出行。十七、给你一份可以直接运行的完整代码下面把前面的代码拼成一份完整版本。from typing import Optionalfrom langchain.tools import toolfrom langchain_openai import ChatOpenAIfrom langchain.messages import HumanMessage, SystemMessage, ToolMessagefrom langgraph.graph import StateGraph, START, END, MessagesStatefrom langgraph.prebuilt import ToolNode# 1. 定义工具tooldef get_weather(city: str) - str: 查询指定城市的天气。输入必须是城市名。 mock_weather_data { 北京: 晴22°C东北风 2 级, 上海: 多云26°C东南风 3 级, 广州: 小雨29°C南风 2 级, 深圳: 阴28°C微风, } return mock_weather_data.get(city, f暂时没有 {city} 的天气数据)# 2. 定义状态class WeatherAgentState(MessagesState): city: Optional[str] tool_result: Optional[str] final_answer: Optional[str]# 3. 初始化模型llm ChatOpenAI(modelgpt-4o-mini, temperature0)llm_with_tools llm.bind_tools([get_weather])# 4. Agent 决策节点def agent_node(state: WeatherAgentState): system_prompt SystemMessage( content( 你是一个天气查询助手。 如果用户在询问天气并且提供了城市优先调用 get_weather 工具。 如果用户没有提供城市不要调用工具直接礼貌追问用户想查询哪个城市。 当已经拿到工具结果后请基于结果生成最终回答。 ) ) response llm_with_tools.invoke([system_prompt] state[messages]) return {messages: [response]}# 5. 工具节点tool_node ToolNode([get_weather])# 6. 提取工具结果节点def collect_tool_result_node(state: WeatherAgentState): last_message state[messages][-1] if isinstance(last_message, ToolMessage): return {tool_result: last_message.content} return {}# 7. 最终回答节点def respond_node(state: WeatherAgentState): prompt [ SystemMessage(content你是一个简洁、友好的天气助手请基于工具结果回答用户不要编造。), *state[messages] ] response llm.invoke(prompt) return { messages: [response], final_answer: response.content }# 8. Routerdef route_after_agent(state: WeatherAgentState): last_message state[messages][-1] if hasattr(last_message, tool_calls) and last_message.tool_calls: returntools returnend# 9. 构建图builder StateGraph(WeatherAgentState)builder.add_node(agent, agent_node)builder.add_node(tools, tool_node)builder.add_node(collect_tool_result, collect_tool_result_node)builder.add_node(respond, respond_node)builder.add_edge(START, agent)builder.add_conditional_edges( agent, route_after_agent, { tools: tools, end: END })builder.add_edge(tools, collect_tool_result)builder.add_edge(collect_tool_result, respond)builder.add_edge(respond, END)graph builder.compile()# 10. 运行result graph.invoke({ messages: [HumanMessage(content北京今天天气怎么样)], city: None, tool_result: None, final_answer: None,})print(最终答案, result[final_answer])十八、这段代码里LangGraph 概念分别对应哪里很多人代码能跑但脑子里还是不清楚图是怎么组成的。我们把代码和概念一一对上。1. State 对应哪里class WeatherAgentState(MessagesState): city: Optional[str] tool_result: Optional[str] final_answer: Optional[str]这就是共享状态定义。所有节点都围绕它读写。2. Node 对应哪里def agent_node(...):def collect_tool_result_node(...):def respond_node(...):tool_node ToolNode([get_weather])这些都是节点。其中ToolNode是 LangGraph 提供的预制节点。3. Edge 对应哪里builder.add_edge(START, agent)builder.add_edge(tools, collect_tool_result)builder.add_edge(collect_tool_result, respond)builder.add_edge(respond, END)这些是固定边表示确定的跳转关系。4. Router 对应哪里def route_after_agent(state): ...加上builder.add_conditional_edges(...)这就是条件路由。Agent 不是每次都去工具节点Router 会动态决定。5. 编译对应哪里graph builder.compile()官方文档明确提到StateGraph只是构建器必须compile()后才能invoke()。这点新手经常忘。十九、再进一步如果用户没给城市怎么办例如用户只问““今天天气怎么样”这时一个合格的天气 Agent 不应该盲调工具而应该先追问““请问你想查询哪个城市的天气”而我们的agent_node提示词里已经写了这个规则因此模型通常不会发起工具调用。执行流程会变成用户问“今天天气怎么样”agent判断缺少城市不调用工具Router 返回end图结束这个例子特别适合帮助你理解“Agent 的本质不是“必须调用工具”而是“有能力根据状态决定是否调用工具”。二十、想做成真正的循环 Agent应该怎么改上面的示例是一个“单次工具调用”的简化图。但 LangGraph 真正强大的地方在于它非常适合做循环。比如你可以改成下面这种结构START ↓agent ├── 调工具 → tools → agent └── 直接回答 → END这才是经典 Agent Loop模型先思考需要工具就调工具工具结果回来后再交给模型模型继续判断还要不要下一步不需要了才结束也就是说工具执行后不是必须进respond而是可以回到agent再做一次决策。这样做的好处是支持多个工具串联支持多轮工具调用更接近真实 Agent例如代码结构会变成builder.add_edge(tools, agent)而 Router 则继续判断有工具调用 → 继续工具节点没工具调用 → END这就是 LangGraph 为什么非常适合 Agent它天然支持循环而循环正是 Agent 的典型运行形态。二十一、新手最常见的 5 个坑坑 1把 State 当成普通入参很多人会写出这样的思路节点 A 返回一个字符串节点 B 接收这个字符串这更像普通函数调用不是 LangGraph 的核心用法。LangGraph 里更推荐的思路是所有节点围绕共享 State 工作节点返回 Partial State 更新坑 2忘了compile()StateGraph只是图构建器。真正可执行的是编译后的 graph。错误思路builder.invoke(...)正确思路graph builder.compile()graph.invoke(...)坑 3搞不清消息和状态字段的关系很多人问““既然messages里已经有工具结果了为什么还要tool_result”答案是不一定要。但显式字段有两个好处更利于调试更利于后续节点直接读取结构化信息所以小 Demo 里你可以只用messages真正项目里常常会额外维护结构化 State 字段坑 4把 Router 理解成模型Router 不是模型。Router 是你写的一个普通 Python 函数用来根据状态决定下一跳。模型负责“思考”。Router 负责“跳线”。坑 5以为 ToolNode 会自动帮你完成所有业务状态更新ToolNode很方便但它主要处理的是读取工具调用执行工具把结果写回消息如果你想把工具结果同步到自己的业务字段比如weather_jsoncityrisk_level那通常还需要额外节点或让工具返回更结构化的数据。二十二、怎么把模拟工具换成真实天气 API当你已经跑通这个示例后升级非常简单。只要改get_weather()就行图结构几乎不用动。例如import requestsfrom langchain.tools import tooltooldef get_weather(city: str) - str: 查询指定城市的天气。输入必须是城市名。 # 伪代码替换为你自己的天气接口 resp requests.get(https://your-weather-api.com/weather, params{city: city}) data resp.json() return f{city}{data[weather]}{data[temp]}°C{data[wind]}这正是 LangGraph 的另一个优点“工作流编排和具体工具实现是解耦的。你可以先把图跑通再逐步把模拟工具替换成真实工具。二十三、如果你想继续升级这 4 个方向最值得学当你学会这个天气 Agent 后下一步建议你按这个顺序进阶。1. 做成循环 Agent让tools - agent而不是直接去respond。这样你会真正理解 Agent Loop。2. 给 State 增加更多业务字段例如intentlocationneed_forecastretry_count这样你会开始体会“有状态工作流”的价值。3. 接入持久化与记忆LangGraph 官方文档把持久化、长执行恢复、记忆都作为核心能力。当你的 Agent 需要多轮对话或中断恢复时这会非常重要。4. 接入 LangSmith 做可观测性一旦图变复杂仅靠 print 很难调试。可视化节点执行路径、状态变化和耗时是 LangGraph 进入生产实践的重要一环。二十四、最后用一句话把 LangGraph 讲明白如果你读到这里还有点模糊我给你一个最适合新手记住的定义“LangGraph 就是把 Agent 的思考、工具调用、分支决策和状态管理组织成一个可执行图。在这个图里State负责记住当前进展Node负责执行某一步逻辑Router/Conditional Edge负责决定下一步去哪Loop负责让 Agent 可以反复思考和行动直到任务完成而天气查询 Agent正是理解这一切的最佳入门案例。因为它足够简单却完整包含了 Agent 的核心结构用户提问模型判断工具调用状态更新最终回复当你真正把这个例子跑通你对 LangGraph 的理解就不再停留在“看过概念”而是已经建立起了最关键的直觉。二十五、本文小结我们今天完成了 3 件事理解了 LangGraph 的核心概念State 是共享状态Node 是处理步骤Router 是下一跳决策函数搭建了一个完整的天气查询 Agent用户问天气Agent 判断是否调用工具工具返回结果最终生成回答明白了为什么 LangGraph 比普通链更适合 Agent它不是只做顺序调用它擅长有状态、可分支、可循环的工作流这正是 Agent 的天然形态如果你接下来想真正从“会跑 Demo”进阶到“会设计 Agent”建议你马上做两个练习把天气工具改成真实 API把流程改成agent - tools - agent的循环结构只要你亲手做完这两步LangGraph 的门就算真正入了。假如你从2026年开始学大模型按这个步骤走准能稳步进阶。接下来告诉你一条最快的邪修路线3个月即可成为模型大师薪资直接起飞。阶段1:大模型基础阶段2:RAG应用开发工程阶段3:大模型Agent应用架构阶段4:大模型微调与私有化部署配套文档资源全套AI 大模型 学习资料朋友们如果需要可以微信扫描下方二维码免费领取【保证100%免费】配套文档资源全套AI 大模型 学习资料朋友们如果需要可以微信扫描下方二维码免费领取【保证100%免费】
从“让大模型回答问题“到智能决策:LangGraph 构建 AI Agent 的核心奥秘
发布时间:2026/5/20 10:59:08
本文深入解析了 AI Agent 的核心价值在于判断与决策而非简单回答问题。LangGraph 作为图式工作流框架通过 State共享状态、Node处理节点、Router决策分支的设计完美契合 Agent 的有状态、分支、循环特性。文章以最小天气查询 Agent 为例详细展示了如何利用 LangGraph 实现用户输入→模型判断→工具调用→状态更新→最终回复的完整闭环并对比了 LangGraph 与普通链式调用的差异强调其在复杂流程、循环交互、持久化等方面的优势。通过搭建可运行的示例帮助读者直观理解 LangGraph 的核心概念和 Agent 的构建逻辑为进阶设计复杂 Agent 提供了清晰的实践路径。如果你刚开始学 AI Agent很容易把它理解成“让大模型回答问题”。但真正的 Agent关键不只是“回答”而是它会先判断再决定要不要调用工具拿到工具结果后继续往下走最后再输出答案。这类流程如果只靠普通链式调用来写通常会越来越乱输入进来先调用模型如果模型说要查天气就再调一次工具工具结果回来再调一次模型如果工具失败可能还要重试如果用户没说城市还得补问。流程一复杂代码就会开始到处塞 if/else。这正是 LangGraph 的价值所在。根据 LangGraph 官方文档它本质上是一个“图式工作流框架”State共享状态保存当前运行快照Node处理逻辑节点读取状态并返回状态更新Edge决定接下来执行哪个节点StateGraph把这些节点和边编译成可执行图图编译后可以invoke()、stream()、异步执行并且天然适合有循环、分支、工具调用、持久化和人工介入的 Agent 流程官方文档还特别强调LangGraph 是面向有状态、可循环、可恢复执行的 Agent 编排运行时而不只是把多个步骤简单串起来。这也是它比普通链更适合 Agent 的核心原因。这篇文章我们就从零开始搭一个最小可运行的天气查询 Agent让你真正理解什么是State什么是Node什么是Router为什么 Agent 天然适合用LangGraph一个“用户问天气 → Agent 决策 → 调用工具 → 返回答案”的完整执行流程是怎么跑起来的一、先理解LangGraph 到底在解决什么问题先看一个最简单的用户请求““北京今天天气怎么样”对于这个问题一个真正的 Agent 不应该一上来就瞎答而应该经历下面的过程接收用户消息判断这是不是一个需要工具的问题如果需要提取城市名比如“北京”调用天气工具拿到天气结果再组织成自然语言回复用户LangGraph 天气查询 Agent 的完整执行流程图注意这里面不是单次“输入→输出”而是一个带状态的多步决策过程。如果以后再扩展一下需求比如如果用户没说城市要追问如果天气接口报错要重试如果用户还问“顺便告诉我穿衣建议”还要继续推理如果要支持多轮对话还得保留消息历史这已经明显不是简单 Prompt 能优雅解决的问题了。LangGraph 的思路是把 Agent 看成一个状态机state machine或图graph。每一个步骤是一个节点每一次跳转由边来控制而所有节点共享同一个状态。二、新手最容易混淆的 3 个概念State、Node、Router这是初学 LangGraph 最容易绕晕的地方我们先讲透。1. State当前运行过程中的“共享记忆”你可以把 State 理解成 Agent 在这一轮执行中随身带着的一份工作记录。例如我们的天气 AgentState 里可以放这些信息messages对话消息列表city解析出的城市tool_result天气工具返回的数据final_answer最终输出给用户的答案在 LangGraph 官方 Graph API 中State 的核心特点是所有节点都能读它节点执行后返回的是Partial State也就是“我只更新其中一部分字段”图运行时会把这些更新合并回共享状态中也就是说Node 不是直接“打印结果”而是“修改状态”。2. Node一个处理步骤Node 本质就是一个函数。它接收当前状态做一些逻辑处理然后返回要更新的字段。例如agent_node让大模型判断是否需要调用工具tool_node真正执行天气查询respond_node根据工具结果生成最终答案所以你可以把 Node 理解成“Agent 工作流中的一个“处理站”3. Router决定下一步去哪Router 不是一个独立的官方类名而是开发中常见的说法。通常指的是根据当前状态决定图接下来走哪条边的函数。例如如果模型已经发起了工具调用 → 去tool_node如果模型已经可以直接回答 → 去respond_node如果执行结束了 → 去END在 LangGraph 里这类逻辑一般通过add_conditional_edges()来实现。所以最直白的理解是State现在手里有哪些信息Node当前这一步要做什么Router下一步该去哪里State、Node、Router 三个概念的对比关系图三、为什么 LangGraph 适合 Agent而不只是普通链式调用很多人第一次接触 LangGraph 时会问““我直接写一个链不也能先 LLM、再工具、再 LLM 吗”可以但两者适合的场景不同。普通链式调用更像流水线链式调用通常适合步骤固定基本没有分支不需要循环不需要状态长期保存不需要失败恢复例如用户输入 → 提取关键词 → 总结结果 → 输出这种很适合链。Agent 更像“动态决策流程”Agent 的特点是是否调用工具运行时才知道调用哪个工具运行时才知道可能会循环多轮思考 → 调工具 → 再思考可能需要中断、恢复、回放可能需要保留复杂状态而 LangGraph 官方文档强调的优势正是这些Durable execution长流程可以持久化与恢复Human-in-the-loop中途人工介入Stateful天然管理状态Streaming / Debugging / Observability适合生产级 Agent 追踪和调试一句话总结“普通链擅长“固定步骤”LangGraph 擅长“会分支、会循环、会调用工具的有状态 Agent”。LangGraph 与普通链式调用的对比图四、先搭一个最小版天气 Agent下面我们用 Python LangGraph 搭一个完整示例。为了聚焦 LangGraph 核心概念这里天气工具先用模拟数据不接真实天气 API。等你跑通流程后再把工具替换成真实接口即可。五、安装依赖pip install -U langgraph langchain langchain-openai如果你用 OpenAI 模型还需要配置环境变量export OPENAI_API_KEY你的_keyWindows PowerShell:setx OPENAI_API_KEY 你的_key六、定义天气工具先定义一个最简单的工具。LangChain 官方 Tools 文档中推荐使用tool装饰器定义工具这也是 LangGraph 里最常见的工具接入方式。from langchain.tools import tooltooldef get_weather(city: str) - str: 查询指定城市的天气。输入必须是城市名。 mock_weather_data { 北京: 晴22°C东北风 2 级, 上海: 多云26°C东南风 3 级, 广州: 小雨29°C南风 2 级, 深圳: 阴28°C微风, } return mock_weather_data.get(city, f暂时没有 {city} 的天气数据)这里先不追求真实而是先把“工具调用”这个动作建立起来。七、定义 StateLangGraph 官方 Graph API 文档推荐使用TypedDict或 Pydantic 来定义状态。如果你的工作流围绕消息展开还可以使用MessagesState。我们的例子正好是聊天场景所以直接继承MessagesState最省事。from typing import Annotated, TypedDict, Optionalfrom langgraph.graph import MessagesStatefrom langgraph.graph.message import add_messagesfrom langchain.messages import AnyMessageclass WeatherAgentState(MessagesState): city: Optional[str] tool_result: Optional[str] final_answer: Optional[str]这里要注意MessagesState已经帮你准备好了messagesmessages会以适合消息场景的方式合并我们额外补充了city、tool_result、final_answer你也可以不继承MessagesState手写class WeatherAgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] city: Optional[str] tool_result: Optional[str] final_answer: Optional[str]这两种写法都可以。对新手来说继承MessagesState更直观。八、定义模型from langchain_openai import ChatOpenAIllm ChatOpenAI(modelgpt-4o-mini, temperature0)llm_with_tools llm.bind_tools([get_weather])这里的关键是bind_tools([get_weather])。绑定后模型就具备了“按工具 schema 发起工具调用”的能力。九、定义第一个节点Agent 决策节点这个节点的职责是读取当前消息让模型判断要不要调用get_weather把模型输出追加回messagesfrom langchain.messages import SystemMessagedef agent_node(state: WeatherAgentState): system_prompt SystemMessage( content( 你是一个天气查询助手。 如果用户在询问天气并且提供了城市优先调用 get_weather 工具。 如果用户没有提供城市不要调用工具直接礼貌追问用户想查询哪个城市。 当已经拿到工具结果后请基于结果生成最终回答。 ) ) response llm_with_tools.invoke([system_prompt] state[messages]) return {messages: [response]}LangGraph 天气 Agent 最小代码结构示意图这里很多新手会疑惑“为什么这里只返回{messages: [response]}没有直接返回最终答案因为这个节点还只是“决策节点”。它的工作是让模型先决定要不要调工具还是直接回答真正执行工具是下一个节点的事情。这就是 LangGraph 的好处把“思考”和“行动”拆开。十、定义工具节点LangGraph 里处理工具调用最方便的方式是使用预置的ToolNode。from langgraph.prebuilt import ToolNodetool_node ToolNode([get_weather])它会自动读取上一条 AIMessage 里的 tool calls执行对应工具并把结果写回消息流。不过为了让新手更容易理解“发生了什么”我们再额外写一个节点把工具结果从消息里提取出来存进显式状态字段tool_result。十一、定义结果整理节点from langchain.messages import ToolMessagedef collect_tool_result_node(state: WeatherAgentState): last_message state[messages][-1] if isinstance(last_message, ToolMessage): return { tool_result: last_message.content } return {}这个节点的作用是从消息列表里取出最后一条消息如果它是ToolMessage说明刚刚执行过工具把工具返回值同步到tool_result这一步不是必须的但对新手理解 State 很有帮助消息流是一种状态显式字段也是一种状态。十二、定义最终回答节点工具结果拿到了接下来就让模型把它组织成对用户友好的回答。def respond_node(state: WeatherAgentState): tool_result state.get(tool_result, ) user_question state[messages][0].content if state[messages] else prompt [ SystemMessage(content你是一个简洁、友好的天气助手请基于工具结果回答用户不要编造。), *state[messages] ] response llm.invoke(prompt) return { messages: [response], final_answer: response.content }这个节点会生成最终用户看到的内容并写入messagesfinal_answer十三、定义 Router决定下一步去哪这是 LangGraph 最关键的部分之一。我们希望流程是Agent 决策后如果模型发起工具调用 → 去工具节点如果模型没有工具调用 → 直接结束工具执行后 → 去收集结果节点收集完结果 → 再回到回答节点回答完成 → 结束先写判断函数def route_after_agent(state: WeatherAgentState): last_message state[messages][-1] if hasattr(last_message, tool_calls) and last_message.tool_calls: return tools return end这个 router 的逻辑非常简单如果 AIMessage 里有tool_calls说明模型决定调用工具那么下一步就走到tools否则直接结束注意这里的tools、end不是随便写的它们会映射到图里配置的节点或终点。十四、把整个图组装起来现在开始真正使用StateGraph。from langgraph.graph import StateGraph, START, ENDbuilder StateGraph(WeatherAgentState)builder.add_node(agent, agent_node)builder.add_node(tools, tool_node)builder.add_node(collect_tool_result, collect_tool_result_node)builder.add_node(respond, respond_node)builder.add_edge(START, agent)builder.add_conditional_edges( agent, route_after_agent, { tools: tools, end: END })builder.add_edge(tools, collect_tool_result)builder.add_edge(collect_tool_result, respond)builder.add_edge(respond, END)graph builder.compile()到这里一个最小可运行的天气 Agent 图就搭完了。十五、完整流程图解我们用文字流程图把它画出来START ↓agent让模型判断直接回答 or 调用工具 ├── 如果需要工具 → tools执行 get_weather │ ↓ │ collect_tool_result提取工具结果写入 state │ ↓ │ respond基于工具结果生成最终回答 │ ↓ │ END │ └── 如果不需要工具 → END如果你想把这个流程理解得更“运行时”一些可以看成这样用户发来“北京今天天气怎么样”agent节点读到消息模型判断这是天气问题需要调用get_weather(city北京)Router 检查到存在tool_calls图跳转到toolstools执行get_weather工具返回“晴22°C东北风 2 级”collect_tool_result把结果写入state[tool_result]respond基于工具结果生成自然语言答案图到达END这就是一个标准的“先判断再行动再生成答案”的 Agent 闭环。十六、运行示例from langchain.messages import HumanMessageresult graph.invoke({ messages: [HumanMessage(content北京今天天气怎么样)], city: None, tool_result: None, final_answer: None,})print(result[final_answer])print(result[messages][-1].content)你大概率会得到类似结果北京今天天气晴气温 22°C东北风 2 级。整体天气不错适合出行。十七、给你一份可以直接运行的完整代码下面把前面的代码拼成一份完整版本。from typing import Optionalfrom langchain.tools import toolfrom langchain_openai import ChatOpenAIfrom langchain.messages import HumanMessage, SystemMessage, ToolMessagefrom langgraph.graph import StateGraph, START, END, MessagesStatefrom langgraph.prebuilt import ToolNode# 1. 定义工具tooldef get_weather(city: str) - str: 查询指定城市的天气。输入必须是城市名。 mock_weather_data { 北京: 晴22°C东北风 2 级, 上海: 多云26°C东南风 3 级, 广州: 小雨29°C南风 2 级, 深圳: 阴28°C微风, } return mock_weather_data.get(city, f暂时没有 {city} 的天气数据)# 2. 定义状态class WeatherAgentState(MessagesState): city: Optional[str] tool_result: Optional[str] final_answer: Optional[str]# 3. 初始化模型llm ChatOpenAI(modelgpt-4o-mini, temperature0)llm_with_tools llm.bind_tools([get_weather])# 4. Agent 决策节点def agent_node(state: WeatherAgentState): system_prompt SystemMessage( content( 你是一个天气查询助手。 如果用户在询问天气并且提供了城市优先调用 get_weather 工具。 如果用户没有提供城市不要调用工具直接礼貌追问用户想查询哪个城市。 当已经拿到工具结果后请基于结果生成最终回答。 ) ) response llm_with_tools.invoke([system_prompt] state[messages]) return {messages: [response]}# 5. 工具节点tool_node ToolNode([get_weather])# 6. 提取工具结果节点def collect_tool_result_node(state: WeatherAgentState): last_message state[messages][-1] if isinstance(last_message, ToolMessage): return {tool_result: last_message.content} return {}# 7. 最终回答节点def respond_node(state: WeatherAgentState): prompt [ SystemMessage(content你是一个简洁、友好的天气助手请基于工具结果回答用户不要编造。), *state[messages] ] response llm.invoke(prompt) return { messages: [response], final_answer: response.content }# 8. Routerdef route_after_agent(state: WeatherAgentState): last_message state[messages][-1] if hasattr(last_message, tool_calls) and last_message.tool_calls: returntools returnend# 9. 构建图builder StateGraph(WeatherAgentState)builder.add_node(agent, agent_node)builder.add_node(tools, tool_node)builder.add_node(collect_tool_result, collect_tool_result_node)builder.add_node(respond, respond_node)builder.add_edge(START, agent)builder.add_conditional_edges( agent, route_after_agent, { tools: tools, end: END })builder.add_edge(tools, collect_tool_result)builder.add_edge(collect_tool_result, respond)builder.add_edge(respond, END)graph builder.compile()# 10. 运行result graph.invoke({ messages: [HumanMessage(content北京今天天气怎么样)], city: None, tool_result: None, final_answer: None,})print(最终答案, result[final_answer])十八、这段代码里LangGraph 概念分别对应哪里很多人代码能跑但脑子里还是不清楚图是怎么组成的。我们把代码和概念一一对上。1. State 对应哪里class WeatherAgentState(MessagesState): city: Optional[str] tool_result: Optional[str] final_answer: Optional[str]这就是共享状态定义。所有节点都围绕它读写。2. Node 对应哪里def agent_node(...):def collect_tool_result_node(...):def respond_node(...):tool_node ToolNode([get_weather])这些都是节点。其中ToolNode是 LangGraph 提供的预制节点。3. Edge 对应哪里builder.add_edge(START, agent)builder.add_edge(tools, collect_tool_result)builder.add_edge(collect_tool_result, respond)builder.add_edge(respond, END)这些是固定边表示确定的跳转关系。4. Router 对应哪里def route_after_agent(state): ...加上builder.add_conditional_edges(...)这就是条件路由。Agent 不是每次都去工具节点Router 会动态决定。5. 编译对应哪里graph builder.compile()官方文档明确提到StateGraph只是构建器必须compile()后才能invoke()。这点新手经常忘。十九、再进一步如果用户没给城市怎么办例如用户只问““今天天气怎么样”这时一个合格的天气 Agent 不应该盲调工具而应该先追问““请问你想查询哪个城市的天气”而我们的agent_node提示词里已经写了这个规则因此模型通常不会发起工具调用。执行流程会变成用户问“今天天气怎么样”agent判断缺少城市不调用工具Router 返回end图结束这个例子特别适合帮助你理解“Agent 的本质不是“必须调用工具”而是“有能力根据状态决定是否调用工具”。二十、想做成真正的循环 Agent应该怎么改上面的示例是一个“单次工具调用”的简化图。但 LangGraph 真正强大的地方在于它非常适合做循环。比如你可以改成下面这种结构START ↓agent ├── 调工具 → tools → agent └── 直接回答 → END这才是经典 Agent Loop模型先思考需要工具就调工具工具结果回来后再交给模型模型继续判断还要不要下一步不需要了才结束也就是说工具执行后不是必须进respond而是可以回到agent再做一次决策。这样做的好处是支持多个工具串联支持多轮工具调用更接近真实 Agent例如代码结构会变成builder.add_edge(tools, agent)而 Router 则继续判断有工具调用 → 继续工具节点没工具调用 → END这就是 LangGraph 为什么非常适合 Agent它天然支持循环而循环正是 Agent 的典型运行形态。二十一、新手最常见的 5 个坑坑 1把 State 当成普通入参很多人会写出这样的思路节点 A 返回一个字符串节点 B 接收这个字符串这更像普通函数调用不是 LangGraph 的核心用法。LangGraph 里更推荐的思路是所有节点围绕共享 State 工作节点返回 Partial State 更新坑 2忘了compile()StateGraph只是图构建器。真正可执行的是编译后的 graph。错误思路builder.invoke(...)正确思路graph builder.compile()graph.invoke(...)坑 3搞不清消息和状态字段的关系很多人问““既然messages里已经有工具结果了为什么还要tool_result”答案是不一定要。但显式字段有两个好处更利于调试更利于后续节点直接读取结构化信息所以小 Demo 里你可以只用messages真正项目里常常会额外维护结构化 State 字段坑 4把 Router 理解成模型Router 不是模型。Router 是你写的一个普通 Python 函数用来根据状态决定下一跳。模型负责“思考”。Router 负责“跳线”。坑 5以为 ToolNode 会自动帮你完成所有业务状态更新ToolNode很方便但它主要处理的是读取工具调用执行工具把结果写回消息如果你想把工具结果同步到自己的业务字段比如weather_jsoncityrisk_level那通常还需要额外节点或让工具返回更结构化的数据。二十二、怎么把模拟工具换成真实天气 API当你已经跑通这个示例后升级非常简单。只要改get_weather()就行图结构几乎不用动。例如import requestsfrom langchain.tools import tooltooldef get_weather(city: str) - str: 查询指定城市的天气。输入必须是城市名。 # 伪代码替换为你自己的天气接口 resp requests.get(https://your-weather-api.com/weather, params{city: city}) data resp.json() return f{city}{data[weather]}{data[temp]}°C{data[wind]}这正是 LangGraph 的另一个优点“工作流编排和具体工具实现是解耦的。你可以先把图跑通再逐步把模拟工具替换成真实工具。二十三、如果你想继续升级这 4 个方向最值得学当你学会这个天气 Agent 后下一步建议你按这个顺序进阶。1. 做成循环 Agent让tools - agent而不是直接去respond。这样你会真正理解 Agent Loop。2. 给 State 增加更多业务字段例如intentlocationneed_forecastretry_count这样你会开始体会“有状态工作流”的价值。3. 接入持久化与记忆LangGraph 官方文档把持久化、长执行恢复、记忆都作为核心能力。当你的 Agent 需要多轮对话或中断恢复时这会非常重要。4. 接入 LangSmith 做可观测性一旦图变复杂仅靠 print 很难调试。可视化节点执行路径、状态变化和耗时是 LangGraph 进入生产实践的重要一环。二十四、最后用一句话把 LangGraph 讲明白如果你读到这里还有点模糊我给你一个最适合新手记住的定义“LangGraph 就是把 Agent 的思考、工具调用、分支决策和状态管理组织成一个可执行图。在这个图里State负责记住当前进展Node负责执行某一步逻辑Router/Conditional Edge负责决定下一步去哪Loop负责让 Agent 可以反复思考和行动直到任务完成而天气查询 Agent正是理解这一切的最佳入门案例。因为它足够简单却完整包含了 Agent 的核心结构用户提问模型判断工具调用状态更新最终回复当你真正把这个例子跑通你对 LangGraph 的理解就不再停留在“看过概念”而是已经建立起了最关键的直觉。二十五、本文小结我们今天完成了 3 件事理解了 LangGraph 的核心概念State 是共享状态Node 是处理步骤Router 是下一跳决策函数搭建了一个完整的天气查询 Agent用户问天气Agent 判断是否调用工具工具返回结果最终生成回答明白了为什么 LangGraph 比普通链更适合 Agent它不是只做顺序调用它擅长有状态、可分支、可循环的工作流这正是 Agent 的天然形态如果你接下来想真正从“会跑 Demo”进阶到“会设计 Agent”建议你马上做两个练习把天气工具改成真实 API把流程改成agent - tools - agent的循环结构只要你亲手做完这两步LangGraph 的门就算真正入了。假如你从2026年开始学大模型按这个步骤走准能稳步进阶。接下来告诉你一条最快的邪修路线3个月即可成为模型大师薪资直接起飞。阶段1:大模型基础阶段2:RAG应用开发工程阶段3:大模型Agent应用架构阶段4:大模型微调与私有化部署配套文档资源全套AI 大模型 学习资料朋友们如果需要可以微信扫描下方二维码免费领取【保证100%免费】配套文档资源全套AI 大模型 学习资料朋友们如果需要可以微信扫描下方二维码免费领取【保证100%免费】