乐于分享
好东西不私藏

[老丁聊AI] OpenClaw、Hermes Agent、Loops、Graphs:四者关系与 Graph 植入 Hermes Agent 完整操作指南

[老丁聊AI] OpenClaw、Hermes Agent、Loops、Graphs:四者关系与 Graph 植入 Hermes Agent 完整操作指南

2026年7月21日 · 基于 Hermes Agent 实际环境验证


目录#

  • 一、引言:为什么这四个概念会被放在一起
  • 二、四者本质上不在同一层
  • 三、Loops vs Graphs:控制流范式的根本分歧
  • 3.1 Loop(循环范式)
  • 3.2 Graph(图范式)
  • 3.3 核心权衡
  • 3.4 进化谱系
  • 四、OpenClaw 深度剖析
  • 4.1 概况
  • 4.2 架构
  • 4.3 控制流
  • 4.4 多 Agent 与编排
  • 4.5 Graph 能力现状
  • 五、Hermes Agent 深度剖析
  • 5.1 概况
  • 5.2 架构
  • 5.3 八层时间尺度 Loop
  • 5.4 多 Agent 与编排
  • 5.5 Graph 能力现状
  • 六、OpenClaw vs Hermes Agent:全面对比
  • 七、Graph 能力植入 Hermes Agent:完整操作指南
  • Level 1:基础设施搭建(execute_code 内嵌)
  • Level 2:真实工具调用替换
  • Level 3:MCP Server 跨会话持久化
  • Level 4:原生集成方向(长期)
  • 八、关键经验教训
  • 九、日常使用指南
  • 十、OpenClaw 侧的 Graph 植入
  • 附录:文件清单与路径

一、引言:为什么这四个概念会被放在一起#

2026年7月,AI agent 领域最热的架构辩论是 Peter Steinberger(OpenClaw 创建者)在 X 上发的一句话:

“Are we still talking loops or did we shift to graphs yet?” (我们还在聊 loops 吗,还是已经转向 graphs 了?)

这条推文 24 小时内获得 57.5 万次浏览,折射出一个全行业的焦虑:当 agent 从单步聊天进化到多步骤自主任务执行时,谁来决定 agent 的下一步——是一个 while 循环里的 LLM,还是一张预定义的有向图?

这个问题的答案直接影响了两个最火的开源 agent 框架——OpenClaw(383K GitHub stars)和 Hermes Agent(217K stars)——的架构走向。两者目前都以 Loop 为核心控制流,但社区对 Graph 能力的需求日益增长。

本文将: 1. 澄清 OpenClaw、Hermes Agent、Loops、Graphs 四者的关系 2. 深度对比 Loop 和 Graph 两种范式 3. 深度剖析 OpenClaw 和 Hermes Agent 的架构 4. 给出在 Hermes Agent 中植入 Graph 能力的完整操作步骤(每一步都经过实际验证)


二、四者本质上不在同一层#

先厘清一个最常见的误解:OpenClaw 和 Hermes Agent 是产品级 agent 框架,Loops 和 Graphs 是控制流设计范式。前者是”造好的车”,后者是”引擎的设计图纸”。

┌─────────────────────────────────────────────────────┐
│  产品层    OpenClaw          Hermes Agent            │
│  (完整框架: 渠道+工具+记忆+技能+多agent)              │
├─────────────────────────────────────────────────────┤
│  范式层    Loops              Graphs                 │
│  (控制流设计模式: 谁决定下一步)                        │
├─────────────────────────────────────────────────────┤
│  基础层    ReAct pattern      StateGraph/DAG         │
│  (学术/工程原语)                                     │
└─────────────────────────────────────────────────────┘

每个产品都使用了某种范式,但没有一个产品”等于”某个范式。OpenClaw 和 Hermes Agent 的核心控制流都是 Loop(ReAct 模式),但它们的架构设计、扩展方式、适用场景截然不同。而 Loops 和 Graphs 作为范式,可以在任何 agent 框架中实现——问题只是”植入的难度和深度”。


三、Loops vs Graphs:控制流范式的根本分歧#

3.1 Loop(循环范式)#

Loop 是最接近 LLM agent 底层工作方式的控制流。核心思想:把方向盘交给 LLM,循环只负责执行工具、回填结果、循环到 LLM 满意为止。

def run_agent(user_input, tools, max_steps=10):
    messages = [{"role": "user", "content": user_input}]
    for _ in range(max_steps):
        response = model.invoke(messages, tools=tool_specs)
        messages.append(response)
        if not response.tool_calls:
            return response.content  # LLM 不再调用工具,返回最终答案
        for call in response.tool_calls:
            result = tools[call.name](**call.args)
            messages.append({"role": "tool", "tool_call_id": call.id, "content": str(result)})
    return "Hit step limit without finishing."

这就是 ReAct 模式的全部——Reasoning(推理)+ Acting(行动),交替循环。

Loop 的优点:

优点
说明
简单
20 行代码就能写一个可用的 agent
灵活
LLM 可以在运行时决定调用什么工具、什么时候停止
对话式
天然适配聊天场景——用户说一句,agent 做一堆事,回一句
易调试
单线程、单循环,打断点就能看全貌

Loop 的典型 Bug:

  • 无限循环
    :困惑的模型反复调用同一个工具,烧光预算
  • 过早停止
    :模型在还没完成任务时就返回最终答案
  • max_steps
    守卫是必须的——没有它,一个 bug 就能让 agent 无限循环

Loop 何时开始崩溃?

当任务复杂度上升,Loop 模式会暴露四个结构性问题:

  1. 一切变串行:三个独立的数据库查询,Loop 会一个接一个做,每次还要重新调 LLM 决定下一步。应该 5 秒完成的任务变成 20 秒。

  2. 上下文窗口变垃圾场:每轮迭代往消息历史里塞工具输出、推理过程、重试记录。重要指令被噪声淹没。模型反复重新处理过时的工具结果和无关上下文。

  3. 调试是噩梦:Graph 失败时你能指出失败的节点和输入。Loop 失败时你只有”第 12 次迭代做了个奇怪决定”——像考古挖掘一样阅读整个对话轨迹。

  4. 不知何时停:要么过早停止(任务没完成就返回),要么无限游荡(一直调工具不收敛)。每个 agent 工程师最终都加了MAX_ITERATIONS = 20

