langgraph教程系列-01-为什么需要图-从链到图
本文是「LangGraph 教程系列」第 1 篇。写作时基于 langgraph 1.2.10、langchain 1.3.14、langchain-deepseek 1.1.0、Python 3.12。配套代码仓库 https://github.com/wxj006007/deep-research-assistant 本篇对应 tagv0。这个系列要做一件事带你亲手把一个「深度研究助手」从 v0 养到 v5。它一开始只会直接回答问题最后能联网检索、接受人类审批、跨会话记忆、多专家协作、部署成 API。每一篇的节奏都一样上一版撞了什么墙这一版用 LangGraph 的哪个特性把墙拆掉。特性不是硬塞给你的是助手自己「长」出来的需求。今天是第 1 篇我们先把 v0 跑起来。而且要跑两遍一遍用链一遍用图。跑完你就能亲手摸到「从链到图」的差异在哪。一、你可能听过 LangChain 的 chain 写法不需要你熟悉 LangChain只需要知道一个背景。LangChain 是 LangGraph 的前代产品同一家公司LangChain Inc.出品它最出圈的抽象叫 chain链把提示词、模型、输出解析器像水管一样串起来数据从左往右流。这种写法有个正式名字叫 LCELLangChain Expression Language核心就是一个管道符chainprompt|llm|parser优雅、直观、一行搞定。那为什么同一家公司后来又做了 LangGraph 呢坦率的讲因为链有一个天生的限制数据只能单向流动流程不能回头也不能分叉。先别急着理解这句话我们把 v0 写出来跑完再回头看。二、v0一个只会直接回答的研究助手v0 的需求简单到不能再简单用户提一个问题助手直接回答。没有检索、没有反思、没有任何花活。流程只有一步用户问题调用模型回答2.1 环境准备pipinstalllanggraph1.2.10langchain1.3.14 langchain-deepseek1.1.0 python-dotenv模型用 DeepSeek在 platform.deepseek.com 申请 API Key写进.env的DEEPSEEK_API_KEY。整个系列共用一个模型工厂# src/llm.pyfromdotenvimportload_dotenvfromlangchain_deepseekimportChatDeepSeek load_dotenv()defget_llm(temperature:float0.0)-ChatDeepSeek:returnChatDeepSeek(modeldeepseek-chat,temperaturetemperature)2.2 用 LCEL 写 v0# src/v0_chain.pyfromlangchain_core.output_parsersimportStrOutputParserfromlangchain_core.promptsimportChatPromptTemplatefromsrc.llmimportget_llm promptChatPromptTemplate.from_messages([(system,你是一个研究助手请直接、准确地回答用户的问题。),(human,{question}),])chainprompt|get_llm()|StrOutputParser()answerchain.invoke({question:什么是 LangGraph})print(answer)三个组件一根管道数据从prompt流到llm再流到parser一路向右绝不回头。对 v0 这种「一步到位」的需求链是完美的。2.3 用 LangGraph 写 v0现在用 LangGraph 把完全相同的功能再写一遍。LangGraph 的世界里只有三件套State状态一个共享的数据结构流程中所有步骤都读写它Node节点一个普通的 Python 函数读 state、干一件事、返回要更新的字段Edge边声明节点之间谁先谁后# src/v0_graph.pyfromtypingimportTypedDictfromlanggraph.graphimportEND,START,StateGraphfromsrc.llmimportget_llm# State整个图共享的状态classResearchState(TypedDict):question:stranswer:str# Node一个普通函数就是一个节点defanswer_node(state:ResearchState)-dict:llmget_llm()responsellm.invoke([(system,你是一个研究助手请直接、准确地回答用户的问题。),(human,state[question]),])# 节点只返回要更新的字段LangGraph 负责合并进 statereturn{answer:response.content}# Edge把节点连成图builderStateGraph(ResearchState)builder.add_node(answer,answer_node)builder.add_edge(START,answer)builder.add_edge(answer,END)graphbuilder.compile()resultgraph.invoke({question:什么是 LangGraph})print(result[answer])跑一下两个版本的输出几乎一样但代码量明显变多了。可能有小伙伴纳闷这不是退步吗三、图到底比链强在哪3.1 先承认v0 用图是杀鸡用牛刀对单步流程图写法确实更啰嗦。LCEL 一行管道LangGraph 要定义 State、写节点函数、连边、编译四道工序。这一点我不打算辩护说实话如果你的需求永远停留在单步问答用链一点问题没有。但注意两个写法的结构性差异维度链LCEL图LangGraph数据传递上一步的输出直接塞给下一步所有步骤读写同一个共享 State流程形状一条直线方向固定任意拓扑边可以指向任何节点流程控制结构即控制写死在管道里边是显式声明的可以按条件选择回到之前的步骤不可能加一条回指的边就行链的「输出直接喂给下一步」听着省事代价是第 3 步只能看到第 2 步的输出看不到第 1 步的。图的共享 State 不一样任何节点都能看到之前所有节点留下的信息。链的「结构即控制」呢流程在写代码时就定死了。图把边做成显式声明那结果会怎样呢下一步去哪可以在运行时根据 State 决定。这就是下一篇要讲的条件边。3.2 三种范式链、循环、图把流程组织方式抽象一下其实是三个层次图任意拓扑节点A路由节点B节点C节点D循环能回头否是执行满意?结束链单向流水线步骤1步骤2步骤3链能表达「依次做」循环能表达「不满意就重做」图能表达依次做、按条件分叉、不满意重做的任意组合。你想想看链和循环其实都只是图的特例。一个真正的 Agent 需要什么判断、分叉、重试、回头反思这些全是图才有的能力。LangChain Inc. 自己从 chain 走到 graph 的产品演进就是「从链到图」这个标题的最佳注脚先用链把「把 LLM 组件串起来」这件事做顺然后发现严肃的 Agent 场景需要的是图。顺带一提如果你把「节点」换成「工序」这个演进你在历史课本里见过。手工作坊是一条链一个人从头做到尾。流水线引入了固定分工的循环。现代供应链则是一张动态调度的图。生产组织方式的演进和 Agent 编排方式的演进走的是同一条路复杂度到了结构就得升级。3.3 那 v0 为什么还要用图写一遍因为 v0 不会停在 v0。我们的研究助手马上要面对的现实是事实型问题和分析型问题该用不同的回答策略v0.1流程要分叉检索结果要累积不能覆盖v0.2状态要合并答案不满意要回头重查v1流程要循环。如果 v0 用链写每次进化都要推翻重来。用图写每次进化只是加节点、加边State、Node、Edge 三件套不变。这就是我们在最简单的版本就切换到 LangGraph 的原因不是 v0 需要图是 v1、v2、v3 需要。四、本篇小结回到「从链到图」这块这篇其实就讲了一件事。链是prompt | llm | parser式的单向流水线适合定死的流程。图用 State、Node、Edge 三件套描述任意拓扑链和循环都只是它的特例Agent 需要的判断、分叉、重试只有图能表达。另外有一个约定值得你现在就记牢节点不修改 state只返回要更新的字段合并交给框架。第 3 篇讲 reducer 时它是主角。v0 已经能跑了但它有个毛病。不管你问「LangGraph 是哪家公司开源的」还是「为什么 Agent 框架都在转向图结构」它都用同一套提示词硬答事实型问题答得啰嗦分析型问题答得草率。流程需要分叉。下一篇条件边登场。赞或收藏 关注 我们下次再见

相关新闻