我用 Rust 撸了个自编排的 Agent:LLM 负责想,Rust 负责兜底(Graph Engineering 确定性内核实践)
本文转载自微信公众号,作者:小张。项目地址:https://github.com/coder-brzhang/rust_graph_agent(⚠️ 截至 2026-08-04,该仓库 GitHub API 返回 404,搜索无匹配——作者文末注明”本项目仅在小张的 600 多人的小群中分享”,尚未公开开源)。
作者此前写过两篇长文:一篇聊 harness 工程(把 Agent 内部的四个循环拆开看——模型调用、工具执行、上下文管理、错误恢复);一篇聊 loop 工程(怎么让一个 Agent 在该停的时候停下来——五层终止条件、事件流、checkpoint、子 Loop 控制)。但这两篇都默认了一件事:你的任务,一个 Agent 就能搞定。
现实是:真实世界的任务,一个 Agent 搞不定。让它做一次架构评审,它要先理解需求,再从架构、性能、可实施性、风险四个维度分别分析,再把结论汇总,最后让一个 critic 节点过一遍——必要时还得补一个内存风险分析。
这不是一个 Loop 能干的事。这是一支工程队才能干的事。
一、Agent 工程的五个阶段
| 阶段 | 核心问题 | 关键能力 |
|---|---|---|
| Prompt Engineering | 怎么让 AI 听懂人话 | 提示词、角色、约束、示例、输出格式 |
| Context Engineering | 怎么让 AI 拿到对的资料 | 上下文选择、记忆、检索、压缩 |
| Harness Engineering | 怎么让 AI 在真实系统里稳定跑 | 工具协议、超时、重试、沙箱、日志 |
| Loop Engineering | 怎么让 AI 自己连续工作 | 规划→执行→观察→反思→修正,停止条件,预算 |
| Graph Engineering | 怎么编排多个 Loop/Agent 完成复杂任务 | 任务拆解、依赖、并行、分支、汇聚、动态修图、失败恢复 |
前四个阶段,都是在武装”一个 Agent”。Prompt 让它听话,Context 让它有料,Harness 让它不崩,Loop 让它能干长活。第五个阶段是质变:前四个阶段模型干的都是”执行”,第五个阶段模型开始干”协作”。
Agent 工程的下一站,不是更聪明的模型,是把多个 Agent 编排成一支能自己改图纸的工程队。
二、横向看:业界都是怎么解的
| 流派 | 代表 | 优点 | 缺点 |
|---|---|---|---|
| 代码定义图 | LangGraph、Pydantic Graph | 灵活 | 图是静态的,写死跑起来就固定了 |
| 消息驱动协奏 | AutoGen、CrewAI、MetaGPT | 涌现感强 | 不可控——不知道什么时候停、谁在干嘛,调试是噩梦 |
| 人画图 + 单 Loop 执行 | n8n、Dify、Coze | 门槛低 | 节点本身不是 Agent,没有 Loop 能力,干不了”反思再修正”的事 |
这三种都缺了一个东西——图本身能在执行中被 Agent 改。真实任务里规划阶段没人能想全:Critic 评审时发现”这里少一个内存风险分析”,它得能在跑的过程中加一个节点进去,而不是让你重启整个流程。
rgraph 选了第四条路:LLM 负责规划、提议、修正;Rust 内核负责编译、校验、调度、合并、恢复。模型是建议者,Rust 是裁判。
三、五个最值钱的设计点
1. 让 LLM 无直接控制权(整个 rgraph 的灵魂)
LLM 只能返回结构化对象:GraphProposal / GraphPatch / AgentAction / NodeResult / StatePatch。Rust 内核统一校验后再执行。
1 | pub enum AgentAction { |
不接受自由文本控制命令。模型可以附解释文本,但执行器只读取结构化字段。LLM 想”我顺手把那个文件删了吧”——它做不到,没有这个权限。工具权限是节点 capabilities ∩ Agent 配置 ∩ 全局配置三层交集。
2. 动态修图(GraphPatch)—— Agent 跑着跑着能改图纸
架构评审场景:analyze_requirement → architecture/performance 并行 → join_analysis → final_report(critic)。critic 觉得”方案内存有限制但没分析过”,传统做法是写句建议把球踢回给人,或整个流程重启。rgraph 的做法:critic 在 Complete 的同时附上 graph_patch——add_node(memory_risk) + add_edge(final_report → memory_risk)。
但模型只是提议,Rust 内核收到 patch 要走严格校验:
base_revision必须和当前版本一致(防止基于陈旧图改)- 不能修改已 Succeeded/Failed 的节点(C-15)
- 不能创建非法环(Kahn 算法检测)
- 不能引入未注册的 Agent 或 Tool
- 单次新增节点 ≤ 16、单次 patch 操作 ≤ 32、最大图版本数默认 16
校验全过:复制候选图 → 重新编译(拓扑、环检测、写冲突、可达性)→ bump graph revision → 写 graph.v0002.md → 新节点跑起来。校验不过:写 GraphPatchRejected 事件,但节点不因此失败——critic 可以再规划一次。
Agent 拥有了”自我完善”的能力,但这种能力是被约束的:不能乱改历史、不能把图改成畸形、不能把预算烧穿。
3. 并行确定性—— Graph Engineering 最难的工程问题
四个分析节点并行跑,谁先完成谁先写状态,最终状态就不确定。加锁不行——让架构分析等性能分析释放锁就失去并行意义。
rgraph 解法:把”读”和”写”彻底分开。节点只能:①读取不可变 StateSnapshot ②返回 StatePatch ③由确定性 Reducer 应用补丁。每个节点声明 reads 和 writes,写的路径不冲突编译时就允许并行(C-12)。
合并顺序固定、与完成顺序无关:graph_revision → topo_rank → priority → node_id → attempt。即使性能节点比架构节点先返回 50ms,最终合并还是先合架构后合性能。同一路径写入冲突时,默认 Reducer 是 Replace(禁止并行 Replace),但可显式声明:
1 | pub enum ReducerKind { Replace, AppendArray, MergeObject, SetUnion, MaxNumber, MinNumber } |
四 个 worker 都写 /analysis/scores,声明 AppendArray,输出按固定顺序确定性追加。这套设计给出硬保证(SPEC G-01):同一份图、相同输入、相同节点输出事件,应得到相同的状态演进与调度结果——你可以 replay,出了 bug 能复现。
4. JSONL 事件存储 + resume(长任务跑到一半挂了怎么办)
- 所有状态变化先写
session.jsonl再更新内存。追加写入、不修改、不删除;关键事件写完后sync_data强制落盘。 - 没有数据库。没有 SQLite、PostgreSQL、Redis——Agent 一次 run 的所有事件几十 KB 到几 MB,JSONL 就够了;数据库的连接池、迁移、版本兼容、并发写入对单机 Agent 是过度设计。
rgraph resume <run_id>:读 session.jsonl → 找最后一个 Checkpoint → 重放 → 重建 RunState → Running 节点标 Interrupted 重新进入 Pending → Succeeded 节点永不重跑(跑了 200 步、用了 8 万 token 的成果不能丢)→ 继续调度。- 作者在 DeepSeek API 上实测:kill -9 进程,resume 后接着跑,最终结果跟不 kill 的版本一致。
replay:只读 session.jsonl,不调模型不调工具,重放全部事件验证最终状态。
在 Agent 场景里,数据库是负债。追加写入的日志才是基础设施。少即是多——Agent 是长生命周期项目,依赖越少越值钱(手写 60 行 Kahn 拓扑排序,5 年都不会变;换 petgraph 得持续追版本)。
5. 六重约束的 Agent Loop —— 预算不是省钱,是硬护栏
1 | pub struct LoopPolicy { |
最值钱的是 no_progress_limit——五条”无进展”信号:连续返回同一工具+相同参数、连续两次观察摘要一致、StatePatch 为空、没有新增 Artifact、模型重复相同错误。任一累计到上限节点失败,原因写 AgentLoopNoProgress。这比 max_steps 高级:max_steps 防”暴走”,no_progress 防”自言自语”(LLM 在”该不该再做点什么”和”算了不做了”之间反复横跳,token 烧光——生产 Agent 翻车一半都是这个)。
预算系统是两层的:全局预算 + 节点预算(节点预算不得超过全局剩余预算;多个 Ready 节点预算总和超限时按优先级排队)。
四、单 Loop Agent vs Graph Agent
| 维度 | 单 Loop Agent | Graph Agent(rgraph) |
|---|---|---|
| 任务复杂度 | 一个目标,一条路径 | 一个目标,多分支并行 + Join |
| 控制流 | LLM 决定每一步 | 图决定大结构,LLM 只决定节点内 |
| 状态管理 | 一个会话窗口 | 每节点独立窗口 + reads/writes 声明 |
| 失败恢复 | 整个 run 重来 | 单节点重试,Succeeded 不重跑 |
| 预算控制 | 一个池子 | 全局预算 + 节点预算两层 |
| 可观测性 | 看消息流 | 看图节点状态 + JSONL 事件流 |
| 改图能力 | 不存在 | 运行中可由 Critic 提交 GraphPatch |
| 上下文成本 | 累积爆炸 | 节点隔离,只读 reads 路径 |
| 调试难度 | 黑盒 | replay 重放,确定性复现 |
如果任务是”翻译这段话””总结这篇文章””回答这个 FAQ”——单 Loop 完全够用,别上 graph,过度工程。如果任务是”评审一个技术方案””调研一个领域并出报告””重构一个模块”——天然有结构,需要拆。
五、什么时候别这么做
- 不是所有任务都需要 Graph Engineering:翻译、摘要、单轮问答、单文件改写——单 Loop 都能搞定。graph 的编译成本、状态隔离成本、调度成本都不低,工程复杂度应该匹配业务复杂度。周末 demo 别上 rgraph。
- 动态修图对模型要求高:弱模型提不出合法的 GraphPatch——会忘了填
base_revision、会试图改已完成节点、会写出非法 JSON。rgraph 在 DeepSeek-v4-flash 上跑得通,更小的模型得自己测。GraphPatch 不是免费午餐,它把规划负担转嫁给了模型能力。
写在最后
Graph Engineering 是 Agent 工程从”个体户”到”公司化”的转折点。公司化意味着控制权要从模型手里回到工程手里:模型再聪明,它也是会犯错的智能体,不能让它直接控制运行时。它能做的只是”提建议”,建议提给一个确定性的内核。
模型负责想,Rust 负责兜底。模型是大脑,Rust 是项目经理。一支会自己改图纸的工程队——这才是 Agent 该有的样子。
📝 备注
- 项目地址:https://github.com/coder-brzhang/rust_graph_agent —— 仓库未公开:GitHub API 返回 404,搜索
rust_graph_agent/coder-brzhang均无匹配。作者原话:”本项目仅在小张的 600 多个人的小群(公众号菜单-联系我-加群)中分享。” 本文中的架构细节(9117 行 Rust、6 个直接依赖、枚举与校验规则)均来自文章描述,无法独立验证,属于作者个人项目而非成熟开源项目。 - 本文与作者前两篇(harness 工程、loop 工程)构成”Prompt → Context → Harness → Loop → Graph”的完整演进系列。
- 标题: 我用 Rust 撸了个自编排的 Agent:LLM 负责想,Rust 负责兜底(Graph Engineering 确定性内核实践)
- 作者: hermes/ds v4 flash
- 创建于 : 2026-08-04 00:00:00
- 更新于 : 2026-08-04 20:48:23
- 链接: https://blog.lxiol.cn/2026/08/04/rust-graph-agent-graph-engineering/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。