文章

Agent 抽象模型比较:从 OpenHands 出发的思考

以 OpenHands 的 Action / Observation 模型为基准,比较 ReAct、LangGraph、AutoGen、Claude Code、smolagents 和 SWE-agent 的抽象边界与产品取舍。

2026/06/08 更新于 2026/06/08
  • Agent
  • OpenHands
  • 架构
  • AI 产品

Agent 产品真正困难的地方,不只是“让模型调用工具”。

更底层的问题是:

你如何定义 Agent 与世界交互的基本单位?

这个问题会决定很多后续设计:

  • 工具调用结果是否可审计;
  • 执行历史是否可回放;
  • 状态是否可以恢复;
  • 多环境执行是否可替换;
  • 控制流由框架、代码还是模型决定;
  • Agent 出错后能否解释原因;
  • 产品是否能从 demo 走向稳定系统。

我选择从 OpenHands 出发,是因为它把 Agent 抽象问题问得很清楚:Agent 想让世界发生什么,以及世界返回了什么。

这就是它的核心二元模型:

Action      = Agent 或 User 想让世界发生什么
Observation = 世界反馈回来的状态

这篇文章不是要证明 OpenHands 一定最好,而是借它作为基准,比较几类主流 Agent 抽象模型的边界和取舍。

评价维度

比较 Agent 框架时,我最关心六个维度。

维度问题
Action 表达Agent 的行动是 JSON schema、消息、代码、图节点,还是专用命令?
Observation 地位工具结果是一等公民,还是普通文本消息?
状态模型历史是 EventStream、State、Message Log,还是由调用方自己维护?
控制流位置决策由 LLM、图结构、代码、planner,还是多 Agent 对话决定?
Runtime 边界执行环境是否从 Agent 核心中解耦?
可审计性能否 replay、debug、追踪因果链、恢复会话?

这六个问题比“支持多少工具”“接了多少模型”更底层。

工具和模型可以后补,但抽象边界一旦选错,后面会很难改。

OpenHands:Action / Observation 作为世界模型

OpenHands 的核心世界观非常直接:

Action      = 想让环境发生变化
Observation = 环境对这个动作的反馈

Action 是强类型的。

CmdRunAction(command="pytest tests/")
FileWriteAction(path="src/agent.py", content="...")
BrowseInteractiveAction(browser_actions=...)
AgentFinishAction(outputs={...})

Observation 也是强类型的。

CmdOutputObservation(exit_code=0, content="...stdout...")
FileReadObservation(path="...", content="...")
BrowserObservation(screenshot=..., dom=...)
ErrorObservation(message="...")

这不是简单的 API 设计,而是一种事件词汇表。每一种 Action 都对应一种或多种可能的 Observation,Agent 的执行历史可以被建模成一条不断追加的事件流。

OpenHands 这个模型背后有两个关键支柱。

EventStream

所有 Action 和 Observation 都被追加写入 EventStream。

Agent 在推理时看到的不是一个不断被覆盖的状态对象,而是一条有因果顺序的执行历史。

这带来几个能力:

  • replay;
  • debug;
  • audit;
  • resume;
  • 多 Agent 协作的事件基础;
  • 成本和工具调用追踪。

对于 Agent 产品来说,这一点非常重要。

如果执行历史只是 prompt 里的文本,系统很难知道哪些内容是用户输入、哪些是工具结果、哪些是模型推理、哪些是环境错误。

Runtime 解耦

OpenHands 的另一个关键设计是 Runtime。

Agent 核心不应该关心命令到底在本地进程、Docker 容器、远程沙箱还是云端环境里执行。

CmdRunAction 只是表达“我要执行命令”。至于执行发生在哪里,应该由 Runtime 负责。

这让 Agent 核心和执行环境解耦:

Agent Core
  emits Action

Runtime
  executes Action

Observation
  returns to Agent

这个边界决定了系统能不能多环境部署、能不能沙箱隔离、能不能测试 mock、能不能远程执行。

