langgraph教程系列-02-让流程分叉-条件边与路由

发布时间:2026/9/15 23:50:40

langgraph教程系列-02-让流程分叉-条件边与路由 本文是「LangGraph 教程系列」第 2 篇。写作时基于 langgraph 1.2.10、langchain 1.3.14、langchain-deepseek 1.1.0、Python 3.12。配套代码仓库 https://github.com/wxj006007/deep-research-assistant 本篇对应 tagv0.1。上一篇我们用 State / Node / Edge 三件套把 v0 跑了起来还立了个 flag链和循环都是图的特例Agent 需要的判断和分叉只有图能表达。这一篇就来兑现「分叉」。一、v0 撞的墙一条道走到黑给 v0 提两个问题LangGraph 是哪家公司开源的为什么 Agent 框架纷纷从链式结构转向图结构第一个是事实型问题有客观标准答案好的回答应该准确、简短。LangChain Inc.完事。第二个是分析型问题没有标准答案好的回答应该多角度展开、给出推理过程。但 v0 只有一个answer节点、一套系统提示词。结果就是两头不讨好事实型问题它答出一篇小作文分析型问题它草率地丢一个结论。你想想看「简洁准确」和「充分展开」这两个目标本身就是矛盾的一套提示词没法同时优化。解法很自然先判断问题类型再走不同的分支。这在链里做不到管道在写代码时就焊死了。在图里这就是一条条件边conditional edge。二、v0.1 的图结构factualanalyticalSTARTclassify判断问题类型factual_answer简洁准确地回答analytical_answer多角度展开分析END实线是普通边必然走虚线是条件边运行时二选一。整个 v0.1 相比 v0 的变化answer节点一分为二前面加了一个classify节点中间用条件边接起来。三、动手实现3.1 State加一个字段classResearchState(TypedDict):question:strquestion_type:str# factual | analyticalanswer:str相比 v0 只多了question_type。分类结果要写进 state因为路由的依据必须存在于 state 里。这是 LangGraph 的基本纪律节点之间不直接传参一切经过 state。3.2 分类节点让 LLM 当裁判defclassify_node(state:ResearchState)-dict:llmget_llm()responsellm.invoke([(system,你是一个问题分类器。判断用户问题属于哪一类\n- factual有客观标准答案的事实型问题是什么、何时、多少\n- analytical需要推理和多角度讨论的分析型问题为什么、如何评价、利弊\n只输出 factual 或 analytical 这一个单词不要输出其他内容。),(human,state[question]),])labelresponse.content.strip().lower()# 兜底分类器输出意外内容时按分析型处理iflabelnotin(factual,analytical):labelanalyticalreturn{question_type:label}这里有两个工程细节。一个是强约束输出提示词里写死「只输出一个单词」。分类节点的输出要喂给程序逻辑不是给人看的越死板越好。另一个是必须有兜底LLM 是概率模型总有一天它会给你输出Factual.或者一段解释。这个事儿我也踩过坑strip().lower()处理大小写和空白白名单校验兜住其余所有意外。宁可答得啰嗦走分析型不可让图在运行时崩掉。3.3 两个回答节点各自优化各自的目标deffactual_answer_node(state:ResearchState)-dict:llmget_llm()# temperature0要稳responsellm.invoke([(system,你是一个研究助手。这是一个事实型问题请给出准确、简洁的答案不要展开议论。),(human,state[question]),])return{answer:response.content}defanalytical_answer_node(state:ResearchState)-dict:llmget_llm(temperature0.7)# 分析型允许更发散responsellm.invoke([(system,你是一个研究助手。这是一个分析型问题请从多个角度展开分析给出推理过程最后总结你的观点。),(human,state[question]),])return{answer:response.content}分支的价值在这里显形。两个节点不只提示词不同连 temperature 都不同事实型要 0稳定可复现分析型给 0.7允许发散。如果没有分叉这种「按题施策」根本无从谈起。3.4 路由函数条件边的扳道工defroute_by_type(state:ResearchState)-Literal[factual,analytical]:returnstate[question_type]就这三行就这三行。路由函数的职责被刻意压到最小读 state返回一个字符串别的什么都不干。新手最容易犯的错是把分类逻辑写进路由函数在里面调 LLM、做判断。不是说这样跑不起来而是说它违背了 LangGraph 的设计意图节点干活边选路。节点classify可以调用模型、可以有副作用、结果写进 state可以被 checkpoint 记录第 6 篇会讲为什么这很重要。路由函数应该是纯函数只读 state 做决定快进快出。把它们分开图的每一步都有据可查。混在一起路由就成了监控和调试的盲区。3.5 组装add_conditional_edgesbuilderStateGraph(ResearchState)builder.add_node(classify,classify_node)builder.add_node(factual_answer,factual_answer_node)builder.add_node(analytical_answer,analytical_answer_node)builder.add_edge(START,classify)builder.add_conditional_edges(classify,# 从哪个节点出发route_by_type,# 用哪个函数选路{# 返回值 - 目标节点 的映射factual:factual_answer,analytical:analytical_answer,},)builder.add_edge(factual_answer,END)builder.add_edge(analytical_answer,END)graphbuilder.compile()add_conditional_edges三个参数出发节点、路由函数、映射表。映射表把路由函数的返回值翻译成目标节点名。这里两个键恰好和节点名部分重合但它们是两个命名空间路由函数返回的是「路名」映射表才决定「路通向哪」。第三个参数可以省略此时路由函数直接返回节点名。但我自己的感受是显式写映射表更划算LangGraph 能据此画出准确的图结构而且路由逻辑和图拓扑解耦改节点名不用改路由函数。3.6 跑起来questions[LangGraph 是哪家公司开源的,为什么 Agent 框架纷纷从链式结构转向图结构,]forquestioninquestions:resultgraph.invoke({question:question})print(f分类{result[question_type]})print(f回答{result[answer]}\n)第一个问题被分到factual回答一两句话。第二个被分到analytical回答分点展开。同一个图两条执行路径这就是条件边。四、几个值得记住的点顺着上面的再聊聊有三个点值得单独拎出来。条件边是「运行时」的决策。普通边在你写代码时就定了条件边到invoke那一刻才知道走哪条。这是图对链最根上的超越流程结构可以响应数据。路由依据一定要落在 state 里。你可能想分类和路由合成一步多省事。这个想法不是没道理代码确实能少几行。但 state 里留下question_type好处是调试时能看到分类结果下游节点能引用它将来做 checkpoint 回放时它是历史的一部分。state 是图的记忆别绕过它抄近道。分支可以不止两条。映射表想加几个键就加几个键。将来你的助手可能要区分闲聊、事实、分析、需要检索四种类型条件边的写法不变只是映射表变长。五、本篇小结回到「分叉」这块v0 撞的墙是一套提示词无法同时服务事实型和分析型问题解法是classify节点判断类型再用add_conditional_edges按类型选路。过程中我们顺手立了三条纪律节点干活边选路路由函数保持纯函数。路由依据写进 state不走私下传参。LLM 分类必须有兜底白名单校验防止图崩溃。v0.1 会分叉了但它还有个隐患没暴露。目前每个字段都是「整存整取」新值直接覆盖旧值。等到下一步我们让助手做多轮检索问题就来了第二次检索的结果会把第一次的覆盖掉。检索结果应该是累积的不是覆盖的。状态如何累加而不是覆盖下一篇reducer 登场。赞或收藏 关注 我们下次再见
延伸阅读

