想象你是一家繁忙餐厅的排菜总管。墙上贴着二十张订单,每张都写着忌口、辣度、上菜顺序;后厨里有十几个工作台——备料、掌勺、装盘、质检——你得盯着每道菜走到哪一步、哪个台子空着、哪桌在催菜。这就是 LangGraph 在做的事:它用一张“状态机流程图”管住复杂多步流程的每一步。而每位厨师手边那张标准菜谱卡:“洗净 → 切丝 → 爆炒 → 出锅”,就是 LCEL——一条把单步动作串起来的声明式流水线。排菜总管不替厨师颠勺,厨师也不负责全局调度;餐厅能高效运转,靠的是“总管管流程、菜谱管执行”的默契。这篇文章,就带你亲手搭好这对“双人搭档”:让 LangGraph 调度、LCEL 执行,联手端出一盘盘复杂的 AI Agent 大菜。

岗位关联

一句话价值:掌握 LangGraph 与 LCEL 的组合打法,你就能从“调 API 的脚本工”升级为“设计生产级 Agent 流程”的架构师,这也是高级智能体岗位的核心分水岭。

目录
  1. 可视化演示
  2. 状态机原理
  3. LCEL声明式链路
  4. 组合集成方式
  5. 状态传递机制
  6. Agent编排能力
  7. 人工介入控制
  8. 容错重试策略
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示LangGraph状态机多步流程编排、LCEL声明式链路单步执行、两者组合的状态传递与人机交互节点。切换模式查看Agent不同构建机制。

本节配有交互动效(进入视口后自动加载,约 3KB)。

LangGraph状态机编排 节点=计算步骤,边=转移关系 条件边支持分支与循环逻辑 StateGraph(Nodes,Edges) 有向图状态机管理多步流程

状态机原理

后厨的墙上挂着一块巨大的排菜板,每一道菜是一张卡片,卡片上记录着“配菜 + 主料 + 辣度 + 特殊备注”。排菜总管只看这块板,就知道哪道菜在备料、哪道在掌勺、哪道待质检。LangGraph 就是这块排菜板背后的调度系统——它把整个工作流画成一张图来驱动。

图由两类元素构成:节点(node)和边(edge)。节点是“工作台”,执行具体的处理函数;边是“传菜路线”,决定 A 台处理完后去 B 台还是 C 台。整张图运行时会维护一份所有节点共享的状态(state):每个节点读取状态、加工、再写回,就像每个台位在订单卡上做批注。

在代码里,先用 StateGraph(StateSchema) 声明状态的“数据结构”,再用 add_node("备料", func) 注册工作台,用 add_edge / add_conditional_edge 定义路线,最后 compile() 把图“点火”成可执行对象。LangGraph 的核心循环就是:当前状态 S 沿着边找到下一节点,执行节点函数,更新状态,再找下一条边。

有了这张“排菜板”,再复杂的流程都被拆成了清晰的台位与传菜路线。但请注意:总管只负责“谁在哪儿做”,至于每个台位具体怎么把菜做好,那是菜谱卡的事——这就是接下来要讲的 LCEL。

St+1=Node(St, Et)\displaystyle S_{t+1} = \text{Node}\bigl(S_t,\ E_t\bigr)
状态 S 就像那张不断被批注的订单卡:上一工作台的处理结果,就是下一工作台的输入。
  1. S_t(当前状态)此刻这道菜在排菜板上的完整信息,包括已完成的工序和待办事项。
    St={工序, 笔记, 备注}\displaystyle S_t = \{ \text{工序},\ \text{笔记},\ \text{备注} \}
  2. E_t(触发边)总管根据当前情况选择的下一条路线,例如“辣度超标 → 退回重做”。
    Et=Route(St)\displaystyle E_t = \text{Route}(S_t)
  3. Node(节点函数)某个工作台的处理动作,输入状态,输出增量的结果。
    Node(S)↦ΔS\displaystyle \text{Node}(S) \mapsto \Delta S
  4. S_{t+1}(新状态)把增量合并回订单卡,得到下一回合的完整快照。
    St+1=St⊕ΔS\displaystyle S_{t+1} = S_t \oplus \Delta S