3.2 Graph(图范式)#

Graph 把控制流从 LLM 的隐式推理提到代码的显式结构里。核心思想:用节点(Node)和边(Edge)预先声明执行流程,代码决定下一步,LLM 只在节点内部做局部决策。

from langgraph.graph import StateGraph, END, START
from typing import TypedDict, Literal

class State(TypedDict):
    task: str
    result: str
    attempts: int
    validated: bool

def plan_node(state: State) -> dict:
    return {"task": state["task"], "attempts": state.get("attempts", 0) + 1}

def execute_node(state: State) -> dict:
    return {"result": f"执行: {state['task']}"}

def validate_node(state: State) -> dict:
    return {"validated": len(state.get("result", "")) > 5}

def should_retry(state: State) -> Literal["retry", "done"]:
    if state.get("validated") or state.get("attempts", 0) >= 3:
        return "done"
    return "retry"

builder = StateGraph(State)
builder.add_node("plan", plan_node)
builder.add_node("execute", execute_node)
builder.add_node("validate", validate_node)

builder.add_edge(START, "plan")
builder.add_edge("plan", "execute")
builder.add_edge("execute", "validate")
builder.add_conditional_edges("validate", should_retry, {
    "retry": "plan",   # 回环:验证失败 → 回到规划
    "done": END
})

graph = builder.compile()
result = graph.invoke({"task": "研究 loops vs graphs", "result": "", "attempts": 0, "validated": False})

Graph 的三个核心要素:

要素
作用
对应概念
节点(Node)
函数,读状态 → 做事 → 返回状态更新
函数
边(Edge)
节点间的连接,可无条件或有条件
函数调用链
状态(State)
有类型的共享对象,所有节点可读写
全局变量

Graph 解锁的五个 Loop 做不到的能力:

能力
Loop 的局限
Graph 的解法
条件分支
LLM 按自己选择的顺序跑工具,无法强制 fork
add_conditional_edges

按状态路由
暂停/恢复
没有 mid-execution 挂起的概念
checkpoint 持久化,可小时级恢复
并行 fan-out/fan-in
所有工具调用串行
多条出边并行 + 多条入边等齐
Human-in-the-loop
loop 跑到完成,无注入点
breakpoint 暂停等人审批
崩溃恢复
状态只在内存里
每个 super-step 持久化到 SQLite

Graph 的典型 Bug:

  • 不可达节点
    :某条边配置错误,导致一个节点永远无法到达
  • 状态合并冲突
    :并行节点同时修改同一个 state 字段,reducer 冲突
  • 无限循环
    :条件边的路由逻辑有 bug,导致永远不满足退出条件(但比 Loop 的无限循环更容易诊断,因为你可以看到状态流转)

3.3 核心权衡#

“Loops are forgiving. Graphs force you to admit how much of the workflow you haven’t actually modeled yet.”— Luis Catacora

这句话是最精辟的总结:

  • Loop 让你推迟架构
    ——一个 agent 处理一切,直到它处理不了。你不需要提前设计流程,LLM 在运行时自己决定。
  • Graph 要求你提前声明结构
    ——谁负责什么、什么依赖什么、分支失败怎么办。你必须在写代码时就想清楚整个流程。

这不是”谁更好”的问题,而是”你的任务需要多少确定性”的问题:

任务特征
推荐范式
原因
探索性研究、开放式推理
Loop
灵活性是超能力,流程无法预定义
单一用途、几个工具的助手
Loop
20 行代码完事,别过度工程
有严格顺序、审批门、SLA
Graph
确定性、可审计、可回滚
多 agent 并行 + 综合
Graph
fan-out/fan-in 天然表达
需要崩溃恢复/持久化
Graph
checkpoint 是内建的
12+ 条件分支
Graph
loop 里手写会变成意大利面

实践中最有效的模式是混合:用一个小型、策略控制的 agent loop 做探索和分流,后面接一个确定性 graph 做关键路径执行。用 loop 获取灵活性,用 graph 保证可审计性和 SLA。

3.4 进化谱系#

控制流范式不是一夜之间出现的,而是一个清晰的进化谱系:

2022-2024: Prompt Engineering  →  你提示模型
2025-2026: Loop Engineering     →  你设计提示模型的循环
2026 中:   Graph Engineering    →  你设计循环的图——多个 agent 各跑各的 loop,用依赖关系连成组织
  • Prompt Engineering
    时代的核心技能是写好指令文本
  • Loop Engineering
    时代的核心技能是设计while循环——Boris Cherny 的名言定义了这个阶段:”I don’t prompt Claude anymore. I have loops that are running.”
  • Graph Engineering
    时代是让多个 agent 各自跑 loop,用依赖关系把它们连成一张图。Loop 让单个 agent 的行为可编程,Graph 让 agent 组织可编程。

2026 年还出现了动态工作流(Dynamic Workflows)的新范式:让模型在运行时写出编排代码,然后确定性执行。两阶段——authoring(模型写编排)→ execution(程序确定性运行)。静态 graph 在任务已知前就固定控制流;纯 agent 每步运行时决定无固定结构;动态工作流折中——模型读题后提交结构,结构一旦确定就确定性执行。


四、OpenClaw 深度剖析#

4.1 概况#

维度
详情
创建者
Peter Steinberger (@steipete)
创建时间
2025年11月24日
语言
TypeScript (88.4%) + Swift (5.4%) + Kotlin (2.0%)
GitHub Stars
383,579(2026年7月,GitHub 增长最快的项目之一)
License
MIT
核心定位
自托管个人 AI 助手——”Your own personal AI assistant. Any OS. Any Platform.”
口号
“The lobster way. 🦞”

