智能体面试准备(八):LangChain / LlamaIndex / CrewAI 深度对比——架构哲学、代码范式与选型答题框架
系列第二篇曾从宏观视角对比过 LangChain/AutoGPT/MetaGPT/AutoGen 四个框架的定位。这一篇往深处走:聚焦当前生产环境使用率最高的三个技术栈——LangChain(含 LangGraph)、LlamaIndex、CrewAI,从架构哲学、核心抽象、代码范式三个层面拆解,并给出面试选型题的标准答题框架。这类题在面试里的真实形态往往不是"介绍一下 LangChain",而是"你为什么用 X 不用 Y"或"让你搭一个 XX 系统你选什么框架"——考的是技术判断,不是文档背诵。
一、三个框架的出身决定了架构哲学
理解框架先看它"为解决什么问题而生",这决定了它的核心抽象和能力边界。
LangChain:为"编排"而生。2022 年底诞生,最初的核心抽象是 Chain(链)——把提示词、模型调用、输出解析串成可复用的流水线,后来发展出 LCEL(管道式声明语法)。它想当 LLM 应用的"全家桶胶水层":模型接入、提示词管理、工具、记忆、检索全都有封装。2024 年起重心转向LangGraph——用状态机/图来建模 Agent 工作流:节点是计算步骤,边是流转条件,共享一个显式 State。LangGraph 解决了老版 AgentExecutor "黑盒循环不可控"的痛点,支持循环、分支、人工审批中断、状态持久化(checkpoint),是三者中控制粒度最细的。
LlamaIndex:为"数据"而生。前身叫 GPT Index,出发点是"怎么把私有数据喂给 LLM"。核心抽象全是数据侧的:Document/Node(文档与切块)、Index(索引结构)、Retriever(检索器)、Query Engine(查询引擎)。它在 RAG 这条线上的深度无出其右:几十种索引结构(向量、树状、关键词、知识图谱)、层级检索、句子窗口检索、自动合并检索等高级策略开箱即用。Agent 能力(ReActAgent、FunctionAgent、AgentWorkflow)是后来补的,定位偏向"以数据查询为中心的 Agent"。
CrewAI:为"角色协作"而生。2023 年底出现,抽象直接映射人类团队:Agent(带 role/goal/backstory 的角色)、Task(任务)、Crew(团队)、Process(协作流程:顺序/层级)。它赌的是"多 Agent 协作会成为主流形态",把角色分工范式做到了极致的易用——几十行代码就能跑起一个"研究员+写手"团队。底层不依赖 LangChain(自研核心),近年补上了 Flows(事件驱动的确定性编排)来对标 LangGraph 的精细控制。
一句话总结哲学差异:LangChain/LangGraph 把 Agent 建模为"图上的状态流转",LlamaIndex 把 Agent 建模为"数据查询的智能路由",CrewAI 把 Agent 建模为"团队里的角色"。
二、核心维度对比表
| 维度 | LangChain + LangGraph | LlamaIndex | CrewAI |
|---|---|---|---|
| 核心抽象 | Graph / Node / Edge / State | Index / Retriever / QueryEngine | Agent / Task / Crew / Process |
| 架构哲学 | 显式状态机,控制流优先 | 数据管道优先,查询为中心 | 角色协作优先,拟人化分工 |
| RAG 能力 | 有但偏基础组件拼装 | 最强(高级检索策略最全) | 弱(常内嵌 LlamaIndex 补足) |
| 多 Agent 支持 | LangGraph 手工搭(灵活但代码多) | AgentWorkflow(较新) | 开箱即用(顺序/层级流程) |
| 控制粒度 | 最细(每条边可编程、可中断) | 中 | 粗(高抽象,深度定制要下钻) |
| 状态持久化 | Checkpoint 机制成熟(断点续跑/时间旅行) | 有基础支持 | Flows 提供部分能力 |
| 学习曲线 | 陡(概念多、版本变动快) | 中(RAG 场景内平缓) | 最平缓(半天可出 demo) |
| 可观测性 | LangSmith(生态最成熟) | 回调体系+第三方集成 | 内置日志+第三方集成 |
| 适合场景 | 复杂工作流、需人工审批、状态机类业务 | 知识库问答、文档密集型应用 | 内容生产、调研报告等角色分工任务 |
| 主要风险 | 抽象层厚、调试心智负担大 | Agent 编排能力相对年轻 | 高抽象牺牲灵活性、复杂场景易顶到天花板 |
面试画这张表时,重点强调三行:RAG 能力、多 Agent 支持、控制粒度——这三行基本决定选型。
三、同一任务三种写法:代码范式对比
看代码范式最能体现框架气质。任务:"检索资料并生成摘要报告"。
LangGraph 风格——显式状态机(伪代码骨架,突出图结构):
from typing import TypedDict class State(TypedDict): query: str; docs: list; report: str; approved: bool def retrieve(state): return {"docs": search(state["query"])} def write(state): return {"report": llm_write(state["docs"])} def review(state): return {"approved": llm_review(state["report"])} # graph.add_node("retrieve", retrieve) ... add_conditional_edges( # "review", lambda s: "write" if not s["approved"] else END) # 特点:流程即图,每步可断点、可回放、可插人工审批CrewAI 风格——角色声明:研究员 Agent + 写手 Agent,Crew 按顺序流程执行,开发者不写控制流,框架内部调度。LlamaIndex 风格——查询引擎:先VectorStoreIndex.from_documents(docs)建索引,再index.as_query_engine().query(...),Agent 只是包在查询引擎外面的一层路由。
下面给一段可直接运行的代码——不依赖任何框架,实现三个框架共同的底层机制"工具路由 + 状态流转",用来向面试官证明你理解框架在替你做什么(这也是"框架黑盒论"的最好回应):
import json class MiniGraph: """LangGraph 核心机制的极简复刻:节点+条件边+共享状态""" def __init__(self): self.nodes, self.edges = {}, {} def add_node(self, name, fn): self.nodes[name] = fn def add_edge(self, src, router): """router: state -> 下一个节点名 或 'END'""" self.edges[src] = router def run(self, entry, state, max_steps=20): cur, trace = entry, [] for _ in range(max_steps): state.update(self.nodes[cur](state) or {}) trace.append(cur) nxt = self.edges[cur](state) if nxt == "END": state["__trace__"] = "->".join(trace + ["END"]) return state cur = nxt raise RuntimeError("超过最大步数,疑似死循环") # ---- 用 MiniGraph 搭"检索->写作->审查->(不过关则重写)"工作流 ---- def retrieve(s): return {"docs": [f"关于「{s['query']}」的资料{i}" for i in range(3)]} def write(s): version = s.get("version", 0) + 1 return {"report": f"[v{version}] 基于{len(s['docs'])}份资料的报告", "version": version} def review(s): return {"approved": s["version"] >= 2} # 模拟:第一版打回,第二版通过 g = MiniGraph() g.add_node("retrieve", retrieve) g.add_node("write", write) g.add_node("review", review) g.add_edge("retrieve", lambda s: "write") g.add_edge("write", lambda s: "review") g.add_edge("review", lambda s: "END" if s["approved"] else "write") result = g.run("retrieve", {"query": "Agent框架选型"}) print(json.dumps(result, ensure_ascii=False, indent=2)) # __trace__: retrieve->write->review->write->review->END这 40 行代码就是 LangGraph 的心智模型:状态字典 + 节点函数 + 条件路由。运行输出的__trace__展示了"审查不通过→回到写作节点"的循环——这正是老式线性 Chain 做不到、而 Agent 工作流必需的能力。面试时给出这个实现,再说"LangGraph 在此之上加了持久化 checkpoint、并行分支、人工中断和 tracing",理解深度立刻和背文档的候选人拉开差距。
四、选型答题框架:四问定位法
面试官问"你会选哪个框架",用四个问题定位,展示的是决策方法而不是站队:
第一问:任务的核心复杂度在哪?复杂度在数据侧(异构文档、检索质量决定成败)→ LlamaIndex;复杂度在流程侧(多步骤、条件分支、需要人工审批)→ LangGraph;复杂度在分工侧(多角色产出内容)→ CrewAI。
第二问:对控制粒度的要求?金融、医疗等强合规场景要求每一步可审计、可中断、可回放 → LangGraph 的 checkpoint 和 human-in-the-loop 是刚需;内部工具或 demo → CrewAI 的高抽象反而是生产力。
第三问:团队工程能力与项目周期?一周出原型验证价值 → CrewAI/LlamaIndex 高层 API;长期演进的核心系统 → 宁可用 LangGraph 甚至自研薄框架,避免被厚抽象锁死。
第四问:要不要框架?这是最加分的一问。主动说:框架不是必选项。OpenAI 的 Swarm/Agents SDK 与 Anthropic 的工程实践都提倡"能用简单可组合模式就不上重框架"。自研薄层(几百行:LLM 调用 + 工具注册 + 状态机 + tracing)换来完全可控和零升级绑架,代价是要自己造持久化、重试、观测的轮子。判断标准:当框架文档阅读时间超过自己实现核心循环的时间,且业务对可控性敏感,就该考虑自研——上面那个 MiniGraph 就是证明成本没那么高的论据。
回答模板(30 秒版):"我会先看复杂度落点:数据密集选 LlamaIndex,流程密集选 LangGraph,角色分工型选 CrewAI;再看合规与控制粒度要求;核心长期系统我会评估自研薄框架。我在 XX 项目里选了 XX,因为 XX——踩过的坑是 XX。"最后这句项目落点必须有,否则前面全是纸上谈兵。
五、高频追问与避坑
- "LangChain 被很多人骂抽象过度,你怎么看?"——承认批评有依据(早期 AgentExecutor 黑盒、版本破坏性变更频繁),但要指出 LangGraph 已转向显式控制流,且 LangSmith 生态是生产可观测性的现实优势。辩证回答,不跟风踩。
- "CrewAI 和 AutoGen 的多 Agent 有什么区别?"——CrewAI 是"角色+任务"的结构化分工(流程可预定义),AutoGen 是"对话驱动"的自由协作(Agent 间聊天推进任务),前者可控性强,后者灵活但终止条件难控。
- "LlamaIndex 和 LangChain 能一起用吗?"——能且常见:LlamaIndex 做检索层(Query Engine 封装成工具),LangGraph 做编排层。框架不是排他的,按层组合是生产常态。
- "框架升级导致代码崩过吗?"——诚实答,并给出防御手段:锁版本、把框架 API 收敛到自己的适配层(adapter)里,业务代码不直接 import 框架符号。
下一篇进入工作流编排:DAG 与状态机的工程实现。