爱意满满的作品展示区。
shaxiaozili

一个约 1800 行的 agent 框架内核:为了真正搞懂 LangGraph

  •  
  •   shaxiaozili · 1h 57m ago · 127 views

    我之前反复研究 LangGraph 和 Google 的 ADK ,想搞清楚一个 agent 运行时到底是怎么工作的,但每次都卡壳。不是说它们不好,而是等我穿过三层抽象之后,已经彻底搞不清楚哪些东西是"必须的"、哪些是附加的。所以我干脆自己写了一个尽可能小、但仍然保留生产级 agent 该有的关键特性的东西:崩溃恢复、human-in-the-loop 暂停、有界并发,以及并行分支下的确定性状态。

    项目叫 prodagent: https://github.com/limenagent/prodagent

    内核大约 1800 行代码,分布在 11 个文件里,只依赖 Python 标准库(唯一的开发依赖是 pytest ; 70 个测试全部离线运行)。整体拆分得很干净,机制( mechanism )和策略( policy )分离:

    • 内核完全不知道 LLM 是什么。它只有一个静态的 Plan (节点 / 边 / 状态通道)、一个针对每次执行的 Run ,以及一个 Scheduler——它每一轮( wave )只做一件事:算出"现在谁可以跑",并发执行它们,然后在一个屏障( barrier )处统一提交。

    • 状态是一个投影( projection ),而不是一个存储( store )。一份只追加的事件日志才是唯一真相源;状态是通过每个通道各自的 reducer 从事件日志折叠( fold )出来的。checkpoint 只是这个折叠结果的一份可丢弃缓存——这也是为什么"崩溃后恢复"和"时间旅行(回放)"几乎是免费得到的。

    • 控制语义故意只留两个命令:Goto (重新激活一个静态节点 / 走回边 / 做 handoff )和 Send (在运行时实例化一个 fan-out 模板)。内核里没有 ReAct 节点,也没有"agent 模式"的枚举——ReAct 说白了就是两个节点加一条回边,在内核之上一个可替换的层里拼出来的。多 agent 之间的 handoff 也不是一个新的原语,它就是一次指向另一个 agent 节点、且没有返回边的 Goto 。

    • 模型、工具、子 agent 和存储全部通过"端口( port )"接入,所以同一个内核在测试里可以完全离线地跑在写死的 fake 实现上。

    make play 会打开一个零依赖的本地 playground ,你可以在里面看到 wave 的时间线、看并行分支如何折叠状态,并且可以在某次运行中途批准一次工具调用,让它从 checkpoint 处继续执行。文档是中英双语的。

    它不是什么:它是单进程的,自带的持久化只是一个基于文件的 checkpoint 存储,没有分布式调度器,也没有多租户能力。这是一个带有明确态度的"教学工件"——核心想法是"花一个周末读懂这个,再回去看 LangGraph / ADK ,那些抽象自然就懂了"。

    我很想听听两个问题上的反馈:这种基于 BSP ( wave barrier )的调度方式,相比纯 actor 模型,是不是这类工作流更合适的默认选择?以及把控制语义压缩成只有两个命令,到底是真的更清晰,还是只是我个人偏执的怪癖?内核内部任何细节都欢迎问。

    No Comments Yet
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   3040 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 312ms · UTC 14:34 · PVG 22:34 · LAX 07:34 · JFK 10:34
    ♥ Do have faith in what you're doing.