OpenClaw 在不到 8 个月的时间里从零成为 GitHub 星标最多的项目之一。它的成功不是因为技术最深,而是因为它解决了一个真实痛点:让开发者拥有一个自托管的、跨所有聊天平台的、有完整系统访问权限的 AI 助手。

4.2 架构#

┌──────────────────────────────────────────────────┐
│              Chat Apps + Plugins                  │
│  WhatsApp · Telegram · Slack · Discord · Signal  │
│  iMessage · WeChat · Matrix · Teams · ...20+     │
└──────────────────────┬───────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────┐
│                   Gateway                         │
│  (控制面:路由、会话、渠道连接的单一真相来源)        │
└──────┬───────┬───────┬───────┬───────────────────┘
       │       │       │       │
       ▼       ▼       ▼       ▼
   Agent     CLI   Web UI   Mobile Nodes
   (大脑)          (控制台)  (iOS/Android)

Gateway 是核心——一个进程同时服务所有渠道。它不是 chatbot 包装器,而是一个完整的 agent 运行时:会话管理、路由、工具调度、记忆持久化、技能加载。

4.3 控制流#

OpenClaw 的核心控制流是标准 ReAct Loop——LLM 决定调用什么工具,Loop 执行工具调用,把结果回填给 LLM,循环直到 LLM 产出最终回复。

用户消息 → LLM 推理 → 有工具调用? → 是 → 执行工具 → 回填结果 → LLM 推理 → ...
                              ↓ 否
                         返回最终回复

没有内建的 Graph 引擎。OpenClaw 的设计哲学是”Loop is enough”——一个 agent 跑自己的 ReAct 循环,需要多 agent 时通过 bindings 路由到隔离的 agent 实例。

4.4 多 Agent 与编排#

OpenClaw 的多 Agent 模式是路由式——每个 agent 是完全隔离的大脑,有自己的:

  • Workspace
    (文件、AGENTS.md/SOUL.md/USER.md、人格规则)
  • State Directory
    (auth profiles、model registry、per-agent config)
  • Session Store
    (聊天历史 + 路由状态)
  • Skills
    (per-agent skills 目录 + 共享 skills)

通过bindings把不同渠道/发送者路由到不同 agent。例如:工作消息 → coding agent,私人消息 → social agent。

社区编排插件生态(这是 OpenClaw 获取 Graph 能力的主要途径):

插件
能力
Graph 特性
openclaw-orchestrator

(lurkacai0831)
DAG 工作流引擎 + 可视化编辑器
条件分支、并行汇合(AND/OR/XOR)、审批卡点、失败重试、防无限循环
openclaw-hawkins

(parijatmukherjee)
持久化编排 + 衰减记忆
VINES(状态持久化到MariaDB)、VECNA(共享记忆)、崩溃恢复
agent-orchestrator

(aatmaan1)
Meta-agent 任务分解
动态生成子 agent SKILL.md、文件通信、consolidation
agency-agents-router

(Staok)
自然语言 DAG 编排
215 agent 描述库、single/parallel/sequential/DAG
openclaw-orchestrator

(zeynepyorulmaz)
自适应 LLM 编排
非刚性 DAG,LLM 基于累积结果决定下一步

4.5 Graph 能力现状#

OpenClaw 本身是 Loop,但插件系统足够强大,可以完整承载 Graph 能力。社区已经实现了 DAG、checkpoint、并行、审批、重试等 graph 原语。openclaw-orchestrator甚至有 React Flow 可视化画布,支持拖拽设计工作流。

结论:在 OpenClaw 上跑 Graph,不需要改核心代码,装插件即可。


五、Hermes Agent 深度剖析#

5.1 概况#

维度
详情
创建者
Nous Research(模型训练实验室,Hermes/Nomos/Psyche 模型背后团队)
创建时间
2025年7月22日
语言
Python (81.5%) + TypeScript (15.9%, TUI)
GitHub Stars
217,951
License
MIT
核心定位
自我进化的 AI agent——”The agent that grows with you”
独特卖点
唯一内建学习循环的 agent——从经验中创建技能、使用中改进技能、跨会话搜索自己的对话历史

Hermes Agent 与 OpenClaw 的根本区别在于设计哲学:OpenClaw 是”多渠道路由的 gateway 型助手”,Hermes 是”多时间尺度自我进化的研究型 agent OS”。

5.2 架构#

┌─────────────────────────────────────────────────────────┐
│                    Entry Points                          │
│  CLI (cli.py) · Gateway (gateway/run.py) · ACP · API    │
│  Batch Runner · Desktop App · Web Dashboard              │
└─────────┬──────────────┬──────────────────┬─────────────┘
          │              │                  │
          ▼              ▼                  ▼
┌─────────────────────────────────────────────────────────┐
│              AIAgent (run_agent.py)                      │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐              │
│  │  Prompt   │  │ Provider │  │  Tool    │              │
│  │  Builder  │  │ Resolution│  │ Dispatch │              │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘              │
│  ┌────┴─────┐  ┌────┴─────┐  ┌────┴─────┐              │
│  │Compression│  │ 3 API    │  │ 70+ tools│              │
│  │ & Caching │  │ Modes    │  │ 28 toolsets│             │
│  └──────────┘  └──────────┘  └──────────┘              │
└─────────┴──────────────────┴─────────────────────────────┘
          │                  │
          ▼                  ▼
┌──────────────────┐  ┌──────────────────────┐
│ Session Storage   │  │   Tool Backends      │
│ (SQLite + FTS5)   │  │ Terminal (6 backends)│
│ hermes_state.py   │  │ Browser (5 backends) │
│                   │  │ Web (4 backends)     │
│                   │  │ MCP (dynamic)        │
│                   │  │ File, Vision, etc.   │
└──────────────────┘  └──────────────────────┘

核心是AIAgentrun_agent.py),它管理单个对话会话的”Think-Act-Observe”循环。但与标准 ReAct Loop 不同的是,这个 Loop 嵌套在一个更大的运行时里——8 个不同时间尺度的 Loop 同时运行,慢循环管理和改进快循环。