LCEL声明式链路

每位厨师台前都贴着一张菜谱卡:“洗净 → 切丝 → 大火爆炒 → 出锅装盘”。它用一条直线把工序串起来,厨师不用想下一步干嘛,照着卡走就行。LCEL(LangChain Expression Language)就是这张菜谱卡——它把“提示词整理、模型调用、结果解析”串成一条声明式的流水线。

LCEL 的核心是竖线管道运算符 |:左边产出的东西自动变成右边的输入,像传送带一样一环扣一环。任何实现了 Runnable 接口的对象——提示模板、大模型、输出解析器——都可以被 | 串起来。这就是“可运行对象”(Runnable)的统一契约:有输入、有输出、能调用。

一条典型的链长这样:prompt_template | llm | output_parser。它最终是一个 RunnableSequence,支持 invoke(同步执行)、stream(流式输出)、batch(批量处理)。声明式的妙处在于:代码读起来就是流程本身,不需要手写任何胶水逻辑。

菜谱卡让每个台位的“单步动作”标准化、可复用。但光有菜谱卡,餐厅还是转不起来——必须由排菜总管把卡发到对应工作台,并按订单顺序调度。下一节,我们就正式把 LCEL 链“递”给 LangGraph 的每个节点。

Chain=Prompt∣Model∣Parser\displaystyle \text{Chain} = \text{Prompt} \mid \text{Model} \mid \text{Parser}
菜谱卡把“备料、下锅、装盘”写成一行,LCEL 把“提示、生成、解析”串成一个管道。
  1. Prompt(提示模板)把用户的自然语言问题,套进固定的提示词模板,得到完整提问文本。
    Prompt(q)=template(q)\displaystyle \text{Prompt}(q) = \text{template}(q)
  2. Model(大模型)接收提问文本,返回模型生成的原始回答字符串。
    Model(text)=reply\displaystyle \text{Model}(\text{text}) = \text{reply}
  3. Parser(输出解析器)把原始回答解析成结构化结果,例如去掉杂质、转成 JSON。
    Parser(reply)=structured\displaystyle \text{Parser}(\text{reply}) = \text{structured}
  4. Chain(整条链路)三者用管道串联,输入 q 直接得到最终结果。
    Chain(q)=Parser(Model(Prompt(q)))\displaystyle \text{Chain}(q) = \text{Parser}\bigl(\text{Model}\bigl(\text{Prompt}(q)\bigr)\bigr)

组合集成方式

排菜总管把菜谱卡钉在每个工作台正上方:“备料台请按《凉菜卡01》执行,掌勺台请按《热菜卡07》执行”。工作台换了人,流程却不变——因为“台位职责”和“具体怎么做”被拆开了。LangGraph 与 LCEL 的组合,拆的正是这两件事。

组合的方法非常简单:把一个 LCEL 链“包”进一个普通函数,这个函数接收状态、调用链、返回增量字段,再把这个函数注册成 LangGraph 的节点。LangGraph 根本不关心节点内部是什么,它只认“输入状态 → 输出状态”这个契约。

典型的节点函数长这样:

然后 graph.add_node("node_name", node) 把它挂上图,定义好边,最后 graph.compile()。运行时,LangGraph 负责挑节点、传状态、收结果,LCEL 负责在节点内部完成“提示 → 生成 → 解析”的精细活。

菜谱卡钉上了墙,总管一声令下,台位就按卡开工。但这里有个关键问题:台位之间怎么把订单信息完整传下去?辣度、忌口、加急备注,如何在十几个台位间准确流转?这就是状态传递机制的活。

