【Pocket Flow】源码剖析(一):100 行代码的极简哲学——Node、Flow 与 Shared Store

发布时间:2026/7/17 16:52:57

【Pocket Flow】源码剖析(一):100 行代码的极简哲学——Node、Flow 与 Shared Store 【Pocket Flow】源码剖析一100 行代码的极简哲学——Node、Flow 与 Shared Store写在前面在拆完 OpenClaw43 万行和 LangGraph3 万行之后今天我们来看一个反其道而行的项目——Pocket Flow。它只有100 行 Python 代码零依赖却实现了 Agent、Workflow、RAG、Multi-Agent 等所有主流 LLM 应用模式。GitHub 上超过30K Star被开发者称为LLM 框架界的 Hello World。它的核心论点极其激进复杂 LLM 系统本质上就是有向图100 行代码足够。今天起我将用3 篇文章逐行拆解这 100 行代码的每一个设计决策。这是第一篇——理解 Pocket Flow 的三大核心抽象Node、Flow 和 Shared Store。 文章目录 一、Pocket Flow 是什么100 行代码能做什么️ 二、三大核心抽象Node Flow Shared Store 三、BaseNode100 行代码的第一行 四、Flowwhile 循环驱动的有向图引擎️ 五、路由机制action 字符串与运算符重载⚖️ 六、Pocket Flow vs LangGraph极简 vs 完备 七、系列预告 一、Pocket Flow 是什么100 行代码能做什么1.1 一个反常识的项目2025 年当 LangGraph 已经有 3 万行代码、OpenClaw 已经有 43 万行代码的时候Columbia 大学的 Zachary Huang 发布了一个只有 100 行 Python 代码的 LLM 框架——Pocket Flow。它没有 Channel没有 Reducer没有 Checkpoint没有 Pregel甚至没有依赖任何第三方库。但它声称能做所有其他框架能做的事Agent、Workflow、RAG、Multi-Agent、MapReduce……这听起来像是个噱头。但当你真的读完这 100 行代码你会发现它的设计极其精巧——它不是少写了代码而是找到了正确的抽象层级。就像乐高只有几种基础积木却能拼出整个世界。1.2 Pocket Flow 的核心论点Pocket Flow 的核心论点可以概括为一句话复杂 LLM 系统本质上就是有向图节点执行逻辑边决定路由共享存储传递状态。其他所有东西——Channel、Reducer、Checkpoint、Pregel——都是在这个基础上的锦上添花而非不可或缺。这个论点是否正确取决于你的场景。如果你需要生产级的持久化和人机交互那 Checkpoint 是必需的。但如果你只是想快速搭建一个 Agent 原型或者让 AI 自己写 Agent 代码Agentic Coding那 100 行代码确实够了。1.3 100 行代码的全景整个框架只有 10 个类分为四层BaseNode基类→ Node/Flow/AsyncNode核心→ BatchNode/BatchFlow批量→ Async 变体异步。核心逻辑只有 3 个Node 的 prep/exec/post 生命周期、Flow 的 while 循环编排、action 字符串路由。️ 二、三大核心抽象Node Flow Shared StorePocket Flow 的整个设计建立在三个极简抽象之上2.1 Node节点Node 是最小执行单元每个 Node 有三个方法方法输入输出职责prep(shared)共享存储任意传给 exec从 shared 读取数据准备执行参数exec(prep_res)prep 的输出任意传给 post执行核心逻辑调 LLM、搜索、计算等post(shared, prep_res, exec_res)shared 两个结果action 字符串写回 shared 决定下一步走哪条边这个三阶段设计非常像厨房流水线prep 是备料exec 是烹饪post 是出菜并决定下一道菜做什么。关键在于post 返回的 action 字符串——它决定了流程的下一步走向是条件路由的核心。2.2 Flow流程Flow 是有向图编排器它的工作方式极其简单def_orch(self,shared,paramsNone):currcopy.copy(self.start_node)whilecurr:curr.set_params(params)last_actioncurr._run(shared)currcopy.copy(self.get_next_node(curr,last_action))returnlast_action翻译成人话从 start_node 开始执行当前节点读取 action查找后继节点移动过去重复。直到没有后继节点为止。这就是一个最朴素的有向图遍历——while 循环 action 路由。2.3 Shared Store共享存储Shared Store 就是一个普通的 Python dict。所有节点通过它传递数据shared{question:什么是RAG?,docs:[],answer:}没有 Channel没有 Reducer没有版本追踪。节点直接读写 dict。简单粗暴但完全透明——你看到什么就是什么没有隐藏的合并逻辑。 三、BaseNode100 行代码的第一行3.1 BaseNode 的完整源码classBaseNode:def__init__(self):self.params,self.successors{},{}defset_params(self,params):self.paramsparamsdefnext(self,node,actiondefault):ifactioninself.successors:warnings.warn(fOverwriting successor for action {action})self.successors[action]nodereturnnodedefprep(self,shared):passdefexec(self,prep_res):passdefpost(self,shared,prep_res,exec_res):passdef_exec(self,prep_res):returnself.exec(prep_res)def_run(self,shared):pself.prep(shared)eself._exec(p)returnself.post(shared,p,e)defrun(self,shared):ifself.successors:warnings.warn(Node wont run successors. Use Flow.)returnself._run(shared)def__rshift__(self,other):returnself.next(other)def__sub__(self,action):ifisinstance(action,str):return_ConditionalTransition(self,action)raiseTypeError(Action must be a string)3.2 逐行解读__init__初始化两个字典——params节点参数和successors后继节点映射。successors 的 key 是 action 字符串value 是目标 Node。这就是有向图的边。next(node, actiondefault)注册一条从当前节点到目标节点的边标签为 action。如果 action 重复会发出警告。返回目标节点支持链式调用。prep / exec / post三个空方法子类重写。这是模板方法模式的经典实现——基类定义骨架子类填充细节。_run(shared)执行三阶段生命周期。注意_run是内部方法run是公开接口。run会检查是否有 successors如果有则警告——因为单独运行一个有后继的 Node 没有意义应该用 Flow。__rshift__重载运算符让a b等价于a.next(b)。这是 Pocket Flow 最优雅的语法糖——用连接节点像管道一样直观。__sub__重载-运算符让a - search b等价于a.next(b, search)。配合_ConditionalTransition类实现条件边的语法糖。3.3 Node 子类增加重试classNode(BaseNode):def__init__(self,max_retries1,wait0):super().__init__()self.max_retries,self.waitmax_retries,waitdefexec_fallback(self,prep_res,exc):raiseexcdef_exec(self,prep_res):forself.cur_retryinrange(self.max_retries):try:returnself.exec(prep_res)exceptExceptionase:ifself.cur_retryself.max_retries-1:returnself.exec_fallback(prep_res,e)ifself.wait0:time.sleep(self.wait)Node 在 BaseNode 的基础上只增加了一个功能重试。_exec方法包裹了exec在异常时重试最多max_retries次每次间隔wait秒。最后一次失败时调用exec_fallback默认行为是重新抛出异常子类可以重写它实现降级逻辑。这个设计非常实用——LLM 调用经常因为网络抖动或速率限制失败重试是最基本的容错手段。Pocket Flow 把它做进了核心而不是留给用户自己实现。 四、Flowwhile 循环驱动的有向图引擎4.1 Flow 的完整源码classFlow(BaseNode):def__init__(self,startNone):super().__init__()self.start_nodestartdefstart(self,start):self.start_nodestartreturnstartdefget_next_node(self,curr,action):nxtcurr.successors.get(actionordefault)ifnotnxtandcurr.successors:warnings.warn(fFlow ends: {action} not found in{list(curr.successors)})returnnxtdef_orch(self,shared,paramsNone):curr,p,last_actioncopy.copy(self.start_node),(paramsor{**self.params}),Nonewhilecurr:curr.set_params(p)last_actioncurr._run(shared)currcopy.copy(self.get_next_node(curr,last_action))returnlast_actiondef_run(self,shared):pself.prep(shared)oself._orch(shared)returnself.post(shared,p,o)defpost(self,shared,prep_res,exec_res):returnexec_res4.2 _orch最核心的 5 行代码整个 Flow 的灵魂在_orch方法中只有 5 行核心逻辑whilecurr:curr.set_params(p)last_actioncurr._run(shared)currcopy.copy(self.get_next_node(curr,last_action))这 5 行代码实现了一个完整的有向图遍历引擎curr.set_params(p)设置节点参数用于 BatchFlow 传递批量参数curr._run(shared)执行节点的 prep → exec → post 生命周期返回 actionget_next_node(curr, last_action)根据 action 查找后继节点copy.copy(curr)深拷贝节点确保每次执行都是干净的4.3 为什么用 copy.copy这是一个容易被忽略但极其重要的细节。copy.copy(self.start_node)确保每次进入 Flow 时节点都是干净的——没有上一次执行留下的状态残留。这意味着同一个 Flow 可以被多次调用每次都是独立的执行。4.4 Flow 本身也是 Node注意 Flow 继承自 BaseNode这意味着Flow 可以作为 Node 嵌套在另一个 Flow 中——这就是子图Subgraph模式。你可以把一个复杂的 Agent 封装成一个 Flow然后把它作为节点插入更大的工作流中。️ 五、路由机制action 字符串与运算符重载5.1 action 字符串路由Pocket Flow 的路由机制极其简洁——post 方法返回一个字符串Flow 根据这个字符串查找 successors 字典。没有条件边类没有路由函数没有版本追踪。就是一个字符串 → 字典查找。# 定义条件边search_node-searchsearch_node# 继续搜索search_node-answeranswer_node# 回答问题# Node 的 post 方法返回 actiondefpost(self,shared,prep_res,exec_res):ifneed_more_search:returnsearchelse:returnanswer5.2 运算符重载DSL 语法糖Pocket Flow 重载了两个运算符让图的定义像写管道一样直观运算符等价调用用途a ba.next(b)默认边action“default”a - x ba.next(b, x)条件边action“x”# 线性流程node_anode_bnode_c# 条件分支decide-searchsearch_node decide-answeranswer_node# 循环search_node-searchsearch_node# 自循环search_node-answeranswer_node5.3 _ConditionalTransition连接 - 和 的桥梁class_ConditionalTransition:def__init__(self,src,action):self.src,self.actionsrc,actiondef__rshift__(self,tgt):returnself.src.next(tgt,self.action)当你写a - search b时Python 先计算a - search返回一个_ConditionalTransition对象然后调用它的__rshift__方法完成a.next(b, search)。这是一个精巧的 DSL 设计——用最少的代码实现了最直观的语法。⚖️ 六、Pocket Flow vs LangGraph极简 vs 完备维度Pocket FlowLangGraph代码量100 行3 万行依赖零依赖langchain-core 等状态管理dict 直写Channel Reducer路由机制action 字符串版本追踪 条件边函数并行执行AsyncParallelBatchNodePregel BSP持久化无CheckpointMemory/SQLite/PG人机交互无interrupt update_state学习曲线5 分钟2-3 天适用场景原型 / Agentic Coding生产级 Agent核心哲学框架应该足够简单让 AI 能自己写框架应该足够完备让开发者不用造轮子6.1 Pocket Flow 赢在哪里极简。100 行代码意味着你可以读完每一行理解每一个设计决策。你可以 fork 它改它甚至重写它。更重要的是AI 也能读懂它——Pocket Flow 的核心愿景是Agentic Coding让 AI 自己写 Agent 代码。100 行的框架AI 可以完全理解3 万行的框架AI 只能照葫芦画瓢。6.2 Pocket Flow 输在哪里完备性。没有 Checkpoint 意味着崩溃后无法恢复没有 Channel/Reducer 意味着并行节点可能互相覆盖状态没有版本追踪意味着无法实现复杂的状态依赖。这些在生产环境中是致命的。6.3 什么时候用哪个场景推荐快速原型验证Pocket FlowAgentic CodingAI 写 AgentPocket Flow教学 / 学习 Agent 原理Pocket Flow生产级 Agent 服务LangGraph需要持久化和人机交互LangGraph需要多通道消息接入OpenClaw 七、系列预告第二篇我们将深入 Pocket Flow 的批量与异步体系核心问题BatchNode 如何对列表逐项执行BatchFlow 如何实现 MapReduce 模式AsyncNode/AsyncFlow 的 async/await 改造有哪些细节AsyncParallelBatchNode 如何用 asyncio.gather 实现并行这些变体如何组合出 RAG、MapReduce、并行 Agent 等模式第三篇我们将用 Pocket Flow实战构建一个完整的 Agent核心问题如何用 100 行框架实现 ReAct Agent如何实现 RAG检索增强生成如何实现 Multi-Agent 协作Agentic Coding 的真正含义是什么关注我不要错过后续更新 总结速查卡Pocket Flow 核心概念概念一句话解释Node最小执行单元prep → exec → post 三阶段生命周期Flow有向图编排器while 循环 action 路由Shared Store普通 dict节点间通信的唯一方式actionpost 返回的字符串决定下一步走哪条边successors字典映射 {action: Node}定义有向图的边默认边语法糖a ba.next(b)- x 条件边语法糖a - x ba.next(b, x)max_retriesNode 内置重试机制LLM 调用容错10 个类速查类职责行数约BaseNode基类定义生命周期和路由20 行Node同步节点增加重试8 行Flow同步流程while 循环编排12 行BatchNode批量节点逐项执行2 行BatchFlow批量流程逐组执行4 行AsyncNode异步节点12 行AsyncFlow异步流程10 行AsyncBatchNode异步批量节点2 行AsyncParallelBatchNode异步并行批量2 行AsyncBatchFlow / AsyncParallelBatchFlow异步批量流程6 行一句话总结Pocket Flow 用 100 行代码证明了一件事LLM 应用的核心抽象只需要三个——Node执行逻辑、Flow编排路由、Shared Store传递状态。action 字符串路由比版本追踪简单dict 直写比 Channel/Reducer 透明while 循环比 BSP 循环直观。它不是少写了代码而是找到了正确的抽象层级。当你需要极简Pocket Flow 是答案当你需要完备LangGraph 是答案。参考链接Pocket Flow GitHub 仓库Pocket Flow 官方文档4 Surprising Lessons from a 100-Line LLM FrameworkDatawhale Easy-Pocket 教程

相关新闻