5.3 八层时间尺度 Loop#

这是 Hermes 最独特的架构设计——不是一个 Loop,而是 8 个嵌套的 Loop,每个在不同时间尺度运行:

Loop
时间尺度
名称
功能
1
毫秒→分钟
核心循环
AIAgent.run_conversation()

处理输入、构建 prompt、调 LLM、执行工具、返回响应。每轮后状态持久化到 SQLite
2
分钟→小时
/goal 仲裁
运行/goal "迁移所有测试到 pytest"时,judge 模型每轮后检查验收标准。未满足+有预算→继续。跨会话持久
3
任务后
自我改进
5+工具调用的任务后,自动分析工作流。如果可复用,序列化为 Skill 存入~/.hermes/skills/
4
每7天
Curator
清理/归档/合并过期 skill。tar.gz 备份。确定性扫描免费,LLM 合并可选
5
每轮
记忆持久化
SQLite + FTS5 + 记忆刷盘。确保上下文丢失前知识已保存
6
定时
Cron 调度
独立会话 + 跨平台投递。3分钟硬中断,.tick.lock防重复
7
阈值触发
上下文压缩
四阶段管线:工具输出裁剪→Head/Tail 保护→LLM 结构化摘要→工具对完整性修复
8
事件驱动
Kanban 分派
多 profile 工作队列 + dispatcher 自动分派 + 崩溃恢复

关键洞察:Hermes 的 8 层 Loop 实际上比简单 Graph 更复杂——只是不显式。每一层 Loop 都有明确的输入/输出/触发条件/退出条件,本质上是一个”隐式 Graph”的节点。但因为没有显式的图 API,这些 Loop 之间的依赖关系是嵌在代码里的,不是声明式的。

5.4 多 Agent 与编排#

Hermes 的多 Agent 模式有三种:

1. delegate_task(子 agent 委派)

# 单任务
delegate_task(goal="研究 GRPO 论文", context="...")

# 批量并行(最多 3 并发)
delegate_task(tasks=[
    {"goal": "研究A", ...},
    {"goal": "研究B", ...},
    {"goal": "研究C", ...}
])
# 三个子 agent 并行,全部完成后汇总

这本质上就是 Graph 的fan-out → fan-in模式,只是不是用图 API 声明的。

2. /goal + judge(条件循环 + 验证门)

用户: /goal "把所有测试迁移到 pytest"
→ 每轮后 judge 模型检查验收标准
→ 未满足 + 有预算(默认20轮) → 继续
→ 满足 → 退出

这是 Graph 里”条件边 + 回环”的等价物。

3. Kanban(持久化工作流图)

  • 任务有依赖(link/unlink)
  • 状态机:pending → claimed → completed/blocked
  • dispatcher 自动分派 + 崩溃恢复
  • 多 worker profile 并行消费

4. cron + context_from(DAG 链式执行)

Job A (收集数据) → output 注入 → Job B (分析) → output 注入 → Job C (报告)

这是 DAG 的链式节点,调度器驱动而非图引擎驱动。

5.5 Graph 能力现状#

Hermes没有内建的 StateGraph API。通过 delegate_task + /goal + cron + Kanban 的组合,可以模拟大部分 graph 能力,但:

  • 没有显式的节点/边/条件路由 API
  • 没有图级 checkpoint
    (会话级有 SQLite,但不是 graph 级)
  • 没有可视化图编辑器
  • 没有图级可审计执行轨迹

这正是我们需要植入的。


六、OpenClaw vs Hermes Agent:全面对比#

维度
OpenClaw 🦞
Hermes Agent ☤
语言
TypeScript
Python
Stars
383K
217K
核心控制流
单 Loop(ReAct)
8 层嵌套 Loop
自我改进
技能手动/半自动
自动创建 skill + 自我修补 + curator 维护
记忆
文件式(MEMORY.md + 日志)
SQLite + FTS5 + 可插拔后端(Honcho/Mem0)
多 Agent
bindings 路由到隔离 agent
delegate_task + Kanban + tmux 多实例
并行
社区插件实现
delegate_task 批量并行(最多3并发)
持久化
文件系统
SQLite(会话、记忆、Kanban)
长目标
无内建
/goal 跨会话持久 + judge 仲裁
调度
无内建 cron
内建 cron + 跨平台投递
终端后端
本地
6种:local/Docker/SSH/Modal/Daytona/Singularity
Provider
OpenAI/Anthropic/Ollama 等
20+ provider + OAuth 池化 + 自动 failover
插件生态
ClawHub 市场
Skills hub + MCP + 插件
移动端
iOS/Android 原生 node
无原生移动端(通过消息平台触达)
桌面端
Web Control UI
Electron 桌面 app
设计哲学
“Loop is enough, wire agents by bindings”
“Loop at multiple timescales = operating system for intelligence”
Graph 能力
社区插件(DAG/审批/并行)
delegate_task 模拟(fan-out/回环)
典型用户
想要多渠道个人助手的开发者
想要自我进化 agent 的研究者/高级用户

一句话区分:OpenClaw 是”多渠道 + 多 agent 路由”的 gateway 型助手;Hermes 是”多时间尺度自我进化”的研究型 agent OS。


七、Graph 能力植入 Hermes Agent:完整操作指南#

以下是经过实际验证的四级植入方案,从最简单到最完整,每一级都在上一级基础上构建。

Level 1:基础设施搭建(execute_code 内嵌)#

目标:在 Hermes 的execute_code环境里安装 LangGraph,验证基础图能力可用。

为什么从这里开始:零框架改动、今天就能跑、Hermes 的 70+ 工具直接变成 graph 节点的执行器。

步骤 1.1:安装 LangGraph#

# 进入 Hermes 的虚拟环境
cd ~/.hermes/hermes-agent
source .venv/bin/activate  # 或 source venv/bin/activate

# 安装 LangGraph 核心 + SQLite checkpoint
pip install langgraph langchain-core langgraph-checkpoint-sqlite

验证安装成功

