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

发布时间:2026/11/3 1:26:11

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/10/25 4:02:10

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

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

2026/10/25 20:47:53

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

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

2026/10/30 21:15:57

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

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

2026/11/3 5:25:02

Model-Optimizer:从量化压缩到端侧推理加速的实践

我需要你先提供具体的项目标题和素材,我才能基于它写出一篇可直接发布的高质量博文。请你按这个格式把信息补全:项目标题: [你想写的标题] 项目正文: [零散的原始描述,越具体越好] 关键词: [关键词1, 关键词2, ...] 摘要描述: [一句话简介]如…

2026/11/3 5:25:02

Kali Linux下zsteg图像隐写分析工具实战指南

1. zsteg工具概述与Kali环境适配性zsteg是一款专注于PNG和BMP图像隐写分析的开源工具,采用Ruby语言开发。作为Kali Linux渗透测试工具链的重要补充,它填补了传统取证工具在LSB(最低有效位)隐写检测领域的空白。我在实际CTF比赛和渗…

2026/11/3 5:25:02

BMS中SOH与SOP估算策略:从机理到多时间尺度滤波的工程实践

简介:面向电动汽车BMS算法学习者与工程技术人员的一份专题总结文档,聚焦SOH(健康状态)与SOP(功率状态)两大核心指标的估算策略,帮助读者系统梳理从定义、方法分类到优缺点比较的知识脉络。压缩包…

2026/11/3 5:25:02

电池SOH估算:开环与闭环的工程取舍与避坑指南

简介:面向电动汽车BMS开发与电池管理算法学习者的技术总结文档,聚焦SOH(健康状态)与SOP(功率状态)两大核心指标的估算策略,帮助读者系统梳理从定义、方法分类到优缺点比较的完整知识框架。压缩包…

2026/11/3 5:25:02

解决Vue项目中Babel配置路径错误问题

1. 问题现象与背景解析当你在VS Code中打开一个Vue项目时,如果项目目录没有作为根目录直接打开,而是作为子目录打开的,可能会遇到这个典型的Babel配置错误。控制台会抛出"Parsing error: No Babel config file detected"的警告&…

2026/11/3 5:20:02

高效备考打卡系统设计与实践指南

1. 项目概述"复试打卡day18"这个标题看起来像是一个备考过程中的日常记录。作为一名经历过多次重要考试的老考生,我完全理解这种打卡记录背后的意义和价值。这不仅仅是一个简单的天数标记,更是一个完整的备考管理系统。在备考过程中&#xff0…

2026/11/2 6:08:01

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/2 6:39:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

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

2026/11/3 1:04:48

STM32实战:基于MAX14431数字隔离器的SPI隔离通信方案

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

2026/11/3 1:04:48

工业SPI隔离通信设计:MAX14431BAEE+与STM32L4A6RG实战

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

2026/11/3 1:04:48

STM32+NRF24L01无线抢答器:硬件设计、通信协议与低功耗实现

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

2026/11/2 6:08:01

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/2 6:39:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

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

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

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

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