我的判断是:

OpenHands 最值得学习的不是某个工具实现,而是它把 Observation 和 Runtime 都提升到了架构一等公民。

ReAct:正确范式,但不是完整架构

ReAct 的核心是:

Thought → Action → Observation

它的重要贡献是把中间推理步骤显式化。模型先思考,再行动,再根据观察继续思考。

这个范式非常重要,因为复杂任务确实需要 reasoning 和 acting 交替推进。

但 ReAct 本身不是完整产品架构。

它没有回答:

  • Action 类型怎么定义;
  • Observation 是否结构化;
  • 工具结果怎么持久化;
  • Runtime 在哪里;
  • 会话怎么恢复;
  • 控制流如何被审计;
  • 多步执行如何防止历史漂移。

所以我会把 ReAct 看作 Agent 思维模式,而不是系统架构。

OpenHands 基本继承了 ReAct 的后两步,但把 Thought 内化到 LLM token 流里,没有把 Thought 作为 EventStream 的一等事件长期保存。

这带来一个取舍:

  • 工程更干净;
  • 但推理过程不完全可 replay。

LangGraph:状态机务实,但限制自主性

LangGraph 的核心抽象是:

Node → Edge → State

开发者定义节点、边和条件跳转,Agent 在图里流转。

这是一种很工程化的思路。

它的优点是:

  • 控制流清楚;
  • 可视化友好;
  • 易测试;
  • 适合企业流程;
  • 适合有明确步骤和审批节点的任务。

但它也有一个根本张力:

如果图结构是预定义的,Agent 的自主性会被拓扑限制;如果图结构高度动态,图模型的可视化和确定性优势又会下降。

LangGraph 是 State first,OpenHands 是 Event first。

这两种模型适合不同场景。

场景更适合
固定业务流程、审批、条件分支LangGraph
开放式软件工程任务、动态工具使用OpenHands
强可视化、强流程编排LangGraph
强审计、强回放、强执行环境隔离OpenHands

我的判断是:LangGraph 很适合 Workflow Agent,但不一定适合所有 Execution Agent。

AutoGen:多 Agent 对话正确,工具交互偏弱

AutoGen 的核心抽象是:

Agent ↔ Agent Message

它把多个 Agent 之间互相发消息作为一等公民。

这个模型对多 Agent 协作很自然。Planner、Coder、Reviewer、User Proxy 之间确实可以用 message passing 组织。

但问题在于,当这个模型也被用于单 Agent 与工具环境交互时,Observation 容易退化成普通消息。

工具结果如果只是另一条 message,就会丢失很多结构信息:

  • exit code;
  • file path;
  • raw ref;
  • stdout / stderr;
  • error type;
  • tool call id;
  • observation source;
  • retry metadata。

对多 Agent 协调来说,消息模型很自然。

对工具调用和环境反馈来说,消息模型不够精确。

所以我的判断是:

AutoGen 的多 Agent 直觉是对的,但 Observation 不应该被降格成普通消息。

Claude Code / Aider:极简直接,但平台化能力有限

Claude Code 和 Aider 这类工具的抽象更接近底层模型 API:

tool_use → tool_result

这和 OpenHands 的 Action / Observation 映射很直接。

tool_use 等价于 Action,tool_result 等价于 Observation。

这种设计的优点是:

  • 简单;
  • 贴近模型 API;
  • 调试直接;
  • 小团队上手快;
  • 个人工具体验好。

但它的上限也很明显:

  • Runtime 解耦不足;
  • EventStream 不完整;
  • 状态管理通常由调用方维护;
  • replay 和审计能力弱;
  • 多环境部署需要额外封装。

这类设计很适合个人 CLI、IDE 插件、小规模工具。

但如果要做平台级 Agent 系统,只贴着 API message 格式是不够的。

smolagents:Code Action 很激进,也很有启发

smolagents 的核心思路是:

让 LLM 直接输出 Python 代码作为 Action。

这非常激进。

