掘金 人工智能 08月11日
我为什么又开始手写Agent框架了?从CrewAI和LangGraph的局限谈起
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

文章探讨了在多智能体应用开发中,直接使用CrewAI等“应用级”框架时遇到的僵化流程和控制权缺失问题,以及LangGraph这类“引擎级”工具带来的过度灵活和从零搭建的挑战。作者提出了一种折衷方案:在LangGraph强大的基础上,构建一层轻量级的“协作层”。这一层通过定义统一的“世界状态”、中心化的“调度器”和标准的“交互协议”,解决了Agent间通信、流程调度和状态管理的核心痛点。这种方法旨在让开发者从框架使用者转变为架构设计者,能够根据自身业务需求,自由组合和驾驭AI工具,打造定制化的Agent应用。

✅ **CrewAI的局限性在于其“强干预”特性**:它为Agent协作预设了标准化的“角色-任务-流程”模型,虽然在标准场景下高效,但当需要更复杂的动态流程、精细的状态管理或流程中途的控制权时,CrewAI的僵化线性流程和模糊的状态管理会成为“美丽枷锁”,限制了开发的灵活性和业务逻辑的实现。

🛠️ **LangGraph提供“自由与混沌”的引擎能力**:LangGraph作为强大的工作流引擎,赋予了开发者构建任意复杂流程的自由,但它本身不提供Agent协作的默认解决方案。这意味着开发者需要从零开始定义Agent状态、实现调度逻辑、管理工具调用等,如同从零件开始组装一辆车,门槛较高。

🚀 **自建“协作层”是破局之道**:作者提出在LangGraph基础上构建一层薄而关键的“协作层”。该层核心解决三个问题:1. 定义一个所有Agent认可的“世界状态”(统一数据结构);2. 设立一个中心化的“调度器”(LangGraph中的特殊节点),负责根据世界状态决定下一步Agent;3. 建立一套标准的“交互协议”(Agent如何写入消息,调度器如何解析),实现Agent间的解耦和中心化控制。

💡 **“协作层”带来的核心优势**:通过这层封装,实现了Agent间通过消息列表通信(解耦),由唯一的“调度器”进行中心化流程控制,并提供了极大的扩展性,允许调度器集成LLM决策或复杂业务规则。这使得开发者能够成为“汽车设计师”,用专业引擎(LangGraph)打造最适合业务的定制化Agent应用。

✨ **从“使用者”到“设计者”的价值跃迁**:作者强调,此举并非重复造轮子,而是为了夺回控制权,成为AI时代的“架构设计者”。不再仅仅是框架的使用者,而是能够有思想地组合、驾驭工具,创造出满足特定业务需求的独特解决方案,这才是AI时代架构师的真正价值所在。

大家好呀,我是技术老金

文章首发到公众号:技术老金,每天分享AI架构与实践分享!

文章内容收录到个人网站,方便阅读:vkflow.com/


一、 引言:被“框架”困住的我们

嗨,大家好,我是技术老金。

最近,我发现自己陷入了一个有趣的困境。

当我想快速搭建一个多智能体(Multi-Agent)应用时,我首先想到了CrewAI。它就像一个精装修的公寓,角色、任务、流程都替你定义好了,拎包入住,很快就能跑起来。但只要我想稍微改动一下“房型”,比如让两个Agent先碰个头,或者根据某个工具的执行结果,动态决定下一步谁来接手,我就会发现自己被困在了这精美的“枷锁”里,动弹不得。

于是,我转向了LangGraph。它就像一个堆满了顶级建材(节点、边、状态)的“毛坯房”,给了我无限的自由。我可以随心所-欲地设计任何我想要的流程,循环、分支、判断,无所不能。但很快,新的问题来了:我发现我不仅要设计流程,还要亲自设计状态管理、消息传递、工具调用、错误处理……我需要从零开始,为这个毛坯房设计一整套“水电煤”系统。

我们似乎被困在了两难的境地:要么选择一个僵化的“应用级”框架,要么选择一个过于灵活的“引擎级”工具。

有没有一条中间道路?

在反复挣扎和实践后,我得出了一个结论:有。那就是在LangGraph这种强大的“引擎”之上,构建一层我们自己的、轻量级的、符合自己团队心智模型的“协作层”。

今天,我就来聊聊,我为什么放弃了直接使用现成的框架,又开始“手写”这薄薄的一层,以及这一层到底解决了什么核心问题。

二、 CrewAI的“美丽枷锁”:当规范大于灵活

CrewAI的初衷是好的,它试图将构建Agent的过程,标准化为“角色(Agent)-任务(Task)-流程(Process)-船员(Crew)”这套模型。对于很多标准场景,这套模型非常高效。

但它的核心问题在于,它是一个“强干预”的框架。它为你做了太多决策,而这些决策,往往与你真实的、复杂的业务逻辑相悖。

它的主要局限在于:

    僵化的线性流程:默认情况下,CrewAI的任务是串行执行的。你想实现一个“A和B并行,然后结果汇总给C”的流程,会非常别扭。模糊的状态管理:Agent之间的数据传递,很大程度上依赖于一个全局的、非结构化的“上下文黑盒”。你很难精确地控制,在任务的某个阶段,哪些信息是可见的,哪些是不可见的。控制权的缺失:整个流程的调度,是由CrewAI的内部机制黑盒管理的。你无法在流程中途,根据一个外部事件或一个工具的执行结果,来动态地改变整个“剧本”。