Nodei=wrap(Chaini)\displaystyle \text{Node}_i = \text{wrap}\bigl(\text{Chain}_i\bigr)
每个工作台 = 一张菜谱卡 + 一个“按卡执行”的包装函数;每个节点 = 一条 LCEL 链 + 一个接收状态的函数壳。
  1. Chain_i(第 i 条链)为某个职责预制的 LCEL 流水线,例如“总结链”“翻译链”。
    Chaini=Pi∣M∣Ri\displaystyle \text{Chain}_i = P_i \mid M \mid R_i
  2. wrap(包装动作)写一个函数,把链的调用封装在“读状态 → 调链 → 写回增量”的夹层里。
    wrap(C)(S)↦{增量字段}\displaystyle \text{wrap}(C)(S) \mapsto \{ \text{增量字段} \}
  3. Node_i(图节点)包装后的函数符合 LangGraph 的节点契约,可被 add_node 注册。
    Nodei:S↦ΔS\displaystyle \text{Node}_i : S \mapsto \Delta S
  4. 整体执行图调度到节点 i 时,等效于把状态 S 交给链处理,再把结果合并回去。
    execute(S)=S⊕Chaini(S)\displaystyle \text{execute}(S) = S \oplus \text{Chain}_i(S)
python3 行
def node(state):    result = chain.invoke({"question": state["question"]})    return {"answer": result}

状态传递机制

订单卡从进厨房的第一秒起,就在被各个台位批注:备料台写上“鱼已切好”,掌勺台写上“辣度减半已执行”,装盘台写上“少放葱”。没人重抄整张卡,每个人只在自己负责的格子里写几笔——但任何台位拿到卡,都能看到完整信息。这就是 LangGraph 状态传递的本质。

状态的结构由 StateSchema(通常是一个 TypedDict)提前定义好,例如 {"question": str, "draft": str, "messages": list}。每个节点执行完只返回自己负责的那部分字段,即增量;LangGraph 会用“归约器”(reducer)把增量合并回总状态,节点之间永远共享同一份最新快照。

对于普通字段,默认的归约规则是“覆盖”:新值替换旧值。对于需要累积的字段(比如多轮对话记录),要显式声明归约器,最常用的是 add_messages——它把新消息追加到消息列表末尾,而不是覆盖。这样状态既全局可见,又避免了每个节点重复携带全部数据。

订单卡就这样“越写越厚”地穿过整条后厨流水线——这正是复杂 Agent 的血液系统。有了血液(状态),还得有大脑(编排逻辑):什么时候该走哪条路、要不要调用外部工具,这就是 Agent 的编排能力。

S′=S⊕ΔS\displaystyle S' = S \oplus \Delta S
状态合并就像往订单卡上贴新笔记:$\oplus$ 是“贴上去”这个动作——有的格子直接覆盖,有的格子不断追加。
  1. S(当前状态)此刻订单卡上的全部信息,所有节点共享同一份。
    S={q, d, msgs}\displaystyle S = \{ q,\ d,\ \text{msgs} \}
  2. ΔS(节点增量)某个节点只返回它改动的那几个字段,不必返回全部。
    ΔS={d:新草稿}\displaystyle \Delta S = \{ d: \text{新草稿} \}
  3. ⊕(归约合并)根据每个字段的 reducer 类型,把增量合并回总状态 S。
    merge:(S, ΔS)↦S′\displaystyle \text{merge}: (S,\ \Delta S) \mapsto S'
  4. S'(新状态)下一个节点看到的完整订单卡,包含此前所有台位的批注。
    S′=S⊕ΔS\displaystyle S' = S \oplus \Delta S

Agent编排能力

有经验的排菜总管不会傻走一条线。看到订单备注“客人对花生过敏”,他立刻把菜从“常规炒台”改派到“无过敏原专台”;发现冰箱缺了鲈鱼,他马上派小工去市场采购。复杂 Agent 也是这样:根据当前状态,动态决定下一步走哪条边。

LangGraph 提供了条件边(conditional edge):一个路由函数接收状态,返回“下一个节点的名字”。这把 if-else 从代码里搬进了流程图——流程走向由状态数据驱动,而不是写死的。这是 Agent 区别于“固定流水线”的核心能力。

再加上大模型本身的推理能力,一个 Agent 循环就成型了:模型判断“需要查资料” → 路由到工具节点 → 工具返回结果写回状态 → 模型再判断“可以回答了” → 路由到输出节点。多步推理(multi-step reasoning)和工具调用(tool calling)就是这样被编排成一张动态图。