# 在 Hermes 对话里用 execute_code 执行
from langgraph.graph import StateGraph, END, START
print("✅ LangGraph 可用")

步骤 1.2:验证基础图——条件分支 + 回环#

from typing import TypedDict, Literal
from langgraph.graph import StateGraph, END, START

class TaskState(TypedDict):
    task: str
    plan: str
    result: str
    attempts: int
    status: str

def plan_node(state: TaskState) -> dict:
    return {
        "plan": f"计划: 分解 '{state['task']}'",
        "attempts": state.get("attempts", 0) + 1
    }

def execute_node(state: TaskState) -> dict:
    return {"result": f"执行结果 (attempt {state['attempts']})"}

def evaluate_node(state: TaskState) -> dict:
    if state["attempts"] >= 3:
        return {"status": "done"}
    return {"status": "done"}

def should_retry(state: TaskState) -> Literal["retry", "done"]:
    return "retry" if state["status"] == "retry" else "done"

builder = StateGraph(TaskState)
builder.add_node("plan", plan_node)
builder.add_node("execute", execute_node)
builder.add_node("evaluate", evaluate_node)
builder.add_edge(START, "plan")
builder.add_edge("plan", "execute")
builder.add_edge("execute", "evaluate")
builder.add_conditional_edges("evaluate", should_retry, {
    "retry": "plan",   # 回环
    "done": END
})

graph = builder.compile()
result = graph.invoke({
    "task": "测试", "plan": "", "result": "", "attempts": 0, "status": ""
})
print(result)

步骤 1.3:验证 checkpoint 持久化#

import tempfile, sqlite3
from langgraph.checkpoint.sqlite import SqliteSaver

db_path = tempfile.mktemp(suffix=".sqlite")
conn = sqlite3.connect(db_path, check_same_thread=False)
checkpointer = SqliteSaver(conn)
graph = builder.compile(checkpointer=checkpointer)

config = {"configurable": {"thread_id": "task-001"}}

# 第一次运行
result = graph.invoke(initial_state, config)

# 查看checkpoint
snapshot = graph.get_state(config)
print(f"next: {snapshot.next}, values: {snapshot.values}")

# 崩溃后恢复——传 None 从上次断点继续
result2 = graph.invoke(None, config)

步骤 1.4:验证 Hermes 工具集成#

# graph 节点直接调用 hermes_tools
from hermes_tools import terminal

def research_node(state):
    result = terminal(command="echo '搜索中...'", timeout=10)
    return {"result": result.get("output", "")}

验证结果:条件分支、回环、checkpoint 持久化、Hermes 工具调用全部通过。


Level 2:真实工具调用替换#

目标:把模板里的模拟节点替换为真实搜索、分析、验证、报告生成。

核心挑战execute_code有 5 分钟超时,不能在内部调hermes chat -q子进程(每次 50 秒),DuckDuckGo 搜索可能被反爬。

解决方案:采用”数据注入”模式——在 execute_code 外部用 Hermes MCP 搜索工具获取数据,把结果作为 graph 初始状态传入。graph 内部只做规则式分析/验证/总结(<1秒完成)。

步骤 2.1:创建研究工作流脚本#

文件路径:~/.hermes/skills/software-development/hermes-graph-engine/scripts/research_graph.py

核心结构:

from typing import TypedDict, Literal
from langgraph.graph import StateGraph, END, START

class ResearchState(TypedDict):
    topic: str
    search_query: str
    raw_results: str      # 外部注入的搜索数据
    findings: str
    validation_notes: str
    summary: str
    report_path: str
    attempts: int
    validated: bool

# 节点函数
def plan_search(state): ...       # 规划搜索策略
def execute_search(state): ...    # 执行搜索(urllib 或 hermes chat)
def analyze_results(state): ...   # 规则式提取关键发现
def validate(state): ...          # 规则式验证质量
def summarize(state): ...         # 生成报告写入文件

# 条件路由
def should_retry(state): ...      # 验证通过→总结,未通过→重试

# 构建图
builder = StateGraph(ResearchState)
builder.add_node("plan", plan_search)
builder.add_node("search", execute_search)
builder.add_node("analyze", analyze_results)
builder.add_node("validate", validate)
builder.add_node("summarize", summarize)
builder.add_edge(START, "plan")
builder.add_edge("plan", "search")
builder.add_edge("search", "analyze")
builder.add_edge("analyze", "validate")
builder.add_conditional_edges("validate", should_retry, {
    "retry": "plan",     # 回环
    "finish": "summarize"
})
builder.add_edge("summarize", END)

步骤 2.2:搜索策略(三层回退)#

def _duckduckgo_search(query, timeout=20):
    # 方案1:hermes chat -q 快速问答(最可靠,但慢~50秒)
    from hermes_tools import terminal
    result = terminal(
        command=f'hermes chat -q "列出关于 {query} 的5个关键事实" --quiet',
        timeout=90
    )
    output = result.get("output", "").strip()
    lines = [l for l in output.split("\n") if l.strip() and not l.startswith("Warning:")]
    if len(lines) >= 2:
        return "\n".join(lines)

    # 方案2:DuckDuckGo Lite(urllib)
    import urllib.request, urllib.parse, re, html as html_module
    url = f"https://lite.duckduckgo.com/lite/?q={urllib.parse.quote(query)}"
    req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0..."})
    with urllib.request.urlopen(req, timeout=timeout) as resp:
        raw = resp.read().decode("utf-8", errors="replace")
    # DDG Lite 结果在 <table> 里,每条结果占 3 行 <tr>
    tables = re.findall(r'<table[^>]*>(.*?)</table>', raw, re.DOTALL)
    # ...提取标题、摘要、URL

步骤 2.3:数据注入模式(推荐用法)#

# 在 Hermes 对话里:
# 1. 先用 mcp__anysearch__search 搜索获取数据
# 2. 把搜索结果注入 graph 初始状态
# 3. graph 内部只做规则式处理(<1秒)

