LangChain vs CrewAI vs 从零搭建 — 我的经验

LangChain vs CrewAI vs 从零搭建 — 我的经验
开场
过去一年我用 LangChain 搭过 3 个项目,用 CrewAI 搭过 2 个,还从零写过一个不依赖任何框架的 Agent 系统。最终的结论可能会让你意外:框架不是越重越好,也不是完全不用框架就最好——关键在于你的项目处在什么阶段,团队有什么样的技术能力。
问题背景
2026 年的 AI Agent 框架市场,LangChain(含 LangGraph)和 CrewAI 是最活跃的两个选手。LangChain 在 PyPI 上月下载量超过 4700 万次,是最大的生态系统。CrewAI 增长最快,尤其在 multi-agent 场景。
但还有第三条路:从零搭建。直接调用 Claude 或 GPT 的 API,自己写 Agent 循环、Tool 调用、状态管理。听起来复杂,但在某些场景下反而是最高效的选择。
我把三种方式都跑过实际项目,这篇文章分享真实的对比数据和选型建议。
核心对比
LangChain + LangGraph
LangChain 是 2023 年起步的 Agent 框架,到 2026 年已经进化出了 LangGraph——一个基于有向图的 Agent 编排引擎。核心思路是:你用节点(Node)表示每个处理步骤,用边(Edge)定义步骤之间的流转关系。
from langgraph.graph import StateGraph, MessagesState, START, END
from langchain_anthropic import ChatAnthropic
from langchain_core.tools import tool
# 定义工具
@tool
def search_database(query: str) -> str:
"""搜索产品数据库"""
# 实际的数据库查询逻辑
return f"找到 3 条关于 '{query}' 的结果"
@tool
def calculate_price(product_id: str, quantity: int) -> str:
"""计算商品总价"""
# 实际的价格计算逻辑
prices = {"SKU001": 99.0, "SKU002": 149.0}
total = prices.get(product_id, 0) * quantity
return f"总价: ¥{total}"
# 初始化模型
model = ChatAnthropic(
model="claude-sonnet-4-5-20250514"
).bind_tools([search_database, calculate_price])
# 定义图节点
def call_model(state: MessagesState):
response = model.invoke(state["messages"])
return {"messages": [response]}
def call_tools(state: MessagesState):
"""执行工具调用"""
last_message = state["messages"][-1]
results = []
for tool_call in last_message.tool_calls:
if tool_call["name"] == "search_database":
result = search_database.invoke(tool_call["args"])
elif tool_call["name"] == "calculate_price":
result = calculate_price.invoke(tool_call["args"])
results.append({"role": "tool", "content": result, "tool_call_id": tool_call["id"]})
return {"messages": results}
# 构建图
def should_continue(state: MessagesState):
last = state["messages"][-1]
if hasattr(last, "tool_calls") and last.tool_calls:
return "tools"
return END
graph = StateGraph(MessagesState)
graph.add_node("agent", call_model)
graph.add_node("tools", call_tools)
graph.add_edge(START, "agent")
graph.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END})
graph.add_edge("tools", "agent")
app = graph.compile()
LangGraph 的优势:
- 状态管理清晰——每一步的输入输出都有明确定义
- 支持循环和条件分支——适合复杂的 Agent 逻辑
- 内置 checkpoint 机制——可以持久化中间状态,支持断点恢复
- 社区生态大——各种 integration 和示例代码很多
LangGraph 的问题:
- 抽象层太多——一个简单的 tool call 需要经过 LangChain Core、LangGraph、Provider 三层封装
- 版本迭代太快——我去年的代码今年跑不了,API breaking change 频繁
- Debug 困难——报错信息经常指向框架内部,不容易定位问题
CrewAI
CrewAI 的核心抽象是 "角色"。你不需要思考节点和边,只需要定义谁来做什么:
from crewai import Agent, Task, Crew, Process
# 定义 Agent(按角色)
researcher = Agent(
role="市场调研员",
goal="收集竞品的价格、功能和用户评价数据",
backstory="你是一个资深的市场分析师,擅长从公开信息中提取关键洞察",
llm="anthropic/claude-sonnet-4-5-20250514",
verbose=True
)
writer = Agent(
role="内容写手",
goal="基于调研数据撰写分析报告",
backstory="你是一个技术内容专家,擅长把复杂信息写成可读性强的文章",
llm="anthropic/claude-sonnet-4-5-20250514",
verbose=True
)
reviewer = Agent(
role="质量审核员",
goal="确保报告的准确性和可读性",
backstory="你是一个严格的编辑,关注数据准确性和逻辑一致性",
llm="anthropic/claude-haiku-4-5-20250514", # 审核用便宜模型
verbose=True
)
# 定义任务
research_task = Task(
description="调研以下竞品的最新定价和核心功能: {products}",
expected_output="结构化的竞品分析数据(JSON 格式)",
agent=researcher
)
writing_task = Task(
description="基于调研数据,写一篇 2000 字的竞品分析报告",
expected_output="Markdown 格式的分析报告",
agent=writer,
context=[research_task] # 依赖调研任务的输出
)
review_task = Task(
description="审核报告的质量,检查数据准确性和逻辑性",
expected_output="审核意见和修改建议",
agent=reviewer,
context=[writing_task]
)
# 组建团队并执行
crew = Crew(
agents=[researcher, writer, reviewer],
tasks=[research_task, writing_task, review_task],
process=Process.sequential, # 顺序执行
verbose=True
)
result = crew.kickoff(inputs={"products": "ChatGPT, Claude, Gemini"})
CrewAI 的优势:
- 抽象直观——角色 + 任务的模型符合人的思维方式
- 上手快——30 分钟可以跑通一个 multi-agent 流程
- 内置 Agent 间通信——不需要手动传数据
CrewAI 的问题:
- 底层仍然依赖 LangChain——CrewAI 建立在 LangChain 的基础上,继承了它的一些复杂性
- 灵活性受限——复杂的条件分支和循环很难实现
- 生产特性不足——缺少内置的错误重试、速率限制、监控
从零搭建
当你需要完全控制 Agent 的行为,或者项目逻辑简单到不需要框架的抽象时,直接写是最高效的:
import anthropic
from dataclasses import dataclass
@dataclass
class AgentConfig:
name: str
system_prompt: str
model: str = "claude-sonnet-4-5-20250514"
max_tokens: int = 4096
class SimpleAgent:
"""一个不依赖任何框架的 Agent 实现"""
def __init__(self, config: AgentConfig):
self.config = config
self.client = anthropic.Anthropic()
self.tools: dict[str, callable] = {}
def register_tool(self, name: str, description: str, schema: dict, func: callable):
"""注册一个工具"""
self.tools[name] = {
"definition": {
"name": name,
"description": description,
"input_schema": schema
},
"func": func
}
def run(self, user_input: str) -> str:
"""执行 Agent 循环"""
messages = [{"role": "user", "content": user_input}]
tool_defs = [t["definition"] for t in self.tools.values()]
# Agent 循环:调用 LLM → 执行工具 → 再调用 LLM
for _ in range(10): # 最多 10 轮,防止无限循环
response = self.client.messages.create(
model=self.config.model,
max_tokens=self.config.max_tokens,
system=self.config.system_prompt,
tools=tool_defs if tool_defs else None,
messages=messages
)
# 如果模型直接回复(没有 tool call),返回结果
if response.stop_reason == "end_turn":
return self._extract_text(response)
# 处理 tool call
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = self.tools[block.name]["func"](**block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": str(result)
})
messages.append({"role": "user", "content": tool_results})
return "达到最大循环次数,请简化问题"
def _extract_text(self, response) -> str:
return "".join(b.text for b in response.content if b.type == "text")
# 多 Agent 编排(极简版)
class AgentPipeline:
"""顺序执行多个 Agent"""
def __init__(self):
self.steps: list[tuple[SimpleAgent, str]] = []
def add_step(self, agent: SimpleAgent, prompt_template: str):
self.steps.append((agent, prompt_template))
def run(self, initial_input: str) -> str:
current_output = initial_input
for agent, template in self.steps:
prompt = template.format(input=current_output)
current_output = agent.run(prompt)
return current_output
从零搭建的优势:
- 零依赖——不用担心框架版本更新导致代码失效
- 完全可控——每一行代码都是你写的,debug 直接定位
- 性能最优——没有框架的抽象开销
从零搭建的问题:
- 基础设施要自己造——错误处理、重试、日志、监控全要自己写
- 复杂编排时代码量大——条件分支、并行执行、状态持久化需要大量代码
- 团队协作成本高——没有统一的抽象,每个人可能写出不同风格的 Agent 代码
实战经验
三个项目的真实对比
| 维度 | 项目 A (LangGraph) | 项目 B (CrewAI) | 项目 C (从零) |
|---|---|---|---|
| 项目类型 | 客服 Agent | 内容生产 | 数据分析 |
| 开发时间 | 3 周 | 1 周 | 2 周 |
| 代码行数 | 2,400 行 | 800 行 | 1,600 行 |
| 运行延迟 | 4.2s/请求 | 12.5s/任务 | 3.1s/请求 |
| 框架开销 | ~200ms | ~800ms | 0ms |
| 维护难度 | 中(版本升级频繁) | 低 | 中(自建组件多) |
| 可扩展性 | 高 | 中 | 高(但要自己写) |
注意运行延迟的数据:CrewAI 在执行 3 个 Agent 顺序任务时耗时 12.5 秒,其中约 800ms 是框架本身的 overhead(Agent 角色初始化、内部通信协议)。LangGraph 的 overhead 约 200ms,从零搭建的 overhead 为 0。
选型决策框架
经过这三个项目,我总结了一个选型决策树:
问 1:你的 Agent 逻辑有多复杂?
- 简单线性流程(A → B → C)→ CrewAI 或从零搭建
- 有条件分支和循环 → LangGraph
- 极简单(一个 Agent + 几个 Tool)→ 从零搭建
问 2:你的团队技术水平?
- 产品/运营团队 → CrewAI(抽象最直观)
- 工程团队 → LangGraph 或从零搭建
- 一个人干 → 看项目复杂度决定
问 3:你对生产稳定性的要求?
- 高(面向客户的产品)→ LangGraph(成熟度最高)或从零搭建(完全可控)
- 中(内部工具)→ 三种都行
- 低(原型验证)→ CrewAI(最快)
问 4:你需要多少 integration?
- 大量第三方集成 → LangChain(生态最大)
- 少数几个 API → 从零搭建(自己写 tool 更直接)
我的真实选择
在我自己的项目中:
- 内容生产 Agent 团队(就是你正在读的这个项目)→ 从零搭建。因为流程固定,我需要精确控制每个 Agent 的 prompt 和输出格式。
- 客户 Demo:CrewAI。因为可以快速搭建一个看起来很酷的 multi-agent 演示。
- 企业客户的生产系统:LangGraph。因为客户需要持久化状态、断点恢复、审计日志,这些 LangGraph 内置支持。
总结
三条核心 takeaway:
-
没有"最好"的框架,只有最合适的框架——选型取决于项目复杂度、团队能力和生产要求,不取决于 GitHub stars。
-
框架的价值在于你用到了多少——如果你只用了 LangChain 的 ChatModel 和 Tool,那你其实不需要 LangChain。框架的价值在于它的高级特性(状态管理、checkpoint、可视化),如果你用不到,它就是纯负担。
-
从简单开始,必要时才引入框架——我的建议是先用原生 API 把 Agent 逻辑跑通,确认需要框架提供的某个特定能力后再引入。不要因为 "大家都在用" 就选了一个框架。
你现在在用哪个框架搭 Agent?踩过什么坑?欢迎分享你的经验。