第 07 篇拆了 LangGraph,理解了一个”图状态机”框架。本篇拆它的反面——CrewAI:一个”角色协作”框架。两者都做 Agent 编排,但哲学完全不同。本篇目标是看懂 CrewAI 的四大核心类(Agent / Tool / Task / Crew)的源码结构与协作机制,并用第 01 篇承诺过的”钓鱼日记生成”场景,把 tools/douyin-blog/generate-blog.py 的串行流程改写为 Crew 协作。
一、CrewAI 的核心抽象
1.1 四个类,四个角色
CrewAI 把所有 AI 工作流建模成”一个团队在干活”:
1 | Crew(团队) |
- Agent:不是通用的”执行者”,而是有”人格”的参与者——
role(岗位)、goal(目标)、backstory(人设背景)、tools(工具)、llm(可每个角色配不同模型)。 - Task:
description(要做什么)+expected_output(期望的产出格式)+agent(谁来做)。任务之间可以传递上下文(context)。 - Crew:编排器,
tasks列表 +process(sequential 顺序 / hierarchical 层级)。kickoff()启动整个流程。 - Process:sequential 是”任务 A → B → C”;hierarchical 引入一个 Manager Agent 动态分派任务。
1.2 与 LangGraph 的哲学对比
| 维度 | LangGraph | CrewAI |
|---|---|---|
| 心智模型 | 图 / 状态机 / 显式控制流 | 团队 / 角色 / 任务分工 |
| 控制流 | 你在代码里画边,完全显式 | sequential 自动串,hierarchical 交给 Manager |
| 状态管理 | 一等公民(State+reducer+检查点) | 隐式,靠任务上下文传递 |
| 学习成本 | 高(Pregel/检查点/流式) | 低(四个类即全貌) |
| 复杂分支 | 强(条件边、回退、并行) | 弱(hierarchical 依赖 LLM 判断) |
| 可恢复性 | 强(检查点持久化) | 弱(无内建检查点) |
| 适合场景 | 复杂状态流、需断点续跑 | 多角色分工明确、流程相对线性 |
一句话总结:LangGraph 强在”流程的确定性控制”,CrewAI 强在”角色的声明式分工”。你的流程是”图”就用 LangGraph,你的流程是”流水线分工”就用 CrewAI。
二、源码结构拆解
2.1 Agent 的本质
CrewAI 的 Agent 并不神秘——它内部就是把”role/goal/backstory + tools 描述 + 任务描述”拼成一个 system prompt,然后调 LLM:
1 | # crewai.agent.Agent.agent_executor 的关键逻辑(伪码还原) |
关键工程点:tools 的描述(JSON Schema)会注入 prompt,模型根据描述决定”调哪个工具、传什么参数”,然后 CrewAI 帮你执行函数调用(function calling),把结果再喂回模型。这就是第 03 篇”函数调用”的 Agent 化封装。
2.2 Task 的上下文传递
Task 的 context 字段决定前置任务:Crew 按顺序执行时,会把前面任务的输出注入当前任务的上下文。这是隐式状态传递——与 LangGraph 的显式 reducer 形成对比。好处是写起来简单,坏处是”状态在哪个 Agent 手里”不透明。
2.3 Crew 的 kickoff
Crew.kickoff() 内部维护一个任务队列,sequential 模式下逐个执行;hierarchical 模式下先让 Manager 决定每个任务分配给谁。内部还有一个核心组件 TaskOutput / AgentOutput 数据结构,把每个任务的输出和元数据(token 用量、耗时)结构化——这正是第 11 篇可观测性要采集的数据源。
三、实战:钓鱼日记生成流水线改写
tools/douyin-blog/generate-blog.py 现在是一个 22KB 的串行 Python 脚本:读取 videos.json → 按日期找相册图片 → 调 DeepSeek 生成日记 → 写草稿。流程是”一步到底”,没有分工,也没有中间产物。
3.1 改写为 Crew
1 | Crew: 钓鱼日记编辑部 |
1 | from crewai import Agent, Task, Crew, Process |
3.2 对比:CrewAI 版 vs 原串行版
| 维度 | 原 generate-blog.py | CrewAI 版 |
|---|---|---|
| 代码结构 | 一个函数串到底 | 四角色职责分离 |
| 中间产物 | 无(一次生成) | 素材清单→大纲→草稿→SEO,每步可审查 |
| 改一处逻辑 | 改主函数,牵一发动全身 | 只改对应 Agent 的 role/goal |
| 每角色模型 | 单一模型 | 可给校对 Agent 配更强/更弱模型 |
| 可控性 | 完全确定 | 依赖 prompt 质量,需人工审查 |
| 部署 | 纯脚本 | 依赖 crewai 包,运行成本更高 |
结论:对于”生成一篇日记”这种角色分工明确的线性任务,CrewAI 的声明式写法更清晰、更易维护、可插拔(想给校对加工具,给 Agent 加一行就行)。但注意——改写不等于必然更好,原脚本一次调用 1 次 DeepSeek,Crew 版要 4 次调用(4 个 Agent),成本翻 4 倍。这是第 10 篇要深入讨论的成本问题。
四、LangGraph vs CrewAI:同场景对比复盘
用第 07 篇的”鱼获数据提取 Agent”在同一场景下对比:
| 场景需求 | LangGraph | CrewAI |
|---|---|---|
| 提取失败自动重试(条件边) | 原生支持,显式 | 无原生,需 Manager 或外部循环 |
| 提取到一半崩溃恢复 | 检查点 + thread_id | 无内建,需自建重入 |
| 拆成”提取员/校验员/写入员” | 也能做,但要自己画图 | 声明式,更自然 |
| 需要并行提取多篇 | 超步天然并行 | 需 await_fork 或自定义 |
选型最终建议(回扣第 01 篇决策树):
- 有重试/分支/持久化需求 → LangGraph
- 多角色线性分工、重视可读性 → CrewAI
- 两者可以混用:CrewAI 管”角色分工”,外层用 LangGraph 画”流程控制图”,把每个 Crew 当一个节点——这是大型系统常见做法(第 10 篇实践)。
五、落地清单与小结
- CrewAI 四类核心:Agent(角色人设 + 工具)、Task(描述 + 期望输出 + 上下文)、Crew(编排器)、Process(sequential/hierarchical)。
- Agent 本质 = 动态 system prompt + function calling 封装,工具描述注入 prompt 让模型决定调用。
- 与 LangGraph 对比:确定性控制选 LangGraph,角色分工选 CrewAI;CrewAI 无内建检查点,可恢复性弱。
- 钓鱼日记生成流水线改写为 4 角色 Crew:素材→策划→写作→SEO,职责清晰、可审查,但成本从 1 次调用变 4 次——工程决策要算账。
- 大型系统可混用:LangGraph 画流程图,CrewAI 做分工节点。
下一篇进入工具层:自研 MCP Server 实战。把博客的数据(TiDB 鱼获、文章检索、Hexo 草稿)封装成标准 MCP Server,接进 Claude/Cursor,实现”AI 助手直接操作博客工具”。
本系列持续更新中,每周一篇。