import sys, os
sys.path.insert(0, os.path.expanduser(
    "~/.hermes/skills/software-development/hermes-graph-engine/scripts"))
from research_graph import build_graph, ResearchState
import sqlite3
from langgraph.checkpoint.sqlite import SqliteSaver

# 搜索数据(由 Hermes MCP Anysearch 外部获取)
search_data = """...搜索结果..."""

# 构建 graph(带 checkpoint)
db_path = os.path.expanduser("~/.hermes/graph_checkpoints.db")
conn = sqlite3.connect(db_path, check_same_thread=False)
graph = build_graph(checkpoint=True, db_path=db_path)

# 运行
config = {"configurable": {"thread_id": f"research-{int(time.time())}"}}
result = graph.invoke({
    "topic": "AI agent loops vs graphs",
    "search_query": "...",
    "raw_results": search_data,  # 外部注入
    "findings": "", "validation_notes": "", "summary": "",
    "report_path": "", "attempts": 0, "validated": False
}, config)

验证结果:0.003 秒完成,8 条发现,验证合格,报告写入~/Desktop/graph_reports/


Level 3:MCP Server 跨会话持久化#

目标:把 Graph 能力包装成 MCP Server,让 Hermes 在任何会话里通过 MCP 工具调用——define/run/resume graph,无需每次在 execute_code 里临时构建。

步骤 3.1:安装 MCP Python SDK#

cd ~/.hermes/hermes-agent
source venv/bin/activate
pip install mcp

步骤 3.2:创建 MCP Server#

文件路径:~/.hermes/mcp-servers/graph_engine_mcp.py

用官方 MCP SDK 实现(确保正确的initialize/initialized握手):

#!/usr/bin/env python3
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
from langgraph.graph import StateGraph, END, START
from langgraph.checkpoint.sqlite import SqliteSaver
from typing import TypedDict, Any
import json, os, sqlite3, time

# ─── 持久化 ───
DB_DIR = os.path.expanduser("~/.hermes/graph_engine")
GRAPHS_DB = os.path.join(DB_DIR, "graphs.json")
CHECKPOINT_DB = os.path.join(DB_DIR, "checkpoints.db")
os.makedirs(DB_DIR, exist_ok=True)

server = Server("graph-engine")

@server.list_tools()
async def list_tools():
    return [
        Tool(name="define_graph", ...),
        Tool(name="run_graph", ...),
        Tool(name="resume_graph", ...),
        Tool(name="list_graphs", ...),
        Tool(name="get_graph_state", ...),
    ]

@server.call_tool()
async def call_tool(name, arguments):
    if name == "define_graph":
        # 保存 graph 定义到 JSON
        ...
    elif name == "run_graph":
        # 从 JSON 定义构建 LangGraph 并运行
        ...
    elif name == "resume_graph":
        # 从 checkpoint 恢复
        ...

async def main():
    async with stdio_server() as (read_stream, write_stream):
        await server.run(read_stream, write_stream,
                        server.create_initialization_options())

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

步骤 3.3:MCP Server 支持的节点类型#

类型
用途
关键配置
执行方式
code
执行 Python 代码
code

(模板),output_field
exec()

在安全作用域
search
DuckDuckGo 搜索
query

(模板),output_field
urllib

直连
llm
调用 hermes chat
prompt

(模板),output_field
subprocess.run(["hermes","chat","-q",...])
validate
规则验证
field

,min_length
字符串长度检查
write
写入文件
path

(模板),content(模板)
open().write()

步骤 3.4:关键实现细节——动态 TypedDict#

最重要的一步:必须用TypedDict而不是 plaindict作为 StateGraph 的状态类型,否则节点间 state 字段会丢失。

# ❌ 错误:plain dict 导致后续节点拿不到前序节点的字段
builder = StateGraph(dict)

# ✅ 正确:动态构建 TypedDict
from typing import TypedDict, Any
all_fields = set()
for node_def in nodes.values():
    out = node_def.get("output_field", "")
    if out:
        all_fields.add(out)
all_fields.update(["task", "result", "search_query", "raw_results",
                   "findings", "validation_notes", "summary", "report_path",
                   "attempts", "validated", "search_results"])
GraphState = TypedDict("GraphState", {f: Any for f in all_fields}, total=False)
builder = StateGraph(GraphState)

原因:LangGraph 的默认 state reducer 对 plain dict 只保留最新节点返回的 key。TypedDict 让 LangGraph 知道所有可能的字段,从而正确累积传递。

步骤 3.5:条件边路由配置#

# routes 定义: {"true": "report", "false": "analyze"}
# router 函数返回 "report" 或 "analyze"

# ❌ 错误:直接传 routes dict
builder.add_conditional_edges("validate", router, routes)

# ✅ 正确:转换成 {目标节点名: 目标节点名}
routing_map = {v: v for v in routes.values()}
builder.add_conditional_edges("validate", router, routing_map)

步骤 3.6:安全模板替换#

所有节点函数里用format(**state)会因为缺失 key 而崩溃。需要安全替换:

def _safe_format(template: str, state: dict) -> str:
    safe = {k: str(v) for k, v in state.items()}
    for k in ("task", "result", "findings", "validation_notes",
              "summary", "attempts", "validated", "search_query",
              "raw_results", "report_path", "search_results"):
        if k not in safe:
            safe[k] = ""
    try:
        return template.format(**safe)
    except Exception:
        return template

步骤 3.7:注册到 Hermes 配置#

~/.hermes/config.yamlmcp_servers字段添加:

mcp_servers:
  anysearch:
    url: https://api.anysearch.com/mcp
    headers:
      Authorization: Bearer ${MCP_ANYSEARCH_API_KEY}
    enabled: true
  graph-engine:
    command: "/Users/<你的用户名>/.hermes/hermes-agent/venv/bin/python3 /Users/<你的用户名>/.hermes/mcp-servers/graph_engine_mcp.py"
    enabled: true

或者用 Python 直接修改:

import os, yaml
config_path = os.path.expanduser("~/.hermes/config.yaml")
with open(config_path, 'r') as f:
    config = yaml.safe_load(f)