更多相关文章

2026/9/15 6:21:26

【项目】uni-app校园课程管理系统(源码+文档)【独一无二】

校园课程管理系统项目说明 项目描述 校园课程管理系统是一款基于 Vue 3 与 uni-app 开发的跨平台课程信息管理应用,可面向 H5、App及微信小程序等终端运行。项目围绕学生查看课表和管理员维护课程两类需求,将月历展示、课程查询、详情浏览、身份登录与数…

2026/9/1 21:32:16

AI内容检测率不降反升的原因与解决方案

1. 问题现象:AI检测率为何越改越高?最近不少开发者反馈一个诡异现象:使用AI工具修改AI生成内容后,检测平台的AI率不降反升。某技术社区用户实测显示,一篇原始AI率为37%的文案,经过三次"优化"后飙…

2026/9/14 14:58:07

C语言字符串处理函数深度解析:从原理到实战避坑指南

1. 为什么C语言字符串处理函数值得你花时间?在嵌入式开发、系统编程或者任何需要与底层内存打交道的场景里,C语言依然是那个绕不开的基石。而字符串处理,作为程序与用户、程序与文件、程序与网络之间最常见的交互形式,其效率和正确…

2026/9/15 23:49:06

为什么知网 AIGC 查出来是 0?不是所有 AI 文本都能识别?

最近有些同学反馈,自己查出来的知网 AIGC 检测率为 0,给自己搞得不自信了。 是不是用了假的知网 AIGC 检测系统 ?不是说论文 AIGC 检测挺严格的吗?自己写的论文都有可能会被判为 AI 率超标,为什么我自己查出来的 AI 率…

2026/9/15 23:49:06

知网 AI 检测结果 0,有没有必要额外做维普 AIGC检测?

最近有些同学反馈,自己查出来的知网 AIGC 检测率为 0,给自己搞得不自信了。 是不是用了假的知网 AIGC 检测系统 ?不是说论文 AIGC 检测挺严格的吗?自己写的论文都有可能会被判为 AI 率超标,为什么我自己查出来的 AI 率…

2026/9/15 23:49:06

WPF布尔属性命名规范与最佳实践

1. WPF布尔属性命名的最佳实践在WPF开发中,布尔属性的命名看似简单却暗藏玄机。作为一名长期奋战在WPF前线的开发者,我发现属性命名规范直接影响代码的可读性和维护性。特别是当项目规模扩大、团队协作增多时,一套清晰的命名约定能显著降低沟…

2026/9/15 23:49:06

GPT-5.5和GPT-6是真实模型吗?识别AI命名幻觉与代码防御指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 23:49:06

知网 AIGC 检出率为 0,要不要再用维普复检ai率?

最近有些同学反馈,自己查出来的知网 AIGC 检测率为 0,给自己搞得不自信了。 是不是用了假的知网 AIGC 检测系统 ?不是说论文 AIGC 检测挺严格的吗?自己写的论文都有可能会被判为 AI 率超标,为什么我自己查出来的 AI 率…

2026/9/15 23:44:06

Claude Code 必装插件清单:九个老手实测后留下的组合

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/15 21:31:11

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码