最佳组合:LangGraph 当骨架,Claude Agent SDK 在节点里干重活
- 看懂「图当骨架 + 节点干重活」的组合架构,理解两层各自的职责边界
- 建立分层职责心智模型:图层只管编排(流向/状态/恢复),节点层只管执行(工具/hooks/子代理)
- 读懂一段「LangGraph 节点里调一个 Claude Agent SDK agent」的结构化骨架,并能逐步预期它的行为
- 用「过度设计预警信号」清单判断什么场景真值得上这套、什么场景是杀鸡用牛刀
上一节你已经判断清楚了:这个项目确实踩中了"显式状态 / 检查点 / 复杂分支"那几个信号,该上 LangGraph。于是你打开文档准备照着写图,写到一半冒出个新纠结——节点里到底放什么?
你试过把一个节点写成"调一次大模型、拿个回复",结果发现这种节点太弱:它不会用工具、不会调子代理、出错了也没人兜。可你又舍不得丢掉 LangGraph 的图——状态、检查点、断点恢复这些你正需要。于是你卡在这:要不要把整套执行逻辑(工具循环、错误重试、子代理)在每个节点里自己手搓一遍?
别。2026 年成熟团队的答案是一套"best of both"的组合:LangGraph 当骨架管编排,每个节点内部交给 Claude Agent SDK 去干重活。 这一节讲清这套组合怎么搭、为什么这么分工、给你一段可读骨架和逐步预期,再用一份预警清单帮你认出什么时候它是过度设计。
这篇适合谁:已经决定上图、正在纠结"节点里写什么"的人。读完你能把一个能跑的组合架构落到代码上。
为什么是组合,而不是二选一
先把两边的强弱看清楚——这是整套组合的根。
LangGraph 强在编排,弱在执行。 它给你显式的状态机:节点、边、有 schema 的共享状态、durable 检查点、可恢复执行、human-in-the-loop。但它本身不替你管"一个节点内部怎么把活干漂亮"——工具调用循环、调起子代理、出错重试、权限钩子,这些得你自己在节点里写。
Claude Agent SDK 强在执行,编排较浅。 它把"一个 Agent 怎么把一个任务干完"包得很厚:内建工具循环、hooks(在工具调用前后插钩子做校验/审计)、MCP(接外部工具和数据源)、子代理(subagent)分工。但它在"多个 Agent 之间怎么按复杂拓扑流转、怎么 durable 地存档恢复"这层,给的抽象比 LangGraph 浅。
两边的强项几乎不重叠。所以聪明的做法不是二选一,而是让各自只干自己最强的那一层:
图管"先做什么再做什么、状态怎么传、崩了从哪恢复";节点管"这一步具体怎么把活干漂亮"。
这就是为什么不该在节点里手搓工具循环——那是 SDK 已经替你做好的执行力,重写一遍既费劲又不如它稳。也不该指望 SDK 去管跨节点的检查点恢复——那是图的强项。各取所长,边界清晰,这套组合才立得住。
增量一:组合架构分层职责图
把这套组合在脑子里分成两层,职责一刀切干净,你就不会再纠结"这个逻辑该写哪":
┌─────────────────────────────────────────────────────┐
│ 图层(LangGraph)—— 只管编排 │
│ │
│ • 共享状态 State(有 schema 的 typed dict) │
│ • 节点之间的边 / 条件边(决定流向) │
│ • durable 检查点(崩了从断点恢复) │
│ • human-in-the-loop(挂起→等人→恢复) │
│ • 并行扇出 / 汇聚、回环 │
│ │
│ ┌──────────┐ 边 ┌──────────┐ 边 ┌────────┐ │
│ │ 节点 A │ ──────▶ │ 节点 B │ ─────▶ │ 节点 C │ │
│ └────┬─────┘ └────┬─────┘ └───┬────┘ │
│ │ 调用 │ 调用 │ │
└────────┼───────────────────┼──────────────────┼───────┘
▼ ▼ ▼
┌─────────────────────────────────────────────────────┐
│ 节点层(Claude Agent SDK)—— 只管执行 │
│ │
│ • 工具循环(模型自己决定调哪个工具、调几次) │
│ • hooks(工具调用前后做校验 / 审计 / 拦截) │
│ • MCP(接外部工具、数据库、内部系统) │
│ • 子代理(把一步再拆给几个专职 subagent) │
│ • 错误重试、单步内的执行细节 │
└─────────────────────────────────────────────────────┘
怎么读这张图:上层每个"框"(节点)对图来说就是一个黑盒——图只关心它吃什么状态、吐什么状态更新、然后往哪条边走。框里面怎么干活、调了几个工具、拉了几个子代理,图一概不管,全是 SDK 的事。两层之间的接口窄得只剩"状态进、状态更新出"。这个窄接口就是整套组合好维护的原因:你换掉某个节点的内部实现,不影响图;你调整图的拓扑,不碰节点内部。
组合骨架:LangGraph 节点里调一个 Claude Agent SDK agent
下面是一段最小可读的组合骨架,帮你建立画面感。重点看结构——图怎么把节点串起来、节点内部怎么把活甩给一个 SDK agent。具体 API 名、方法签名、构造参数一律以官方文档为准(LangGraph 和 Claude Agent SDK 都在演进,你装到的版本可能和这里略有出入),下面用占位函数把执行那部分意思表达清楚:
from typing import TypedDict, Literal
from langgraph.graph import StateGraph, START, END
# ── 节点层:每个节点内部跑一个 Claude Agent SDK agent 干重活 ──
# 下面 run_research_agent / run_writer_agent 是占位:
# 真实实现里,它内部用 Claude Agent SDK 起一个带工具/MCP/子代理的 agent,
# 让模型自己跑工具循环把这一步做完,再把结果取回来。具体构造方式以官方为准。
def run_research_agent(topic: str) -> str:
"""节点内部:起一个带「联网搜索 + 读文档」工具的 SDK agent,
它自己决定搜几次、读哪些源,最后吐一份资料摘要。"""
# agent = ClaudeAgent(tools=[web_search, read_docs], ...) # 构造以官方为准
# return agent.run(f"调研:{topic}")
return f"关于「{topic}」的调研摘要(由 SDK agent 跑工具循环产出)"
def run_writer_agent(topic: str, research: str) -> str:
"""节点内部:起一个写作 agent,可再调起「润色」子代理分工。"""
# agent = ClaudeAgent(tools=[...], subagents=[polish_agent], ...) # 以官方为准
# return agent.run(f"基于资料写稿:{research}")
return f"基于调研写出的「{topic}」初稿"
# ── 图层:LangGraph 只管状态 / 流向 / 恢复 ──
class State(TypedDict):
topic: str
research: str
draft: str
approved: bool
def research_node(state: State) -> dict:
# 节点只做两件事:把活甩给 SDK agent,把结果写回状态
summary = run_research_agent(state["topic"])
return {"research": summary}
def write_node(state: State) -> dict:
draft = run_writer_agent(state["topic"], state["research"])
return {"draft": draft}
def review_node(state: State) -> dict:
# 审稿也可以是个 SDK agent;这里简化成长度判断演示流向
return {"approved": len(state["draft"]) > 10}
def route_after_review(state: State) -> Literal["write", "done"]:
return "done" if state["approved"] else "write" # 没过就回去重写
# ── 拼图:边只表达「先后 / 分支」,不掺任何执行逻辑 ──
graph = StateGraph(State)
graph.add_node("research", research_node)
graph.add_node("write", write_node)
graph.add_node("review", review_node)
graph.add_edge(START, "research")
graph.add_edge("research", "write")
graph.add_edge("write", "review")
graph.add_conditional_edges(
"review", route_after_review,
{"write": "write", "done": END},
)
app = graph.compile() # 要 durable 检查点:compile(checkpointer=...) —— 以官方为准
result = app.invoke({"topic": "多 Agent 编排", "research": "", "draft": "", "approved": False})
print(result)
注意看这段代码的分工有多干净:research_node / write_node 这些图节点函数里几乎没有业务逻辑——它们只负责"把活甩给一个 SDK agent、把返回写回 state"。真正的重活(搜几次、调哪些工具、拉不拉子代理、出错怎么重试)全在 run_research_agent / run_writer_agent 那一层,由 SDK 包掉。图这边永远清爽,永远只在表达流向和状态。
逐步预期:你应该看到什么
把上面这段跑起来(先用占位函数),你应该观察到这样一条链路:
invoke从START进research_node。节点调run_research_agent——真实场景下,这里你会看到 SDK agent 自己跑起工具循环:模型决定搜索、调用搜索工具、读返回、可能再搜一轮,最后吐摘要。占位版直接返回一句假摘要。research字段被写进状态。- 沿边进
write_node,调run_writer_agent。真实场景下这里可能再分裂出子代理(比如一个写、一个润色)。draft字段被写进状态。 - 进
review_node,判断approved。 - 走条件边
route_after_review:approved=False就回到write_node重写(你能看到流程绕回去),True就到END收工。 - 最终
print(result)打出完整的终态 state——topic / research / draft / approved 全在里面。
把 compile 接上 checkpointer 后,你还应该看到关键的那一点:在任意节点之后存档,故意中断进程再重跑,它从断点的下一个节点继续,而不是从 START 重来。这正是"图管恢复、节点管执行"组合的甜头——SDK agent 在节点里干的重活,被图的检查点保护着,崩了不用从头烧 token。
一句话验证标准:节点函数清爽(只甩活+写状态)、重活都在 SDK 那层、崩了能从断点续——三条都成立,你的组合就搭对了。
什么场景值得上这套,什么是过度设计
这套组合强,但它叠了两层框架的复杂度,不是默认选项。判断标准很简单:上一节那 5 个信号你踩中了吗?
- 值得上:你既需要图的编排保证(状态要 schema、要 durable 检查点、要 human-in-loop 审批、拓扑真的复杂),又需要每个节点内部干的是"重活"(要用一堆工具、要接 MCP、要调子代理、要 hooks 做审计)。两边都吃重——这时组合才物有所值。典型如:跑很久很贵、中途要人审批、每步内部又是个完整 Agent 的生产流水线。
- 过度设计:要么节点里其实没什么重活(每个节点就调一次模型拿个回复),那 SDK 那层是空架子,裸 LangGraph 就够;要么你根本没踩中图的信号(顺着几步做完、崩了重跑就行),那裸 Claude Agent SDK + 子代理就够,硬套图纯属自找样板代码。
记住上一节的姿势:从最简起步,每加一层都得有具体理由。 组合架构是这条阶梯的顶,不是起点。
增量二:过度设计预警信号清单
下面这些信号,出现一个就停下来问自己"是不是上重了"。它们是"为组合而组合"的典型症状:
- 你的节点函数里只有一句"调模型拿回复"。——SDK 那层是空的,你没用上它的执行力,那它就是纯负担。降级:裸 LangGraph,节点直接调模型。
- 整张图只有一条直线、没有任何条件边/回环/并行。——你没用上图的拓扑能力。降级:裸 SDK 顺序跑。
- 你从没配
checkpointer,也不打算配。——图最值钱的恢复能力你没要。这是上一节就警告过的:付了图的复杂度却不拿它的核心能力。 - 没有任何一步需要停下来等人。——human-in-loop 用不上,图的一大卖点闲置。
- 整个流程几秒钟跑完、也不烧多少 token。——崩了重跑成本极低,durable 恢复对你没意义,检查点是白付的开销。
- 你解释不清"这段逻辑为什么在节点里而不在图里"。——分层职责没想清楚,迟早写成两层互相渗透的烂泥。回去看分层职责图,把接口收窄回"状态进、更新出"。
怎么用这份清单:踩中 1-2 条还能救(局部退回更简方案);踩中 3 条以上,基本可以判定整套组合对你是过度设计——退回单框架,甚至退回裸 SDK。复杂度是要还的债,别借你用不上的那部分。
故障与避坑表
| 坑 | 表现 | 怎么破 |
|---|---|---|
| 把执行逻辑写进图、把编排写进节点 | 两层职责渗透,改一处牵一片,没法独立维护 | 守住分层职责图:图只管流向/状态/恢复,节点只管执行 |
| 节点里手搓工具循环 / 重试 | 写一堆 SDK 已经做好的东西,又不如它稳 | 节点内部直接交给 Claude Agent SDK,别重造工具循环 |
| 节点函数臃肿、塞满业务细节 | 图层不再清爽,流向被业务逻辑淹没 | 节点只"甩活 + 写状态",重活下沉到 SDK agent 那层 |
| 状态 schema 没设计好,节点间字段对不上 | 一个节点写的字段另一个读不到 / 互相覆盖 | 先把 State 里有哪些字段、谁写谁读想清楚,再写节点 |
| 上了组合却不配 checkpointer | 付了双层复杂度,没拿到 durable 恢复 | 要么用上检查点,要么过预警清单退回单框架 |
| 节点内 SDK agent 报错被吞 | 图层只看到"节点失败",定位不到内部哪一步炸 | 在节点里捕获并把 SDK 的错误信息写进状态/日志,再决定重试或上抛 |
| 节点里的 SDK agent 跑飞、无限调工具 | token 爆炸、单节点卡死 | 给节点内 agent 设步数/工具调用上限,超了让节点失败交给图处理(上限配置以官方为准) |
| 把 API 方法名当成稳定不变的 | 升级后报 AttributeError / 签名不符 |
构造方式、参数名都以官方文档为准,别照抄某篇旧文的方法名 |
动手挑战
- 拿上一节你判断"该上图"的那个真实任务,画出它的分层职责图:哪些是图层的边和状态,哪些节点内部需要 SDK 的重活(列清每个节点要用哪些工具/要不要子代理)。
- 把上面的组合骨架跑起来(先全用占位函数),观察
route_after_review在approved=False时把流程拉回write_node。把review_node的判断改严,看它多绕几圈。 - 进阶:挑一个节点,把占位的
run_*_agent换成真用 Claude Agent SDK 起的 agent,给它一两个真工具,让它在节点内部自己跑工具循环(构造方式以官方为准)。其余节点保持占位,确认图照样把它串起来。 - 进阶:给
compile接上 checkpointer,在某个节点后故意中断再恢复,亲眼确认它从断点的下一个节点继续,而不是从头重跑。 - 思辨:拿你手上任意一个 Agent 项目,过一遍"过度设计预警信号清单",数数踩中几条,给出"上组合 / 退单框架 / 退裸 SDK"的明确结论和理由。
小结 · 你现在掌握了什么
- 你理解了组合的根:LangGraph 强在编排弱在执行,Claude Agent SDK 强在执行编排浅,两者强项几乎不重叠,所以最佳解是组合而非二选一。
- 你拿到了分层职责图这个心智模型:图层只管编排(流向/状态/检查点/审批),节点层只管执行(工具/hooks/MCP/子代理),两层接口窄到只剩"状态进、更新出"。
- 你看懂了一段组合骨架:图节点清爽地"甩活 + 写状态",重活全下沉到节点内的 SDK agent,崩了由图的检查点保护。
- 你拿到了一份过度设计预警信号清单,能判断什么场景这套物有所值、什么场景是杀鸡用牛刀。
组合架构是这条阶梯的顶,不是起点。它的价值是"图的可控 + SDK 的执行力",代价是两层框架叠起来的复杂度——只在你两边都真吃重的时候,才值得付这笔账。
回看:还没想清"要不要上图"的,先看上一节什么时候才上 LangGraph;想复习"Agent 到底是什么"的,回AI Agent 是什么;记忆那层看文件即记忆。想看整条阶梯就对照三支柱路线图,或回 AI Agent 智能体阶梯看全貌。
👉 看看 AI 数字员工落地指南,或了解 数字员工搭建实战课。需要为企业落地方案,欢迎找我们聊 企业服务。