有了会看单改路线的总管,餐厅能接住各种突发状况。但有一类情况连总管都不敢拍板——比如贵宾宴席的主菜,他必须请主厨亲自尝一口再决定上不上。这种“流程停下来等人”的机制,就是人机交互节点。

next=Router(S, Tools)\displaystyle \text{next} = \text{Router}\bigl(S,\ \text{Tools}\bigr)
排菜总管看一眼订单卡和现有食材,决定派给哪个台位;路由函数看一眼状态和可用工具,决定走哪条边。
  1. S(当前状态)包含用户问题、中间推理结果、工具返回的数据。
    S={问题, 推理, 工具结果}\displaystyle S = \{ \text{问题},\ \text{推理},\ \text{工具结果} \}
  2. Tools(工具集合)Agent 可调用的外部能力,如搜索引擎、计算器、数据库。
    Tools={search, calc, db}\displaystyle \text{Tools} = \{ \text{search},\ \text{calc},\ \text{db} \}
  3. Router(路由函数)读取状态 S,返回下一个节点的名字。
    Router(S)↦node_name\displaystyle \text{Router}(S) \mapsto \text{node\_name}
  4. next(下一节点)LangGraph 据此沿对应边把流程推向下一个工作台。
    edge:current→next\displaystyle \text{edge}: \text{current} \to \text{next}

人工介入控制

国宴级别的订单,排菜总管会设定一个“主厨试菜点”:菜做完先不上桌,端到主厨面前尝一口,要么盖章放行,要么打回重做。在这个点上,整条流水线是暂停的——所有人等着主厨的裁决。这就是 human-in-the-loop(人在回路)。

LangGraph 提供了中断机制:在某个节点执行前(interrupt_before)或执行后(interrupt_after)设置断点。图运行到断点时,会保存当前状态并挂起,等待外部(人类)输入,之后从断点继续,而不是从头执行。

配合持久化(checkpointer)功能,中断后的状态可以安全保存和恢复。常见用法:Agent 生成草稿 → 中断 → 人审阅并修改 → 恢复执行后续节点。这个能力把 Agent 从“全自动工具”升级为“可控的生产流程”——就像主厨的章,让每一道大菜都有人把关。

主厨尝完菜,流程继续。但人不可能永远盯着机器——如果某个台位总是把菜做坏,总管就得定规矩:最多重做几次、重做失败怎么办。这就是容错重试策略。

Shalt=Interrupt(S, ask)\displaystyle S_{\text{halt}} = \text{Interrupt}\bigl(S,\ \text{ask}\bigr)
主厨试菜点:菜(状态)停在主厨手里,总管记下要问的问题;等主厨的批注(人类输入)拿回来,菜继续往前走。
  1. Interrupt(中断原语)把当前状态挂起,并把预设问题抛给人类。
    Interrupt(S, ask)↦Shalt\displaystyle \text{Interrupt}(S,\ \text{ask}) \mapsto S_{\text{halt}}
  2. ask(待确认问题)例如“这份草稿是否批准发布?”。
    ask=Question[草稿]\displaystyle \text{ask} = \text{Question}[\text{草稿}]
  3. S_halt(挂起状态)断点时刻的完整快照,被 checkpointer 持久化保存。
    Shalt=S\displaystyle S_{\text{halt}} = S
  4. 恢复执行拿到人类回答后,合并进状态并继续后续的边。
    Sresume=Shalt⊕{human:answer}\displaystyle S_{\text{resume}} = S_{\text{halt}} \oplus \{ \text{human}: \text{answer} \}

容错重试策略

掌勺台偶尔会糊锅。总管定的规矩是:糊了,重新炒一次;又糊,再重炒一次;连炒三次还糊,立刻上报主厨换菜,绝不让客人干等。谁都不想上菜出错,但一家成熟的餐厅,靠的不是“永不犯错”,而是“错了知道怎么补救”。

复杂 Agent 的节点里,大模型调用、工具调用都可能抛出异常:网络抖动、API 限流、返回格式不对。所以每个关键节点要做两层防护:一是捕获异常(try / except),二是按策略重试(retry)。