config["mcp_servers"]["graph-engine"] = {
    "command": f"{os.path.expanduser('~/.hermes/hermes-agent/venv/bin/python3')} "
               f"{os.path.expanduser('~/.hermes/mcp-servers/graph_engine_mcp.py')}",
    "enabled": True
}
with open(config_path, 'w') as f:
    yaml.dump(config, f, allow_unicode=True, default_flow_style=False, sort_keys=False)

步骤 3.8:验证 MCP Server#

# 1. 验证协议握手
import subprocess, json
init_msg = json.dumps({
    "jsonrpc": "2.0", "id": 1, "method": "initialize",
    "params": {"protocolVersion": "2024-11-05", "capabilities": {},
               "clientInfo": {"name": "test", "version": "1.0"}}
}) + "\n"
proc = subprocess.run(
    ["python3", "~/.hermes/mcp-servers/graph_engine_mcp.py"],
    input=init_msg, capture_output=True, text=True, timeout=8
)
# 应返回: {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05",...}}

# 2. 验证 define_graph
# 3. 验证 run_graph
# 4. 验证 list_graphs
# 5. 验证 get_graph_state

验证结果:5 个工具全部正常工作,checkpoint 持久化到 SQLite,graph 定义持久化到 JSON。

步骤 3.9:新会话激活#

MCP Server 在新会话启动时自动加载。重启 Hermes 或开新会话后:

hermes mcp list  # 应显示 graph-engine

在对话里用/tools确认define_graphrun_graph等工具可用。


Level 4:原生集成方向(长期)#

目标:把 Graph 能力深度集成到 Hermes 核心代码,让delegate_task直接支持 graph 模式。

这需要修改 Hermes 核心代码(agent/目录),是长期方案,需要向 Hermes 项目提 PR。

设想架构

agent/目录下新增graph_engine.py

# agent/graph_engine.py(设想)
from langgraph.graph import StateGraph, END, START
from langgraph.checkpoint.sqlite import SqliteSaver

class HermesGraphEngine:
    """Hermes 原生 Graph 引擎"""

    def __init__(self, hermes_home: str):
        self.checkpoint_db = os.path.join(hermes_home, "graph_checkpoints.db")

    def build_from_skill(self, skill_path: str):
        """从 Skill 文件加载 graph 定义"""
        ...

    def run(self, graph_name: str, input_state: dict, thread_id: str = None):
        """运行 graph,支持 checkpoint 恢复"""
        ...

config.yaml中新增配置:

delegation:
  mode: hybrid  # loop | graph | hybrid
  graph:
    checkpoint: true
    checkpoint_path: ~/.hermes/graph_checkpoints.db
    max_parallel: 5
    default_max_retries: 3

delegate_task支持 graph 模式:

# delegate_task 的 graph 模式
delegate_task(
    goal="研究 loops vs graphs",
    mode="graph",  # 新增:loop | graph
    graph_def={
        "nodes": {"research": {...}, "validate": {...}, "report": {...}},
        "edges": [...],
        "conditional_edges": [...]
    }
)

这是最终形态——但需要社区共识和核心团队审批。在 Level 1-3 的能力足够覆盖绝大多数场景之前,不建议触碰核心代码。


八、关键经验教训#

以下是实际验证过程中发现的关键问题和解法,每一条都踩过坑。

8.1 State 传递:必须用 TypedDict#

问题:用StateGraph(dict)时,节点 A 返回{"result": "xxx"},节点 B 拿到的 state 里只有{"result": "xxx"},初始状态里的task字段消失了。

原因:LangGraph 的默认 state reducer 对 plain dict 只保留最新节点返回的 key。

解法:用TypedDict(total=False)声明所有可能的 state 字段,LangGraph 会正确累积传递。

8.2 搜索源不可靠#

问题:DuckDuckGo HTML 版返回空壳页面(14K HTML 但无搜索结果)。Lite 版有时可用有时不行。频繁请求会被反爬。

解法:三层回退策略: 1. 优先在 execute_code 外部用 Hermes MCP 搜索工具(mcp__anysearch__search)获取数据,注入 graph 2. 用hermes chat -q做搜索式问答(可靠但慢,~50秒) 3. DuckDuckGo Lite 作为回退

8.3 LLM 子进程太慢#

问题hermes chat -q需要启动完整的 Hermes 会话,每次 30-60 秒。在execute_code的 5 分钟超时内,最多只能调 2-3 次。

解法: – graph 内部节点用规则式处理(正则/字符串匹配)——0秒 – 需要LLM 的数据在 execute_code 外部用 Hermes 工具获取,注入 graph 初始状态 – MCP Server 在独立进程里调 LLM(不受 execute_code 超时限制)

8.4 条件边路由配置#

问题add_conditional_edges的第三个参数(routing_map)的 key 必须是目标节点名,不能是 “true”/”false”。

解法

routes = {"true": "report", "false": "analyze"}
routing_map = {v: v for v in routes.values()}  # {"report": "report", "analyze": "analyze"}
builder.add_conditional_edges("validate", router, routing_map)

8.5 模板替换的 KeyError#

问题:节点函数里用template.format(**state)时,如果 state 里缺少模板引用的 key,会抛 KeyError。

解法:实现_safe_format()函数,补充缺失的 key 为空字符串。

8.6 MCP Server 必须用官方 SDK#

问题:手动实现 JSON-RPC 消息处理无法通过hermes mcp add的连接验证——它需要完整的 MCP 协议握手(initialize → initialized → tools/list)。

解法:用mcpPython 官方 SDK(pip install mcp),它自动处理协议握手。

8.7 MCP 注册方式#

问题hermes mcp add的交互式验证会尝试连接 server,但 stdio 模式的 server 在等待 stdin 输入时会超时。

解法:直接修改~/.hermes/config.yamlmcp_servers字段,跳过交互式验证。新会话启动时自动加载。

8.8 execute_code 超时限制#

