Skip to main content

对照组:OpenHands / JoyAgent / Mini-Agent

一句话:前面五家拆得很深,这三家用来划边界——最小的 Agent 长什么样、Java 团队怎么做、以及有人把力气花在了完全不同的地方。

一、Mini-Agent:523 行的基线

先看最小的,好知道前面那些复杂度到底是加在哪儿的。

git clone --depth 1 https://github.com/MiniMax-AI/Mini-Agent.git
仓库MiniMax-AI/Mini-Agent
Star2,972
体量mini_agent/ 全部 1,949 行,核心 agent.py 523 行

主循环就是教科书那个样子:

mini_agent/agent.py:321-352(节选)
async def run(self, cancel_event: Optional[asyncio.Event] = None) -> str:
"""Execute agent loop until task is complete or max steps reached."""
...
step = 0
while step < self.max_steps:
# Check for cancellation at start of each step
if self._check_cancelled():
self._cleanup_incomplete_messages()
return "Task cancelled by user."

# Check and summarize message history to prevent context overflow
await self._summarize_messages()

# Get tool list for LLM call
tool_list = list(self.tools.values())
response = await self.llm.generate(messages=self.messages, tools=tool_list)
mini_agent/agent.py:53
max_steps: int = 50,

默认 50 步——对照 Kimi CLI 的 1000DeerFlow 的 150/60,也对照 Manus 官方说的「平均一个任务约 50 次工具调用」

Mini-Agent 的默认值刚好卡在 Manus 的实测均值上。 这不一定是巧合——50 大概就是「一个中等任务」的自然量级。

它没有的东西,就是「生产级」的定义

Mini-Agent 有:主循环、工具调用、上下文压缩、取消、重试、日志。

它没有:子 Agent、并发控制、token 预算、死循环检测、沙箱、审批、多租户。

把前面五篇的内容减去 Mini-Agent,剩下的就是「从能跑到能卖」之间那段距离。这也是为什么它自我定位是「a minimal yet professional single agent demo」——single agent,官方从没说它是多智能体框架。

用法建议:想搞懂 Agent 原理,先读这 523 行,比读任何框架文档都快。

二、OpenHands:把力气花在了安全上

git clone --depth 1 https://github.com/OpenHands/software-agent-sdk.git
主仓OpenHands/OpenHands 84,444★ —— 但它现在是 TypeScript 应用层
内核OpenHands/software-agent-sdk 1,007★ Python,真正的 Agent 在这
体量SDK 下 1,261 个 Python 文件

⚠️ 常见误读:很多人拿 OpenHands/OpenHands 那 84k star 说事,然后去里面找 Agent 循环——找不到。主仓已经变成前端应用,Agent 内核在 software-agent-sdk,只有 1,007 star。star 数和技术内核不在同一个仓库,这在这个领域越来越常见(OpenHands 是这样,Kimi 的 CLI 和模型也是分开的)。

子 Agent:Markdown frontmatter,和 Claude Code 一个路子

openhands/sdk/subagent/ 下只有四个文件:load.pyregistry.pyschema.py__init__.py。定义方式是 Markdown + frontmatter:

openhands/sdk/subagent/schema.py:346-348(节选)
model: str = str(fm.get("model", "inherit"))
...
tools: list[str] = _extract_tools(fm)
openhands/sdk/subagent/registry.py:174(注释)
- `model: inherit` preserves the parent LLM; an explicit model name ...

model: inherit 这个约定,Claude Code、DeerFlow、OpenHands 三家用的是同一个词。 三家独立实现却收敛到同一个 API 形状,说明这个抽象基本已经定型了:

定义格式模型字段工具字段
Claude CodeMarkdown + YAML frontmattermodel: inherittools / disallowedTools
OpenHands SDKMarkdown + frontmattermodel: inherittools
DeerFlowPython dataclassmodel: "inherit"tools / disallowed_tools
Kimi CLIYAML(带 extend 继承)default_modelallowed_tools / exclude_tools

想自己做一套的话,照着这个形状抄就行,四家已经替你验证过了。

真正的差异化:security/ 模块

这是 OpenHands 和其他几家最不一样的地方。openhands/sdk/security/ 下:

security/
├── analyzer.py ← 风险分析
├── llm_analyzer.py ← 用 LLM 判断风险
├── risk.py ← 风险等级
├── confirmation_policy.py ← 什么情况需要人工确认
├── shell_parser.py ← shell 命令解析
├── _shell_ast.py ← ★ shell 抽象语法树
├── defense_in_depth/ ← 纵深防御
├── ensemble.py ← 多个分析器投票
├── toolshield_helpers.py
├── toolshield_llm_analyzer.py
└── grayswan/ ← 对抗性测试

