前八篇里你已经用 Mastra 把 Agent、工具、工作流、记忆、MCP、评测各写了一遍;《AI Agent 开发》系列第 6~13 篇里,同一批任务你在 Python 栈用 LangGraph 也深潜过。两边都用过之后,那个问题就躲不开了:同一个任务摆上桌,到底选谁?
本篇是《TypeScript Agent 开发(Mastra)》系列第 9 篇,一篇立场鲜明的对比文:不写“各有千秋”式的和稀泥结论,每个维度都给判断。口径沿用前作——LangGraph 1.2.x(以 Python 侧 API 为准)、@mastra/core 1.79.x,所有代码改写自两个系列里实际跑通过的例子。先亮总判断:LangGraph 卖控制权,Mastra 卖开发体验,你能忍受哪一边的代价,选型问题就解决了大半。全文按“编排 → Agent 抽象 → 记忆 → 人机协同 → 观测 → 生态位 → 迁移 → 选型”八个维度推进。
1、编排哲学与状态模型
第 4 篇埋过伏笔:LangGraph 是黑板模型,Mastra 是管道模型。这里把同一个“写作-审稿-修订”循环在两边并排摆开。先看 LangGraph 侧的骨架(writer、reviewer 是两个模型实例,reviewer 挂了结构化输出,写法见 Agent 系列第 8 篇):
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
class State(TypedDict):
topic: str
draft: str
approved: bool
comments: str
def draft_node(state: State) -> dict:
return {"draft": writer.invoke(
f"就主题「{state['topic']}」写一段 300 字导语").content}
def review_node(state: State) -> dict:
r = reviewer.invoke(f"审阅这段导语:{state['draft']}")
return {"approved": r.approved, "comments": r.comments}
def route(state: State) -> str:
return "revise" if not state["approved"] else END
builder = StateGraph(State)
builder.add_node("draft", draft_node)
builder.add_node("review", review_node)
builder.add_node("revise", revise_node) # 按意见重写,同构
builder.add_edge(START, "draft")
builder.add_edge("draft", "review")
builder.add_conditional_edges("review", route)
builder.add_edge("revise", "review")
graph = builder.compile()
三件事值得盯。其一,State 是全图共享的黑板:每个节点收到完整 state、只返回要更新的字段子集,框架负责合并,revise 写回的新 draft 在循环回到 review 时自然可见。其二,循环靠条件边表达,路由函数指回上游节点即成环。其三,两个节点并发写同一字段时必须用 Annotated[list, add_messages] 这类 reducer 声明合并策略,否则运行时直接报错——这是共享状态模型收的税。
再看 Mastra 侧,完整版在第 4 篇,编排原语清单见 Workflow 文档,这里压到骨架:
const writingWorkflow = createWorkflow({
id: 'writing-review-loop',
inputSchema: z.object({ topic: z.string() }),
outputSchema: reviewSchema, // { approved, comments }
})
.then(draftStep) // topic → draft
.then(reviewStep) // draft → 审稿结论
.dountil(reviseOnce, ({ approved }) => approved)
.commit();
语义逐项对得上,映射关系整理成表:
| 概念 | LangGraph | Mastra |
|---|---|---|
| 执行单元 | node 函数 | createStep |
| 循环回指 | 条件边 | dountil 条件函数 |
| 状态载体 | 共享 State 加 reducer | schema 逐段咬合 |
| 契约检查 | 主要在运行时 | 编译期类型推导 |
真正的差异在检查时机:LangGraph 的 State 是 TypedDict,字段名拼错要到运行时才炸;Mastra 的契约由 TypeScript 在编译期把守,改一个字段名,编辑器直接标出断在哪两步之间。判断:数据流主导的任务,Mastra 的管道占优;处处读写共享上下文的任务,LangGraph 的黑板占优——后者想加一个全图可见的执行日志字段,State 里加一项就行;前者得开 stateSchema 或层层透传。
2、Agent 抽象的默认行为
第 2 篇对照过安装与组装,这里往深一层:两个“Agent”字面量背后的默认行为差多少。LangGraph 1.x 的推荐入口是 LangChain 的 create_agent:
from langchain.agents import create_agent
agent = create_agent(
model, # 模型实例或 "openai:gpt-5"
tools=[time_tool],
system_prompt="你是严谨的助手,涉及当前时间必须先调工具。",
)
它返回的本质是一张编译好的 StateGraph,消息循环、工具分发都在图里。好处是几乎没有隐藏行为:不带 checkpointer 就没有记忆,不带 store 就没有持久化,工具循环想改就改——pre_model_hook 与 post_model_hook 允许在每次模型调用前后插自定义逻辑。代价是每个生产特性都要自己组装。Mastra 的同款任务:
export const timeAgent = new Agent({
id: 'time-agent',
name: '时间助手',
instructions: '你是严谨的助手,涉及当前时间必须先调工具。',
model: 'anthropic/claude-sonnet-5-5',
tools: { timeTool },
})
行数相近,差异全在默认值:这个对象注册进 new Mastra() 之后,Studio 里可对话可看 trace(第 2 篇),挂 memory 一行得多轮记忆(第 5 篇),挂 scorers 得随行打分(第 7 篇)——生产化特性是构造参数,不是组装工程。反过来,想改 Mastra 工具循环的内部行为,入口比 LangGraph 少,框架替你做的某些决定不可撤销(第 5 篇说过 v1 移除了 Memory 的 processors)。判断:LangGraph 给你零件和图纸,Mastra 给你一台默认配置合理的整机——原型速度 Mastra 赢,行为边界 LangGraph 赢。
注意:本文 LangGraph 代码以 1.2.x 的 Python API 为基准;LangGraph 也有 JS 版,形态相近但功能与文档都滞后 Python,TS 团队直接用前建议先过一遍 LangGraph JS 文档。
3、记忆配置量对比
第 5 篇给过概念对照,这里比配置量:把“短期记忆加跨会话画像加运行时笔记”的 Agent 在两边各配一遍。LangGraph 把短期记忆交给 checkpointer、长期记忆交给 Store,两套 API 自己组装:
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.store.memory import InMemoryStore
checkpointer = SqliteSaver.from_conn_string("memory.db")
store = InMemoryStore() # 生产换 PostgresStore
agent = create_agent(model, tools,
system_prompt="你是带记忆的助手。",
checkpointer=checkpointer,
store=store)
config = {"configurable": {"thread_id": "conv-1"}}
agent.invoke(
{"messages": [("user", "记住:我喜欢蓝色")]}, config)
# 长期记忆是编程题:节点里 store.put(...) 写入、store.search(...) 检索
跨会话的用户画像在 LangGraph 里不是配置而是编程题:namespace 结构、更新节点、检索时机全要自己设计(细节见记忆概念文档)。Mastra 侧同规格配置是五行:
new Memory({
options: {
lastMessages: 20,
semanticRecall: { topK: 4, scope: 'resource' },
workingMemory: { enabled: true },
},
})
五行换一整套组装,语义召回、工作记忆的注入格式、存储表结构全部框架代管——第 5 篇实测过,接口细节见 Mastra Memory 文档。但五十大板必须打:LangGraph 的“手动”是自由——压缩策略、注入顺序、笔记格式全部可编程;Mastra 的“自动”是收权——注入逻辑被框架定死,v1 还在持续收拢。记忆需求越常规,Mastra 越香;如果记忆本身就是产品核心竞争力(比如个性化引擎),LangGraph 的组装式反而顺手。
4、人机协同 API 形态
两边都有“挂起等审批再继续”,API 形态走了两条路。LangGraph 的 interrupt 是节点内原语(Agent 系列第 11 篇):
from langgraph.types import interrupt, Command
def approve_node(state: State) -> dict:
verdict = interrupt({"draft": state["draft"]}) # 此处挂起
return {"approved": verdict["approved"]}
# 审批人操作后,用恢复值从断点继续(依赖 checkpointer 存档):
graph.invoke(Command(resume={"approved": True}), config)
机制上,interrupt 触发时框架靠 checkpointer 存档整张图,恢复时 Command(resume=...) 的值直接作为 interrupt() 的返回值,节点从断点的下一行继续。Mastra 的 suspend 与 resume 第 4 篇实测过:execute 里调 suspend({ draft, note }) 挂起,审批后 run.resume({ resumeData }) 恢复——恢复时该步骤从头重跑 execute,用 resumeData 是否有值区分首轮与恢复轮。取舍很清楚:LangGraph 从存档原地续跑,interrupt 可以埋在节点逻辑深处甚至工具调用里,灵活但挂起点不翻代码看不见;Mastra 的挂起点必须是 step 边界,首轮与恢复轮的分支要写在函数开头,规整且与 Studio 的可视化图天然对齐——灵活度 LangGraph 胜,挂起点的可见性 Mastra 胜。
5、观测与评测体验
观测是两个框架气质差最大的地方。LangGraph 的配套是 LangSmith:云端 SaaS,注册账号、配好 LANGSMITH_API_KEY,trace 自动上报;数据集、实验对比、线上监控、人工标注队列在云端一套打通。Mastra 的 Studio 跑在本地 4111 端口,pnpm dev 即起,trace、Playground、评测面板零配置,数据不出机器。
账要算全。LangSmith 的强项是团队协作与线上闭环:多人共享 trace、prompt 版本管理、监控告警,这些 Studio 没有;但它是云服务,数据出境要过合规,免费额度之外按量计费。而且严格说这是 LangSmith 产品而非 LangGraph 框架的能力——你用 LangGraph 可以不买 LangSmith,自己接 OpenTelemetry。Studio 的强项是零依赖零外发,但边界第 7 篇画过:数据集工程与 CI 硬门禁不在框架里,团队级实验管理也得自己补。评测侧同理:LangSmith 有数据集加实验的完整工作流,Mastra 内置的是组件级 scorer。单机开发体验 Mastra 明显更顺;多人团队与线上运营,LangSmith 更成熟——前提是你接受云端。两边都导出 OpenTelemetry,理论上可交叉接入对方体系,但都有摩擦,别指望无缝。
6、生态位与双方短板
生态位的账要诚实算。LangGraph 的底牌:官网列出的生产用户里有 Replit、Uber、LinkedIn、GitLab 一排大厂,复杂多阶段流水线的公开案例里它出现频率最高;Python 与 JS 双语言,LangChain 全家桶(集成、LangSmith、部署工具)围着它转。短板:概念面积大,State、reducer、checkpointer、Store、interrupt 一套下来先学半个月;JS 版功能与文档滞后 Python——社区对此抱怨多年,LangGraphJS 仓库 的 issue 区可见一斑,TS 团队用它等于二等公民;记忆要自己组装的账前面算过了。
Mastra 的底牌:TS 原生一条链,Zod 从表单贯穿到模型输出,脚手架加 Studio 的开发体验在 Agent 框架里属第一梯队;七大件一体化,没有拼装成本。短板同样要摆:只有 TypeScript,Python 数据栈团队无从受益;1.x 迭代快,minor 版本动 API(第 4 篇提醒过),升级要盯 changelog;生产案例与社区素材的厚度不及 LangGraph,冷门问题搜不到现成答案;框架收权的方向对深度定制者不友好。一句话:LangGraph 大而全但有门槛,Mastra 小而美但路窄——窄的是生态半径,不是能力半径。
7、迁移成本清单
真要换边,哪些能搬、哪些要重写?按四层拆开:
| 层 | LangGraph 到 Mastra | Mastra 到 LangGraph |
|---|---|---|
| 工具 schema | Pydantic 翻成 Zod,机械劳动 | Zod 翻成 Pydantic,机械劳动 |
| 编排逻辑 | 节点加边重排成 step 链,全部重写 | 工作流展开成图,dountil 变条件边 |
| 记忆 | checkpointer 与 Store 折叠成 Memory 配置,大幅简化 | 一体 Memory 拆回两套 API,自己组装 |
| 观测与评测 | LangSmith 换 Studio 或 OTel | Studio 换 LangSmith,断言逻辑可搬 |
四层的成本结构完全不同:工具层是体力活,字段对字段翻一遍,测试兜底;编排层是重写,概念能映射(节点对应 step、条件边对应 branch 与 dountil)但代码全部重来;记忆层方向性极强——迁向 Mastra 是删代码,迁出 Mastra 是加工程。真正聪明的策略是第 6 篇铺过的路:把工具层沉到 MCP server,两个框架作为 client 各自接——工具的 JSON Schema 只写一份,框架迁移时工具层零成本,这也是 Agent 系列第 25 篇“MCP 削弱框架锁定”的具体含义(协议见 MCP 规范)。编排与记忆没法外包,它们才是迁移成本的实体。
8、选型决策建议
最后给决策,三个问题问下来基本能定:
- 主力语言是 TypeScript,Agent 嵌在产品里?选 Mastra
- 复杂状态机、回溯密集、背靠 Python 数据栈?选 LangGraph
- 两栈并存?编排各守甜区,工具层 MCP 统一
展开说。第一条是绝大多数产品团队的现状:Next.js 加 Node 的栈、对话加工具加 RAG 加人审的常规 Agent 形态,Mastra 一体化全包,Zod 端到端、Studio 白拿,不需要为 Agent 单独养第二个技术栈。第二条是 LangGraph 不可替代的甜区:任意边与检查点、回溯与持久执行的精确控制、Python 生态里现成的数据科学与模型工具,任务越像“状态机”它越对味。第三条最务实:不要强行统一框架——Python 重流程侧继续用 LangGraph,TS 产品侧用 Mastra,把工具沉到 MCP server 共享,跨栈成本就压到了协议层。
两个误区提前拆掉。其一,“先做个技术验证”不构成选 LangGraph 的理由——Mastra 半天跑通的验证,LangGraph 要先过图的概念关;反过来“任务复杂”也不构成选 LangGraph 的理由,先问复杂在数据流还是控制流:前者 Mastra 的管道反而更清晰。其二,别把观测平台当框架的选型因素:LangSmith 与 Studio 都能被 OTel 方案替换,而编排与记忆一旦换了就是重写——选型盯住后两者。
9、总结
八个维度收拢成一句话:LangGraph 用样板换控制权,Mastra 用约定换速度。编排上黑板对管道,数据流任务管道的编译期类型占优,共享上下文任务黑板占优;Agent 抽象上零件对整机;记忆上自由对开箱;人机协同上埋点灵活对挂起规整;观测上云端协作对本地零配;生态上大而全对一体精。迁移账本里工具层最廉价、编排最贵,MCP 能把工具层从账本里划掉。选型收在三个问题:主力语言、任务形态、要不要养第二个技术栈。
练习:回到第 2 篇的时间助手,用两个框架各实现一次“查当前时间并按固定格式回复”的最小 Agent(LangGraph 侧用 create_agent),然后量三个数:总代码行数、其中样板行数、类型检查覆盖到的环节数。再把工具加到三个并补上记忆,重测一遍。你会看到几十行的初始差距在功能加码后逐渐拉开——那才是选型的真实依据。对于读完前八篇的读者,建议把本文两张对比表带走:下次 Agent 项目立项时,对着第 1 节的编排映射表和第 7 节的迁移表直接填空,答案通常自己会浮出来。