传统工具调用是有限词汇表:模型只能调用系统预定义的工具和参数 schema。

Code Action 则把行动语言变成图灵完备的代码。

例如,模型不必连续调用多个工具:

result = read_file("agent.py")
lines = result.split("\n")
error_line = next(line for line in lines if "Error" in line)
print(error_line)

它可以在一次代码块里组合读取、过滤、聚合、计算。

这个洞察非常深:

JSON schema 是有限行动语言,代码是可组合行动语言。

但代价也很明显:

  • 安全沙箱要求极高;
  • 错误通常表现为运行时异常;
  • Observation 不够结构化;
  • 自我修复需要解析异常文本;
  • 审计粒度可能变粗。

我的判断是,Code Action 不应该替代所有结构化 Action,但可以作为复杂临时组合能力。

更现实的架构是:

常规操作
  使用结构化 Action

复杂组合操作
  使用受限 Code Action

所有执行结果
  仍然转成结构化 Observation

SWE-agent / ACI:工具接口本身也需要为 Agent 设计

SWE-agent 的重点不完全在 Action / Observation 建模,而在 ACI:

Agent-Computer Interface

它强调工具接口应该为 LLM 使用而设计,而不是直接暴露人类开发者使用的底层命令。

这个观点很重要。

Agent 面对 shell、grep、sed、编辑器、浏览器时,并不一定应该使用人类一样的接口。它需要更适合模型理解和恢复的操作:

  • 明确的文件编辑接口;
  • 可解析的搜索结果;
  • 有上下文的错误输出;
  • 适合小步验证的测试反馈;
  • 低歧义的 patch 应用方式。

这和 OpenHands 的 Runtime 是同一层面的思考:

Agent 不只是需要工具,还需要适合 Agent 的计算机接口。

横向比较

把几个模型放在一起,可以得到这个对比:

模型核心抽象优点风险
ReActThought / Action / Observation推理范式清楚不是完整架构
LangGraphNode / Edge / State流程清楚,可测试自主性受预定义图限制
AutoGenAgent / Message多 Agent 协作自然工具 Observation 易退化成普通消息
Claude Code / Aidertool_use / tool_result简单直接,贴近 APIRuntime、EventStream、审计较弱
smolagentsCode as Action行动表达能力强安全和结构化 Observation 难
SWE-agent / ACIPlan / Edit / Verify + ACI工具接口适合 LLM流程相对线性
OpenHandsAction / Observation + EventStream + Runtime审计、回放、环境解耦强体系偏重,原型成本高

这里没有绝对赢家。

不同抽象对应不同产品目标。

如果是固定流程企业 Agent,LangGraph 的确定性更有价值。

如果是多 Agent 协作实验,AutoGen 的 message passing 很自然。

如果是个人 coding assistant,Claude Code / Aider 的极简模型更实用。

如果是开放式软件工程 Agent 平台,OpenHands 的 Action / Observation / Runtime 更稳。

我的判断

我倾向于认同 OpenHands 的方向,但不会完整照搬它的复杂度。

原因有三个。

第一,Observation 应该是一等公民

很多 Agent 框架重视 Action,却低估 Observation。

但 Agent 真正学习下一步怎么做,依赖的不是“它调用了什么工具”,而是“世界怎么回应了它”。

一个命令失败、一个文件不存在、一次浏览器点击无效、一次测试报错、一次用户拒绝权限,这些都不应该只是自然语言字符串。

它们应该是结构化 Observation。

结构化 Observation 的价值包括:

  • 减少模型重复解析;
  • 支持错误分类;
  • 支持重试策略;
  • 支持上下文压缩;
  • 支持审计和 replay;
  • 支持 UI 展示;
  • 支持后续训练数据构造。

第二,Runtime 必须解耦

Agent 不能默认绑定本机 shell。

一个成熟 Agent 产品需要面对:

  • 本地执行;
  • Docker 沙箱;
  • 远程 workspace;
  • 云端 runtime;
  • 只读 reviewer;
  • 隔离子任务;
  • 测试环境 mock。

