当前位置: 首页 > news >正文

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

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

写在前面:在拆完 OpenClaw(43 万行)和 LangGraph(3 万行)之后,今天我们来看一个"反其道而行"的项目——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
  • 🔧 三、BaseNode:100 行代码的"第一行"
  • 🔀 四、Flow:while 循环驱动的有向图引擎
  • 🛤️ 五、路由机制: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 Store

Pocket 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,params=None):curr=copy.copy(self.start_node)whilecurr:curr.set_params(params)last_action=curr._run(shared)curr=copy.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。简单粗暴,但完全透明——你看到什么就是什么,没有隐藏的合并逻辑。


🔧 三、BaseNode:100 行代码的"第一行"

3.1 BaseNode 的完整源码

classBaseNode:def__init__(self):self.params,self.successors={},{}defset_params(self,params):self.params=paramsdefnext(self,node,action="default"):ifactioninself.successors:warnings.warn(f"Overwriting 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):p=self.prep(shared)e=self._exec(p)returnself.post(shared,p,e)defrun(self,shared):ifself.successors:warnings.warn("Node won't 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, action="default"):注册一条从当前节点到目标节点的边,标签为 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_retries=1,wait=0):super().__init__()self.max_retries,self.wait=max_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_retry==self.max_retries-1:returnself.exec_fallback(prep_res,e)ifself.wait>0:time.sleep(self.wait)

Node 在 BaseNode 的基础上只增加了一个功能:重试_exec方法包裹了exec,在异常时重试最多max_retries次,每次间隔wait秒。最后一次失败时调用exec_fallback,默认行为是重新抛出异常,子类可以重写它实现降级逻辑。

这个设计非常实用——LLM 调用经常因为网络抖动或速率限制失败,重试是最基本的容错手段。Pocket Flow 把它做进了核心,而不是留给用户自己实现。


🔀 四、Flow:while 循环驱动的有向图引擎

4.1 Flow 的完整源码

classFlow(BaseNode):def__init__(self,start=None):super().__init__()self.start_node=startdefstart(self,start):self.start_node=startreturnstartdefget_next_node(self,curr,action):nxt=curr.successors.get(actionor"default")ifnotnxtandcurr.successors:warnings.warn(f"Flow ends: '{action}' not found in{list(curr.successors)}")returnnxtdef_orch(self,shared,params=None):curr,p,last_action=copy.copy(self.start_node),(paramsor{**self.params}),Nonewhilecurr:curr.set_params(p)last_action=curr._run(shared)curr=copy.copy(self.get_next_node(curr,last_action))returnlast_actiondef_run(self,shared):p=self.prep(shared)o=self._orch(shared)returnself.post(shared,p,o)defpost(self,shared,prep_res,exec_res):returnexec_res

4.2 _orch:最核心的 5 行代码

整个 Flow 的灵魂在_orch方法中,只有 5 行核心逻辑:

whilecurr:curr.set_params(p)last_action=curr._run(shared)curr=copy.copy(self.get_next_node(curr,last_action))

这 5 行代码实现了一个完整的有向图遍历引擎:

  1. curr.set_params(p):设置节点参数(用于 BatchFlow 传递批量参数)
  2. curr._run(shared):执行节点的 prep → exec → post 生命周期,返回 action
  3. get_next_node(curr, last_action):根据 action 查找后继节点
  4. 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-"search">>search_node# 继续搜索search_node-"answer">>answer_node# 回答问题# Node 的 post 方法返回 actiondefpost(self,shared,prep_res,exec_res):ifneed_more_search:return"search"else:return"answer"

5.2 运算符重载:DSL 语法糖

Pocket Flow 重载了两个运算符,让图的定义像写管道一样直观:

运算符等价调用用途
a >> ba.next(b)默认边(action=“default”)
a - "x" >> ba.next(b, "x")条件边(action=“x”)
# 线性流程node_a>>node_b>>node_c# 条件分支decide-"search">>search_node decide-"answer">>answer_node# 循环search_node-"search">>search_node# 自循环search_node-"answer">>answer_node

5.3 _ConditionalTransition:连接 - 和 >> 的桥梁

class_ConditionalTransition:def__init__(self,src,action):self.src,self.action=src,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
持久化Checkpoint(Memory/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 Flow
Agentic Coding(AI 写 Agent)Pocket 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 >> b=a.next(b)
- "x" >>条件边语法糖,a - "x" >> b=a.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 Framework
  • Datawhale Easy-Pocket 教程
http://www.jsqmd.com/news/782677/

相关文章:

  • 在Windows终端环境中使用Taotoken CLI管理多个项目的API配置
  • AutoCAD软件许可浪费严重?合规回收闲置许可,共享给同事
  • Spring AI 2.0 开发Java Agent智能体 - 对话与提示词工程(Prompt)
  • 键盘上的麦克风按钮:笔记本静音/开启的终极指南
  • CANN/HCCL Ring集合通信算法
  • LeetCode HOT100 - 子集
  • 2026年5月上海卖金实时行情,川沙城隍庙古北三店报价全知道/瑞鑫奢饰品黄金回收 鸿泰黄金回收 鸿鑫黄金回收
  • CANN基础设施机器人使用指南
  • 三线城市北方县城返乡创业开茶叶店,加盟哪个岩茶品牌靠谱容易盈利回本快品牌推荐白皮书——以溪谷留香为基准样本的下沉市场深度决策指南 - 商业科技观察
  • PyAsc算子开发指南
  • 海量存储芯片现货
  • 火车采集器:深耕15年,零代码全能网页数据采集神器,新手也能轻松玩转!
  • 如何5分钟完成淘金币全任务:终极自动化脚本解放你的双手
  • AI 工具开始收费后:小团队如何判断哪些订阅值得买?
  • KH Coder:无需编程技能也能完成的专业文本挖掘工具
  • eas 热更新相关
  • 亨得利名表子官方授权服务点全网最全测评:2026年最新门店地址、400电话预约避坑指南与真实维修保养体验分享 - 亨得利腕表维修中心
  • CANN驱动AI Core信息获取
  • WarcraftHelper:魔兽争霸3现代兼容性修复与性能优化完全指南
  • 为什么WHERE中的函数调用会引发灾难:揭秘KES与Oracle的函数执行顺序
  • 航材院内部流出!三套工作站黄金配置单,专治VASP算三天、Abaqus总崩溃、AI显存爆,科研党速抄!
  • 三月七小助手:如何5分钟完成《崩坏:星穹铁道》全部日常任务
  • 终极免费替代方案:500KB轻量级工具全面掌控Alienware灯光与散热系统
  • CANN/catlass矩阵乘API
  • CANN/AMCT 创建量化配置
  • Zeta电位分析仪选购指南:哪个品牌质量好?哪家公司最靠谱? - 品牌推荐大师
  • 科学绘图软件Origin下载与安装教程(详细教程,附安装包) 2025最新版详细图文安装教程
  • Clawdbot本地模型工具调用补丁:解决AI助手与本地推理服务器握手问题
  • 500元以内头戴式耳机推荐哪款?百元性价比最高的十款头戴式耳机
  • 3步搞定微信聊天记录永久备份:开源神器WeChatExporter终极指南