总而言之,CrewAI更像一个**“内置了固定协作模式的Agent应用”,而不是一个让你设计协作模式的“框架”**。

三、 LangGraph的“自由与混沌”:当引擎只是引擎

LangGraph则走向了另一个极端。它极其强大,也极其“无情”。

它给了你构建任何复杂图形(Graph)的能力,但它对“什么是Agent”、“Agent之间如何对话”这些核心问题,不提供任何默认的解决方案

使用LangGraph,你很快就会意识到:

    你需要自己定义“状态”:这个状态(State)里,应该包含哪些字段?当前轮到哪个Agent?消息列表应该是什么格式?这些都需要你自己来设计。你需要自己实现“调度”:当一个Agent完成了它的任务,下一个应该由谁来接手?这个核心的调度逻辑,LangGraph把它作为一个普通的“条件边”(Conditional Edge)交给了你,你需要自己编写一个复杂的函数来实现。你需要自己管理“工具调用”:Agent调用工具的请求、工具执行的结果,如何优雅地整合进你的状态流转中?LangGraph提供了模式,但没有现成的实现。

LangGraph是一个顶级的**“工作流引擎”,但它本身,并不是一个“多智能体协作框架”**。它给了你造车的顶级发动机和变速箱,但车架、底盘、方向盘,都得你自己来造。

四、 破局之道:构建我们自己的“协作层”

现在,我的思路清晰了:我们真正需要的,不是另一个庞大的框架,而是在LangGraph这个坚实底座上,构建一层薄薄的、但至关重要的“协作层”。

这一层的核心,只解决三个问题:

    一个统一的“世界状态” (World State):定义一个所有Agent都认可的数据结构,用于记录全局信息、消息历史和任务状态。一个中心化的“调度器” (Dispatcher):它本身是LangGraph中的一个特殊节点,负责读取“世界状态”,并决定下一个应该被唤醒的Agent。一套标准的“交互协议” (Interaction Protocol):定义Agent如何向状态里写入消息,以及调度器如何解析这些消息。

我们来看一个极简的伪代码实现,你马上就能明白:

from typing import TypedDict, List, Literalfrom langgraph.graph import StateGraph, ENDfrom operator import itemgetter# 1. 定义我们自己的“世界状态”class AgentWorldState(TypedDict):    task: str    messages: List[tuple[str, str]]     next_agent: Literal["Researcher", "Writer", "FINISH"]# 2. 定义Agent节点,展示它如何与“世界状态”交互def researcher_agent_node(state: AgentWorldState):    task = state['task']    print(f"--- [Agent: 研究员] 开始工作,任务: {task} ---")    research_result = f"这是关于'{task}'的研究成果。"    # 注意:这里返回的是一个包含元组的列表,以支持状态的累加    return {"messages": [("Researcher", research_result)]}def writer_agent_node(state: AgentWorldState):    messages = state['messages']    print(f"--- [Agent: 作家] 开始工作 ---")    writing_result = f"基于以下研究成果:\n{messages[-1][1]}\n\n我完成了最终报告。"    return {"messages": [("Writer", writing_result)]}# 3. 定义我们的核心“调度器”节点def dispatcher_node(state: AgentWorldState):    last_message_sender = state['messages'][-1][0] if state['messages'] else "START"        if last_message_sender == "Researcher":        return {"next_agent": "Writer"}    elif last_message_sender == "Writer":        return {"next_agent": "FINISH"}    else: # START        return {"next_agent": "Researcher"}# 4. 在LangGraph中组装workflow = StateGraph(AgentWorldState)workflow.add_node("researcher", researcher_agent_node)workflow.add_node("writer", writer_agent_node)workflow.add_node("dispatcher", dispatcher_node) workflow.set_entry_point("dispatcher")workflow.add_conditional_edges(    "dispatcher",    itemgetter('next_agent'),    {        "Researcher": "researcher",        "Writer": "writer",        "FINISH": END    })workflow.add_edge("researcher", "dispatcher")workflow.add_edge("writer", "dispatcher")# 编译app = workflow.compile()# 运行inputs = {"task": "AI在软件开发中的作用", "messages": []}for s in app.stream(inputs, {"recursion_limit": 10}):    print(s)    print("----")

看明白了吗?通过这层薄薄的封装,我们做到了:

五、 老金总结:从“框架使用者”到“架构设计者”

我们之所以要“手写”这一层,不是为了重复造轮子,而是为了夺回控制权

CrewAI这样的框架,让你成为了一个熟练的“司机”,但它限制了你能走的路。LangGraph给了你最强的“引擎”,但它要求你成为一个“机械师”,从零件开始造车。

而我们今天探讨的思路,是让你成为一个“汽车设计师”。你使用最专业的引擎(LangGraph),但你亲自设计汽车的底盘和传动系统(我们的协作层),最终组装出一辆最适合在你的业务道路上飞驰的、独一-无二的赛车。

这,或许才是AI时代,我们架构师真正的价值所在——不满足于使用工具,而是有能力、有思想地去组合与驾驭工具。

觉得有用,别忘了给老金点个赞,关注一下!

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

LangGraph CrewAI 多智能体 Agent协作 架构设计
相关文章