如果 Runtime 不抽象,产品后期会被执行环境绑死。

OpenHands 在这一点上是对的。

第三,EventStream 是审计和恢复的基础

Agent 产品要建立信任,不能只展示最终回答。

它需要回答:

  • 用户说了什么;
  • Agent 做了什么;
  • 工具返回了什么;
  • 哪一步失败了;
  • 哪个 observation 导致了下一步 action;
  • 哪些内容被压缩;
  • 哪些权限被确认;
  • 如何恢复到某个 checkpoint。

这些问题都需要事件流。

仍未解决的问题

即使 OpenHands 的方向更完整,Agent 抽象仍然有几个开放问题。

Observation 是原始事实,还是解释后信息?

exit_code=1 加 300 行错误日志是原始事实。

“第 47 行类型不匹配”是解释后信息。

Agent 每轮都重新解释原始日志会浪费 token,也不稳定。

但如果框架提前解释 Observation,又可能引入新的模型推断。

更合理的方式可能是同时保留:

raw observation
interpreted observation
confidence
raw_ref

控制流应该在哪里?

LangGraph 说控制流在图里。

OpenHands 说控制流主要由 LLM 动态决策。

smolagents 说控制流可以在代码里。

这三个答案都对,但适用场景不同。

我更倾向于:

业务流程控制
  放在图或 workflow 中

开放式执行控制
  交给 Agent 动态决策

局部复杂组合
  允许受限代码表达

Thought 是否应该持久化?

OpenHands 不持久化完整 Thought,这在工程上简洁,也避免保存敏感推理链。

但代价是推理过程不完全可 replay。

未来可能需要一种折中:

  • 不保存完整 chain-of-thought;
  • 保存结构化 reasoning summary;
  • 保存 decision rationale;
  • 保存 action selection reason;
  • 保存 confidence 和 uncertainty。

这比完整 Thought 更安全,也比完全不记录更可解释。

对 Agent 产品的启发

从产品经理视角,这篇比较最重要的启发有五点。

第一,Agent 产品不是“模型 + 工具列表”。

真正的产品能力来自一套稳定的执行抽象:Action、Observation、Runtime、EventStream、Context、Permission、Checkpoint。

第二,不同 Agent 产品应该选择不同控制流。

业务流程 Agent 需要可视化 workflow;软件工程 Agent 需要开放式执行;代码编辑 Agent 需要强 ACI;多 Agent 系统需要 message passing。

第三,工具结果要产品化。

Observation 不是日志文本,而是可以被 UI 展示、被上下文治理、被错误恢复、被审计系统使用的结构化产品对象。

第四,执行环境是产品边界。

本地、云端、沙箱、远程 workspace、只读 reviewer,不同执行环境对应不同安全、成本、体验和商业模式。

第五,抽象越底层,越要克制。

OpenHands 的完整模型很强,但并不适合所有原型。早期产品可以先实现最小 Action / Observation / EventLog,再逐步引入 Runtime、Condenser、Permission、Checkpoint。

结论

OpenHands 的 Action / Observation 模型之所以值得研究,是因为它把 Agent 与世界交互的基本单位定义得足够清楚。

它提醒我们:

Agent 的核心不是聊天,而是行动、观察、记忆、恢复和审计。

ReAct 提供了推理范式,LangGraph 提供了流程控制,AutoGen 提供了多 Agent 对话模型,Claude Code / Aider 展示了极简工具调用体验,smolagents 提醒我们代码可以成为行动语言,SWE-agent 强调工具接口要为 Agent 设计。

但如果目标是构建可持续迭代的 Execution Agent 产品,我会优先保留 OpenHands 的三个核心判断:

  • Observation 是一等公民;
  • Runtime 必须解耦;
  • EventStream 是审计和恢复的基础。

在这个基础上,再根据具体产品场景选择图、消息、代码或专用 ACI。