我见过太多团队在"自研 vs 框架"这个问题上走弯路。
有人花三个月学习框架,最后发现业务场景根本用不上;也有人坚持裸写,等 Agent 数量增长到 5 个以上时,编排层代码已经比业务逻辑还多。
这篇文章不做框架推荐清单,而提供一套工程决策指南:什么时候该裸写,什么时候该引入框架,框架真正解决什么问题,以及它会带来哪些长期成本。
一、先搞清楚一个事实:框架并非必需品
一个能在生产环境跑的单 Agent,核心代码通常不超过 50 行:
ini
messages = [{"role": "system", "content": system_prompt}]
while step < max_steps:
response = llm.chat(messages, tools=tools)
if response.stop_reason == "tool_use":
results = execute_tools(response.tool_calls)
messages.extend(results)
else:
break
这就是 Agent 的基本形态:围绕 LLM、工具和上下文展开的工具调用循环。
Claude Code、Cursor、echo-agent 这类产品的内核,都可以看作这个模式的工程化变体:LLM 读取上下文,判断是否需要调用工具;工具返回结果后,再把结果写回上下文,继续下一轮推理与行动。
框架做的事情,是在这个循环之上增加抽象层,例如状态管理、流程编排、持久化、可观测性、人工介入、错误恢复等。
真正需要判断的问题只有一个:你的业务复杂度,是否已经值得为这层抽象付出学习、调试、迁移和运行成本?
二、框架给你什么
好处
1. 编排复杂度的封装
当你的流程变成"分析 → 判断 → 分支 A / 分支 B → 人工审批 → 执行 → 验证 → 失败则回退"这种结构时,继续用 if/else 手写状态机,很快会失控。
第一版代码通常还能保持清晰,真正的问题会出现在第三次、第五次需求变更之后:新增一个分支、插入一个审批节点、修改失败回退策略、增加异常补偿逻辑,原本直观的流程会逐渐散落到多个函数、多个文件和多个隐式状态里。
LangGraph 的图模型让你用声明式方式表达复杂流程。节点代表动作,边代表状态转移,条件边表达分支,checkpoint 负责恢复。相比手写状态机,这种表达方式更容易阅读、测试和维护。
2. 开箱即用的生产能力
框架通常会提供一批生产环境常用能力:
- 持久化和断点恢复:进程挂了可以从上次状态继续
- Tracing 和可观测性:记录每一步输入输出、token 消耗、延迟
- 人工介入节点:高风险操作暂停,等待人确认后继续
- 错误重试和降级策略:失败后重试、切换工具、进入备用路径
这些能力自己写都能实现,但每一项都意味着额外工程投入。真正麻烦的地方不只在写代码,还在于处理边界情况:流程跑到一半断电怎么办?工具超时后状态如何回滚?人工审批跨天后上下文如何恢复?这些问题进入生产环境后,都会变成真实成本。
3. 团队协作的统一语言
三个人同时开发 Agent 系统,如果没有统一抽象,很容易写出三种风格的编排逻辑。
有人喜欢函数嵌套,有人喜欢事件驱动,有人喜欢状态字典加条件判断。短期看都能跑,长期看会增加协作成本。框架强制了一套约定:节点、边、状态、工具、checkpoint、trace。团队成员讨论问题时,有了共同语言,代码评审和问题定位都会更高效。
坏处
1. 抽象泄漏成本高
框架的抽象在 80% 的场景下很优雅,但生产环境的边界情况往往落在剩下的 20%。
当你需要绕过框架做特殊处理时,一个原本简单的问题,可能已经被框架封装了三层。你需要理解框架的生命周期、状态序列化方式、回调机制、执行器调度逻辑和异常传播路径,调试难度会明显上升。
Agent 系统最怕黑盒。一旦 LLM 行为、工具返回、框架调度三者混在一起,排查问题会非常痛苦。
2. Token 开销不可忽视
实测数据:CrewAI 在简单单工具调用场景下,token 消耗是等价裸写代码的 3 倍。
框架需要注入角色描述、协调指令、格式约束、任务交接说明,这些都会进入上下文,最终转化成 token 成本。对 demo 来说,这点开销通常可以接受;对高频调用、低毛利、强成本敏感的生产系统来说,这个开销会直接影响利润率。
按 LLM 成本占 Agent 运营总支出 40-60% 计算,框架带来的额外 token 消耗需要进入架构决策模型,不能只看开发体验。
3. 版本升级的被动性
框架 breaking change 的节奏通常由框架方决定。
LangGraph 从 0.x 到 1.0 的迁移、AutoGen 到 Microsoft Agent Framework 的合并,都让依赖它们的团队付出了可观的迁移成本。你的业务逻辑没有变化,但框架 API、执行模型、配置方式变了,你就必须跟着调整。
对于长期维护的生产系统,框架依赖意味着你把一部分架构演进权交给了外部项目。选框架时,必须考虑社区稳定性、版本策略、迁移成本和生态成熟度。
4. 学习曲线侵蚀交付时间
LangGraph 官方都承认需要 1-2 周才能上手。
对于一个需要两周交付 MVP 的项目,把一半时间花在学习框架上,投入产出比显然不高。尤其在早期验证阶段,最重要的事情通常是证明"AI 能不能完成这个业务任务",提前搭一个完备的编排系统反而会拖慢验证节奏。
框架学习成本不仅体现在文档阅读上,还体现在团队共同理解、代码风格统一、调试方式切换和上线流程适配上。
三、主流框架怎么选
2026 年的框架格局已经稳定,逐渐从百花齐放进入各归其位的阶段:
| 框架 | 核心隐喻 | 生产验证 | 适合场景 |
|---|---|---|---|
| LangGraph | 有向图状态机 | 400+ 企业,47M 月下载 | 复杂流程、合规审计、长时间任务 |
| CrewAI | 团队角色分工 | 44K stars,Fortune 500 探索 | 快速原型、demo 演示、线性多角色任务 |
| OpenAI Agents SDK | 五原语极简模型 | 19K stars,1030 万月下载 | GPT 生态、语音 Agent、沙箱执行 |
| Google ADK | 层级 Agent + 多模态 | 17K stars,50+ A2A 伙伴 | GCP 团队、视频/音频/图像统一推理 |
| Microsoft Agent Framework | 图工作流 + Azure 原生 | 2026.4 GA | .NET 团队、Azure 全家桶 |
我的选型态度
LangGraph 是"不会错"的选择,原因不在于它覆盖所有场景,而在于犯错成本最低。社区最大,生态最完整,天花板最高,从简单流程到复杂工作流都能逐步演进。
如果你不确定未来流程会不会变复杂,LangGraph 至少给你保留了向上扩展的空间。它适合那些一开始看起来简单、但未来很可能引入条件分支、人工节点、失败恢复、审计追踪的项目。
CrewAI 更适合作为演示和原型工具。它的角色分工模型很直观,做 demo 很快,适合把"多个角色协作"的概念迅速跑起来。
但我见过太多团队从 CrewAI 起步,半年后被迫迁移到 LangGraph。原因通常很相似:流程一旦出现回退、循环、状态恢复、复杂条件判断,CrewAI 的抽象就会变得吃力。如果你预期项目会长期维护,从一开始就要谨慎选择 CrewAI。
厂商 SDK 只在深度绑定时选。OpenAI Agents SDK、Google ADK、Microsoft Agent Framework 都有各自的生态优势。
如果你的模型、云服务、权限体系、部署体系已经深度绑定某个厂商,厂商 SDK 会带来明显便利。脱离母体生态后,它们的优势会迅速变弱,同时可能带来迁移成本和平台锁定问题。
四、自研:必须考虑什么
如果你决定不用框架,以下是按优先级排列的必备能力:
如果你想看一个不依赖框架、从零实现上述能力的完整项目,可以参考 echo-agent。它展示了工具系统、上下文管理、护栏机制如何在没有框架的情况下落地,适合作为自研路径的参考起点。
P0:没有这些就不叫 Agent
工具系统
Agent 和普通聊天机器人的核心区别,就是能否稳定、可控地调用外部工具。你至少需要:
- 工具注册机制:schema 定义 + 函数绑定
- 执行引擎:解析 LLM 返回的工具调用,执行并回传结果
- 错误隔离:单个工具失败不能让整个 Agent 崩溃
python
tools_registry = {
"read_file": {"fn": read_file, "schema": {...}},
"web_search": {"fn": web_search, "schema": {...}},
"execute_code": {"fn": execute_code, "schema": {...}},
}
def execute_tools(tool_calls):
results = []
for call in tool_calls:
try:
result = tools_registry[call.name]["fn"](**call.args)
results.append({"status": "success", "output": result})
except Exception as e:
results.append({"status": "error", "output": str(e)})
return results
工具系统要尽量简单、透明、可测试。每个工具都应该有清晰的输入 schema、输出结构、错误类型和权限边界。不要把业务逻辑、权限校验、异常处理全部塞进一个工具函数里,否则后续会很难排查。
护栏和终止条件
没有护栏的 Agent 会死循环,或者烧穿你的账单。至少需要:
- 最大步数限制:防止无限循环
- Token 预算上限:防止成本失控
- 连续错误熔断:同一个工具连续失败 3 次就该停
- 高风险操作确认点:删除、发送、部署前暂停
Agent 的不可控性,很多时候来自"没有明确停止条件"。一个生产级 Agent 必须知道什么时候继续、什么时候暂停、什么时候请求人工确认、什么时候彻底终止。
P1:生产环境必须有
上下文管理
LLM 有窗口限制。长任务跑到一半 context 撞墙,前面所有推理和工具结果都可能白费。你需要:
- Token 计数:知道还剩多少上下文空间
- 消息压缩 / 摘要:早期对话做摘要,保留近期完整内容
- System prompt 动态组装:根据当前阶段注入不同指令
上下文管理的关键是"保留决策所需信息,丢弃过程噪声"。早期工具日志、重复解释、无效尝试都可以压缩;用户目标、关键约束、外部系统返回的重要事实必须保留。
错误处理与重试
现实世界里工具调用必然出错:网络超时、API 限流、格式异常、权限失败、外部服务不可用。需要:
- 指数退避重试
- 降级策略:主工具不可用时切备选
- 错误信息回传给 LLM,让它调整策略
错误处理不能只停留在 try/except。你需要区分哪些错误可以重试,哪些错误需要换路径,哪些错误必须交给人处理。把所有异常都变成字符串塞回 LLM,看起来简单,实际会让 Agent 行为变得不可预测。
P2:规模化后才需要
记忆系统
- 短期记忆:就是 messages 列表,天然存在
- 长期记忆:跨会话持久化,通常用向量数据库 + 语义检索
先试最简方案:把关键信息塞回 system prompt。不够用时再上向量检索,别过早引入复杂度。
记忆系统最容易被过度设计。很多项目以为自己需要长期记忆,实际只需要在当前任务中保存几个关键状态。真正需要长期记忆的场景,通常具备跨会话连续性,比如长期客户偏好、项目上下文、历史操作记录。
日志与可观测性
记录每一步的输入输出、token 消耗、执行时间。这属于生产排障的基础设施。
当 Agent 在生产环境出现诡异行为,没有 trace 你根本无法定位问题。你需要知道它当时看到了什么上下文,为什么选择某个工具,工具返回了什么,LLM 如何解释结果,最终如何生成动作。
规划能力
让 Agent 在执行前先输出步骤计划,再逐步执行。这对复杂任务的成功率有显著提升,但简单任务不需要。
规划能力适合多步骤、高不确定性、高风险任务。对于简单查询、单次工具调用、固定流程任务,额外规划反而会增加 token 开销和延迟。
五、决策模型:一棵可以直接用的决策树
objectivec
你的 Agent 项目 →
│
├─ 只有 1 个 Agent + 几个工具?
│ └─ YES → 裸写。50 行代码解决,框架是负担。
│
├─ 多个 Agent 需要协作?
│ ├─ 协作模式是线性分工(A做完给B)?
│ │ └─ YES → CrewAI 做原型验证,确认价值后评估是否迁移 LangGraph
│ └─ 协作模式有条件分支/循环/人工节点?
│ └─ YES → LangGraph,别犹豫
│
├─ 需要持久化、断点恢复?
│ └─ YES → 框架(LangGraph / Microsoft Agent Framework),自研这个太贵
│
├─ 被绑在某朵云上?
│ ├─ Azure/.NET → Microsoft Agent Framework
│ ├─ GCP/Gemini → Google ADK
│ └─ OpenAI 生态 → OpenAI Agents SDK
│
├─ 项目周期 < 1 个月,验证想法?
│ └─ YES → 裸写或最轻量框架(Pydantic AI / Agno)
│
└─ 自己维护的编排代码 > 500 行且跟业务逻辑无关?
└─ YES → 该引入框架了,你在重复造轮子
这棵树背后的核心判断标准只有一个:你的复杂度主要来自业务能力,还是来自编排本身。
如果复杂度来自 prompt、工具质量、检索效果、模型能力,框架帮不上太多忙。如果复杂度来自状态转移、流程恢复、人工节点、多 Agent 协调、审计追踪,框架会显著降低长期维护成本。
六、场景实战
场景一:客服 Agent
需求:接入企业知识库,回答用户问题,必要时转人工。
选择:裸写
理由:本质上就是一个 RAG + 工具调用循环。工具只有"检索知识库"和"转人工"两个。用 LangGraph 画一张图来表达"检索 → 回答 → 用户不满意 → 转人工"这个流程,是用牛刀杀鸡。
核心代码 100 行以内可以搞定,重点精力应该放在 RAG 的检索质量上,比如文档切分、召回策略、rerank、权限过滤、答案引用、拒答策略。客服 Agent 的瓶颈通常在知识库质量和答案可信度,编排层不应成为早期投入重点。
场景二:自动化代码审查 Agent
需求:读 PR diff → 多维度审查(安全、性能、风格)→ 汇总报告 → 有严重问题时阻断合并。
选择:裸写,但加规划层
理由:看起来是多 Agent,比如安全审查员、性能审查员、风格审查员,但它们之间没有真正交互,只是并行执行然后汇总。用 asyncio.gather() 并行调用三次 LLM,比引入 CrewAI 的角色系统简单得多,token 消耗也低得多。
scss
reviews = await asyncio.gather(
review_security(diff),
review_performance(diff),
review_style(diff),
)
summary = await synthesize(reviews)
这个场景真正需要关注的是审查维度设计、diff 压缩、规则库注入、误报控制和报告结构化。把它包装成多角色协作,反而会增加额外上下文和协调成本。
场景三:金融合规审批流
需求:文档提交 → AI 初审 → 规则引擎校验 → 人工复核 → 通过 / 驳回 / 补件 → 归档。流程中任何一步失败,都可能需要回退到前序步骤,全程需要审计日志。
选择:LangGraph
理由:这里有明确的状态机:多个状态、条件转移、人工节点、失败回退、跨天审批、审计追踪。它还需要持久化,因为审批流程可能持续数小时甚至数天;也需要可追溯性,因为每一步的决策和依据都要记录。
这正是 LangGraph 的甜区。裸写这个状态机可以做到,但维护成本会随业务规则增加快速上升。每新增一种审批分支、补件规则、风控策略,都可能影响已有状态转移。用图工作流表达,会让复杂度更可控。
七、踩坑经验
坑一:从 CrewAI 迁移到 LangGraph
一个做内容生产的团队,最初用 CrewAI 搭了"选题 → 研究 → 撰写 → 编辑"流水线,demo 效果很好。但上生产后发现:
- 编辑 Agent 否决文章后,没有优雅的方式让它回到撰写环节重做
- 偶尔网络超时导致中间状态丢失,整个流程要从头跑
- Token 消耗比预期高 3 倍,CrewAI 的角色描述和协调指令吃掉大量 context
迁移到 LangGraph 花了 3 周,基本是重写。
教训:如果你的流程有"回退"需求,一开始就别选 CrewAI。线性流水线可以用 CrewAI 快速验证,带状态回退的复杂流程应该直接选图工作流。
坑二:裸写失控的信号
另一个团队坚持裸写,最初很顺畅。但 Agent 从 2 个增长到 6 个后:
- 编排逻辑散落在 8 个文件里,没人能一眼看出完整流程
- 状态通过全局字典传递,调试时根本不知道某个值是谁在什么时候改的
- 每次加新 Agent 都要改三个地方的代码,经常漏改
当你发现"加一个 Agent 的边际成本在上升"时,就该引入框架了。
裸写失控通常有几个信号:状态传递越来越隐式,流程图只能靠人脑记忆,新增节点会影响多个旧节点,排查问题必须全链路打日志。出现这些迹象,说明你已经在重复造编排层的轮子。
坑三:过早优化架构
最常见的坑:项目还在验证"AI 到底能不能做这件事"的阶段,就花两周搭框架、设计插件系统、写抽象层。结果 AI 能力本身不达标,整个项目被砍掉,框架白搭。
先证明价值,再优化架构。
50 行裸写代码能验证的事情,不需要 2000 行的框架集成。早期最重要的指标是任务成功率、人工替代率、成本、延迟和用户接受度。等这些指标跑通后,再考虑工程化、框架化和平台化。
八、结论:我的明确立场
经历过足够多的项目后,我的判断是:
大部分 Agent 项目不需要框架。
我做过的项目里,60% 最终的生产版本是"LLM API + 工具循环 + 自己写的状态管理"。框架的抽象在演示时优雅,但生产环境的各种边界情况往往需要绕过框架处理。
真正需要框架的信号只有三个:
- 多 Agent 间有复杂的协调逻辑:超出简单并行,进入有状态交互
- 流程需要持久化和断点恢复
- 审计和合规要求每一步决策可追溯
如果这三个都不沾,裸写就是最优解。代码量少、调试简单、迭代快、token 省。
最后一句话:框架解决编排复杂度,无法替代 Agent 能力本身。如果你的 Agent 不够智能,换框架不会让它变聪明。先把核心的 prompt engineering 和工具设计做对,再考虑编排层的事情。
推荐资源
- echo-agent --- 无框架依赖的 Agent 实现,工具循环 + 状态管理 + 护栏机制,适合作为自研路径的参考起点
- LangGraph 官方文档 --- 如果你决定用框架,从这里开始
- Pydantic AI --- 追求类型安全和代码质量的轻量方案