_shell_ast.py 是个信号:它不是用正则去匹配 rm -rf,而是把 shell 命令解析成抽象语法树再判断风险。

正则匹配的问题人尽皆知——rm -rf / 能拦,r''m -rf /$(echo cm0K | base64 -d) -rf /、变量拼接就拦不住。解析成 AST 之后才能真正理解「这条命令到底要干什么」。

ensemble.py 是多个分析器投票,defense_in_depth/ 是纵深防御,grayswan/ 指向对抗性测试。这一整套是「让 Agent 在别人的机器上跑命令」这件事必须付的代价。

对照 Suna 的做法:Suna 是把 Agent 关进沙箱,容器边界就是安全边界;OpenHands 是在命令级别做分析。两条路都对,但成本结构完全不同——沙箱贵在基础设施,AST 分析贵在误报率调优。

agent/parallel_executor.py 的存在说明它也支持并行工具执行,跟 Manus 的「一次一个工具」 是相反取向。

三、JoyAgent-JDGenie:Java 阵营的样本

仓库jd-opensource/joyagent-jdgenie
Star11,872
语言Java
⚠️ 活跃度最后 push 2026-02-12,已停更半年

三进程架构:

genie-backend/   ← Java,Agent 编排主体
genie-tool/ ← Python,工具执行
genie-client/ ←客户端
ui/

Java 做编排、Python 做工具——这个分工很务实。Java 生态在服务治理、事务、权限这些企业能力上强,Python 生态在 AI 工具链上强,各取所长。国内很多企业内部落地会走这条路,因为存量系统是 Java 的。

编排:经典的 Plan-Execute-Summary 三段式

genie-backend/src/main/java/com/jd/genie/agent/agent/ 下的类:

BaseAgent.java          ← 基类
ReActAgent.java ← ReAct 抽象
ReactImplAgent.java ← ReAct 实现
PlanningAgent.java ← 规划
ExecutorAgent.java ← 执行
SummaryAgent.java ← 总结
AgentContext.java ← 共享上下文

注意 AgentContext 是共享的。 这跟前面五家「每个子 Agent 一份独立上下文」的取向不一样——JoyAgent 的三个 Agent 是同一个任务的三个阶段,不是三个独立的委派对象。

这是两种不同的「多 Agent」:

类型含义代表
阶段式一个任务切成规划/执行/总结几段,各段一个 Agent,共享上下文JoyAgent、早期 MetaGPT
委派式主 Agent 把子任务外包出去,上下文隔离Kimi CLI、Claude Code、Manus、DeerFlow

阶段式是 2023–2024 年的主流,委派式是现在的主流。 原因不难理解:阶段式的共享上下文在长任务里会无限膨胀,而且规划阶段和执行阶段看到同样的上下文其实是浪费——规划不需要知道每个文件的具体内容。

JoyAgent 停更在 2026 年 2 月,某种程度上也是这代架构的时间戳。

要不要用它:如果你是 Java 团队且需要一个现成的起点,它仍然有参考价值,尤其是 Java/Python 分进程的工程结构。但半年没更新意味着模型侧的新能力(interleaved thinking、并行工具调用等)它都没跟上,别指望直接上生产。

四、三家的位置

Mini-AgentOpenHands SDKJoyAgent
定位教学基线生产内核企业落地起点
体量523 行核心1,261 个 py 文件Java 多模块
子 Agent没有Markdown frontmatter阶段式,共享上下文
差异化极简可读shell AST 安全分析Java + Python 分进程
活跃度活跃活跃停更半年
什么时候看想搞懂原理想抄一套生产实现Java 团队找参考

五、三条能带走的结论

  1. 「star 最多的仓库」不等于「代码在的仓库」。 OpenHands 84k star 的主仓是前端,内核在 1k star 的 SDK 里。看这个领域的项目先确认内核在哪。

  2. 子 Agent 的定义格式已经收敛了:Markdown/YAML frontmatter + model: inherit + tools/disallowed_tools。四家独立收敛到同一形状,直接抄。

  3. 「阶段式多 Agent」正在退场,「委派式」是当下主流。 判断一个项目新不新,看它的多 Agent 是「规划-执行-总结」还是「主 Agent 派子 Agent」,基本能定年代。

六、参考