问题execute_code有 5 分钟硬超时。如果 graph 内部有多个节点调用 LLM 或搜索,总时长很容易超限。

解法: – 用 checkpoint 把长 graph 拆成多段执行 – 每次execute_code只跑 graph 的一部分,下次传None继续 – 或者用 MCP Server 在独立进程里运行(不受超时限制)


九、日常使用指南#

场景 1:快速 graph 工作流(当前会话)#

在 Hermes 对话里直接说:

“用 graph 工作流帮我做:搜索 X → 分析 → 验证 → 总结,验证不过就重试”

Hermes 会加载hermes-graph-engineskill,在execute_code里构建 LangGraph。数据通过 MCP 搜索工具获取后注入 graph。

场景 2:持久化 graph(跨会话)#

在新会话里(MCP Server 已加载),直接用 MCP 工具:

定义一个 graph:
- 节点1: search 类型,搜索 "AI agent 架构趋势"
- 节点2: code 类型,提取关键发现
- 节点3: validate 类型,验证发现数量 ≥3
- 节点4: write 类型,写入报告到 ~/Desktop/report.md
- 条件边: 节点3 验证失败 → 回到节点1 重试(最多3次)

Hermes 会调用define_graph保存定义,然后run_graph执行。graph 定义持久化到 JSON,checkpoint 持久化到 SQLite。

场景 3:崩溃恢复#

如果 graph 执行中断(会话关闭、进程崩溃),用resume_graph从 checkpoint 恢复:

恢复 graph "research_pipeline" 的执行,thread_id 是 "research-1784617964"

场景 4:查看 graph 状态#

查看 graph "research_pipeline" 的当前状态,thread_id 是 "research-1784617964"

返回当前节点、state 值、下一步执行什么。

场景 5:并行 fan-out#

定义一个 graph:
- START 同时指向 research_a, research_b, research_c(三个搜索节点)
- 三个节点都指向 synthesize(汇总节点)
- synthesize 指向 END

三个搜索节点并行执行,全部完成后 synthesize 汇总。


十、OpenClaw 侧的 Graph 植入#

如果你也在用 OpenClaw,Graph 植入路径完全不同——不用写代码,装插件即可

# 方案A:DAG 工作流引擎(可视化编辑器,最完整)
openclaw plugins install clawhub:@lurkacai0831/openclaw-orchestrator
# 支持:条件分支(contains/regex/json)、并行汇合(AND/OR/XOR)、
#       人工审批卡点、失败自动重试、防无限循环、上下文持久化

# 方案B:持久化编排 + 共享记忆
openclaw plugins install clawhub:@parijatmukherjee/openclaw-hawkins
# 支持:VINES(状态持久化到MariaDB)、VECNA(衰减感知共享记忆)、
#       崩溃恢复、Linear 看板集成

# 方案C:自适应 LLM 编排器(非刚性DAG)
openclaw skills install agent-orchestrator
# 支持:任务分解、动态子agent生成、文件通信、consolidation

# 方案D:自然语言 DAG 编排
openclaw skills install agency-agents-router
# 支持:single/parallel/sequential/DAG-style,215 agent 描述库

OpenClaw vs Hermes 的 Graph 植入对比

维度
OpenClaw
Hermes Agent
植入方式
装插件
写代码(execute_code / MCP Server)
难度
低(零代码)
中(需要 Python + LangGraph 知识)
可视化
React Flow 拖拽画布
无(代码定义)
持久化
MariaDB / SQLite
SQLite
崩溃恢复
Hawkins VINES
LangGraph checkpoint
定制性
插件配置
完全可编程
适合人群
想快速用 graph 的用户
想深度定制 graph 逻辑的开发者

附录:文件清单与路径#

Hermes 侧交付物#

文件
路径
用途
Skill 主文档
~/.hermes/skills/software-development/hermes-graph-engine/SKILL.md
使用指南与模式参考
研究工作流脚本
~/.hermes/skills/software-development/hermes-graph-engine/scripts/research_graph.py
可复用的 graph 工作流模板
验证过的模式
~/.hermes/skills/software-development/hermes-graph-engine/references/verified-patterns.md
陷阱与解法
MCP Server
~/.hermes/mcp-servers/graph_engine_mcp.py
跨会话 Graph 引擎
Graph 定义存储
~/.hermes/graph_engine/graphs.json
已定义的 graph(JSON)
Checkpoint 数据库
~/.hermes/graph_engine/checkpoints.db
SQLite checkpoint
Level 2 checkpoint
~/.hermes/graph_checkpoints.db
execute_code 内嵌模式的 checkpoint
Hermes 配置
~/.hermes/config.yaml

mcp_servers.graph-engine
MCP Server 注册
报告输出目录
~/Desktop/graph_reports/
graph 生成的报告

依赖包#

版本
用途
langgraph
1.2.9
Graph 引擎核心
langchain-core
1.5.0
LangGraph 依赖
langgraph-checkpoint-sqlite
4.1.1
SQLite checkpoint 持久化
mcp
(最新)
MCP Server 官方 SDK

验证过的完整工作流#

用户对话 → Hermes 加载 hermes-graph-engine skill
    → execute_code 构建 LangGraph StateGraph
    → MCP 搜索工具获取数据(或外部注入)
    → graph 执行:plan → search → analyze → validate → summarize
    → 条件回环:验证失败 → 重试(最多3次)
    → checkpoint 持久化到 SQLite
    → 报告写入 ~/Desktop/graph_reports/
    → 返回结果给用户

或者通过 MCP Server

用户对话 → Hermes 调用 define_graph MCP 工具
    → graph 定义持久化到 graphs.json
    → Hermes 调用 run_graph MCP 工具
    → MCP Server 构建 LangGraph 并执行
    → checkpoint 持久化到 checkpoints.db
    → 报告写入文件
    → 返回结果给 Hermes → 返回给用户
    → 如需恢复:resume_graph 从 checkpoint 继续

本文基于Macs系统安装的 Hermes Agent 实际环境验证,所有代码和配置均已在 2026年7月21日的环境中测试通过。