重试策略要控制三个参数:最大重试次数 N_max、退避时长(如指数退避 1s → 2s → 4s)、重试条件(只在可恢复异常时重试)。超过 N_max 就进入兜底分支(Fallback):返回预设文案、降级模型,或转人工。LangGraph 把“重试逻辑”封装在节点内部,配合外层编排实现更精细的重试路由。

到这里,后厨的整套管理体系就齐了:排菜板管全流程、菜谱卡管单步、订单卡传递状态、总管动态派单、主厨试菜把关、糊锅重炒兜底。这就是 LangGraph 与 LCEL 组合构建复杂 Agent 的完整图景——一张自带秩序的生产流水线。

Retry(n)={Reexec(S),n<Nmax⁡Fallback(S),n≥Nmax⁡\displaystyle \text{Retry}(n) =\begin{cases}\text{Reexec}(S), & n < N_{\max} \\\text{Fallback}(S), & n \ge N_{\max}\end{cases}
糊锅就重炒(Reexec),最多三次;三次还糊就换菜或上报主厨(Fallback)。
  1. n(已重试次数)记录这道菜已经重做几次,每次失败自增。
    n←n+1\displaystyle n \gets n + 1
  2. N_max(上限)预先约定的最大重试次数,防止无限循环。
    Nmax⁡=3\displaystyle N_{\max} = 3
  3. Reexec(重试执行)回到节点开头,重新执行一次 LCEL 链。
    Reexec(S)=Chain(S)\displaystyle \text{Reexec}(S) = \text{Chain}(S)
  4. Fallback(兜底分支)重试耗尽后走降级路径,保证整体流程不崩。
    Fallback(S)↦安全结果\displaystyle \text{Fallback}(S) \mapsto \text{安全结果}

AI 应用场景

智能客服工单Agent

阶段:复杂多步骤智能体(Agent)

解决的问题:传统客服脚本只能一问一答,遇到“退款 + 改地址 + 查物流”的复合需求就乱套。用 LangGraph 把工单处理拆成多步——意图识别 → 查询订单 → 生成回复 → 人工复核,再用 LCEL 实现每一步的模型调用,错误自动重试,重大投诉转人工。

具体案例:某电商平台售后 Agent,用户说“我要退款但别退到原卡”。Agent 先走“意图分类”节点,再调“退款规则检查”工具,生成草稿后中断,由客服主管确认退款方式,恢复后执行退款并发送通知。

数据分析Agent

阶段:多步推理与工具调用

解决的问题:传统 BI 工具要人写 SQL、人看报表。数据分析 Agent 把“提问 → 查数 → 分析 → 出图”串成图流程:LLM 生成 SQL → 工具执行查询 → 校验结果 → 生成结论,任一步失败按重试策略重跑或降级为规则引擎兜底。

具体案例:某 SaaS 公司的数据助手,销售问“华东区 Q2 环比增长多少”。Agent 走“语义转 SQL”LCEL 链,调用数据库工具,结果写回状态,再走“结论生成”链输出带数字的答案。全程通过 LangGraph 状态机保证每个环节可追溯、可回放。

人工审批流Agent

阶段:人机交互(human-in-the-loop)

解决的问题:纯自动化的合同生成风险高,纯人工的流程效率低。用 LangGraph 的 interrupt 把流程设为:自动起草(LCEL 链)→ 暂停 → 法务审批 → 恢复 → 自动发送。状态和审批意见在断点间无损传递。

具体案例:某公司的合同助手:业务员提交需求,Agent 调“合同模板链”生成草稿,走到“法务审核”节点自动暂停;法务在线批注点通过后,流程从断点恢复,后续节点自动完成用印申请与归档。

Python 演示

python55 行
from typing import TypedDict from langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAIfrom langgraph.graph import END, StateGraph  class AgentState(TypedDict):    question: str    draft: str    answer: str  llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) summarize_chain = (    ChatPromptTemplate.from_template("请先用一句话提炼问题的核心:{question}")    | llm    | StrOutputParser()) answer_chain = (    ChatPromptTemplate.from_template(        "请结合要点【{draft}】完整回答用户问题:{question}"    )    | llm    | StrOutputParser())  def node_summarize(state: AgentState) -> dict:    return {"draft": summarize_chain.invoke({"question": state["question"]})}  def node_answer(state: AgentState) -> dict:    return {        "answer": answer_chain.invoke(            {"question": state["question"], "draft": state["draft"]}        )    }  graph = StateGraph(AgentState)graph.add_node("summarize", node_summarize)graph.add_node("answer", node_answer)graph.set_entry_point("summarize")graph.add_edge("summarize", "answer")graph.add_edge("answer", END) app = graph.compile() if __name__ == "__main__":    result = app.invoke({"question": "LangGraph和LCEL如何搭配使用?"})    print(result["answer"])
目的:演示“两条 LCEL 链分别包成两个节点,再由 LangGraph 状态机串成两段式 Agent”的最小可运行样例。
  1. class AgentState(TypedDict):用类型字典定义状态的键与类型,即“订单卡模板”。
  2. summarize_chain = (LCEL 竖线管道把提示模板、模型、解析器串成一条链。
  3. | llm管道运算符把上一步输出自动送进大模型。
  4. def node_summarize(state: AgentState) -> dict:节点函数接收状态,是 LangGraph 与 LCEL 之间的适配器。
  5. graph = StateGraph(AgentState)用状态结构创建状态机图。
  6. graph.add_node("summarize", node_summarize)把 LCEL 包装节点注册到图上。
  7. graph.set_entry_point("summarize")指定流程入口节点。
  8. app = graph.compile()编译为可执行应用。
  9. result = app.invoke({"question": "LangGraph和LCEL如何搭配使用?"})喂入初始状态,启动整条流水线。

常见误区

误区用了 LangGraph 就不需要 LCEL 了,状态机把提示、模型、解析全包了,链式语法是多余的历史包袱。

正解两者职责完全不同。LangGraph 管“流程编排”——谁在哪儿做、做完去哪;LCEL 管“单步执行”——一个台位具体怎么把活干完。排菜总管再厉害也不会颠勺;LCEL 是节点内部那把“勺”。实践中几乎每个节点内部都要靠 LCEL 链来调用模型。

为何常见:因为 LangGraph 也自带调用模型的语法糖,初学者容易误以为链式 API 被淘汰了,实际上两者是互补关系而非替代关系。

误区以为在一条 LCEL 链里,前一次 `invoke` 的结果会自动保存,下一次调用还能“记得”上次的输入。

正解LCEL 是无状态的管道:输入进去、结果出来,管道本身不存任何历史。要“记住”中间结果,必须把它写进 LangGraph 的 State,由状态机在下一次节点调用时传回。菜谱卡不会自己记住上次炒的菜,记菜的是排菜板。

为何常见:因为链式调用看起来像“连续对话”,初学者容易把“流水线传参”误解为“自带记忆”。

误区写的节点函数把整个 state 抄一遍再返回,生怕漏了某个字段导致后面的节点拿不到数据。

正解节点只需要返回自己改动的那部分增量字段,LangGraph 用归约器自动合并。全量返回既啰嗦又容易覆盖别人写好的字段。台位只在自己负责的格子里写字,不用重抄整张订单。

为何常见:受普通函数“输入完整、输出完整”习惯的影响,没意识到 LangGraph 提供了声明式的状态合并机制。

误区以为 `interrupt` 就像程序崩溃,恢复后要重新调用整个图,所有节点重跑一遍。

正解interrupt 配合 checkpointer 会保存挂起时的状态快照;恢复时从断点所在的节点继续执行后续边,前面的节点不会重跑。主厨尝完菜,这道菜还在质检台上,不用重新备料。

为何常见:把“中断”理解成了“异常终止”,混淆了暂停(可续跑)与崩溃(需重启)两个概念。

面试题

Q1. LangGraph的核心抽象是什么?

单选题 · easy

  • A.基于状态迁移的图结构← 正确答案
  • B.基于数据表的存储结构
  • C.基于消息队列的流式结构
  • D.基于文件系统的存储结构

答案:A。排菜总管的核心不是某道菜怎么做,而是“菜在哪个台位、下一步去哪”。LangGraph 正是用“节点 + 边 + 状态”的图结构来编排多步流程,而不是存储、消息中间件或文件系统。

Q2. LCEL声明式链路的管道运算符是?

单选题 · easy

  • A.使用加号连接组件
  • B.使用竖线连接组件← 正确答案
  • C.使用箭头连接组件
  • D.使用冒号连接组件

答案:B。菜谱卡上的"→"在 LCEL 里写作 |。竖线把提示模板、模型、解析器串成一条链,前一步的输出自动成为后一步的输入,所以答案是竖线。

Q3. LangGraph中边(edge)的作用是什么?

单选题 · easy

  • A.定义节点间流转方向← 正确答案
  • B.存储大模型权重参数
  • C.缓存历史对话消息
  • D.加密节点间的传输

答案:A。边是“传菜路线”,决定一个节点执行完后下一个该进哪个节点。权重存储、对话缓存、传输加密都不是 LangGraph 中“边”的职责。

Q4. 将LCEL链接入LangGraph节点的正确做法是?

单选题 · mid

  • A.把链直接传给add_edge调用
  • B.在节点函数内调用链invoke← 正确答案
  • C.用链做StateSchema结构
  • D.编译后再挂载到图上面

答案:B。节点函数是 LangGraph 与 LCEL 之间的“适配器”:函数接收状态、调用链的 invoke、返回增量字段。add_edge 管的是节点间的路线,不接收业务链;用链做 StateSchema 或编译后挂载都不是标准做法。

Q5. TypedDict在LangGraph中的作用是?

单选题 · mid

  • A.存储模型训练的参数
  • B.定义状态的键与类型← 正确答案
  • C.解析大模型的输出
  • D.配置重试的次数

答案:B。TypedDict 就是“订单卡模板”,提前规定状态里有哪些字段、各是什么类型。它不是训练参数、不是解析器、也不是重试配置,而是状态结构的静态声明。

Q6. add_messages归约器的主要行为是?

单选题 · mid

  • A.覆盖旧的消息列表
  • B.把新消息追加到列表← 正确答案
  • C.删除超过长度的消息
  • D.压缩消息以减少体积

答案:B。订单卡上的“多轮对话”格需要不断追加而不是覆盖。add_messages 把新消息追加到消息列表末尾,适合累积对话历史;覆盖、删除、压缩都不是它的默认行为。

Q7. 实现人工介入(human-in-the-loop)的常用手段?

多选题 · mid

  • A.节点前后设置中断点← 正确答案
  • B.等待外部输入再恢复← 正确答案
  • C.用LCEL并行替代暂停
  • D.删除状态强制重启

答案:AB。主厨试菜 = 在节点前后设 interrupt 断点,流程挂起等待人类输入,拿到输入后从断点恢复。LCEL 并行与人工介入无关;删除状态强制重启会丢失上下文,不是中断的正规做法。

Q8. 条件路由(conditional edge)的职责是?

单选题 · hard

  • A.强制全部节点串行执行
  • B.把状态复制到每个分支
  • C.根据状态选择下一节点← 正确答案
  • D.自动回滚到上一节点

答案:C。条件边就是总管“看单派台”:路由函数读状态,返回下一个节点的名字,流程再沿对应边走。它不强制串行、不复制状态、也不负责回滚,核心就是“按状态选路”。

Q9. 节点容错重试策略通常包含哪些?

多选题 · hard

  • A.捕获节点内的运行异常← 正确答案
  • B.设定最大重试的次数← 正确答案
  • C.重试前等待退避时长← 正确答案
  • D.把失败状态永久删除

答案:ABC。糊锅重炒的完整规矩:捕获异常(知道糊了)、设上限(最多三次)、退避等待(等油温恢复)。把失败状态永久删除会让流程丢失上下文,反而是要避免的错误做法。

Q10. 人工中断恢复后,图从哪里继续执行?

单选题 · extreme

  • A.从中断节点继续执行← 正确答案
  • B.从入口节点重新开始
  • C.从末尾节点倒序执行
  • D.从随机节点跳跃执行

答案:A。interrupt 配合 checkpointer 保存状态快照,恢复时从断点继续,而不是重跑整张图。就像主厨尝完菜,菜还在质检台接着走,不用重新备料、重新炒。