HarnessAgent vs ReActAgent 对比
在项目的性能测试中发现,spring-ai-alibaba(使用 ReActAgent)的平均响应时间(7213ms)比 agentscope(使用 HarnessAgent)快约 2.47 倍(17805ms)。
本文从源码层面深入分析两者的核心差异,以及对应的优化实践。
一、关系与定位
HarnessAgent
└── 内部持有 ReActAgent delegate(真正执行 LLM ReAct 循环)
└── build() 时向 ReActAgent 注入 N 层 Middleware
HarnessAgent 并不是 ReActAgent 的替代品,而是包裹它的高层编排框架。HarnessAgent 的 Javadoc 原文:
HarnessAgent is the user-facing harness API that wraps a
ReActAgentwith workspace / filesystem / sandbox / subagent / skill / plan-mode / MCP orchestration.For plain ReAct usage without any of the above, use
ReActAgent#builder()directly.
二、Middleware 装配差异
这是两者性能差距的根本原因。每次调用 HarnessAgent.builder()...build() 时,harness 向内部 ReActAgent 注入约 12+ 层 Middleware:
| Middleware | 功能 | HarnessAgent | ReActAgent |
|---|---|---|---|
WorkspaceContextMiddleware |
读取 AGENTS.md / MEMORY.md / KNOWLEDGE.md 注入上下文 | ✅ | ❌ |
AtPathExpansionMiddleware |
@path 语法自动展开为文件内容 |
✅ | ❌ |
MemoryFlushMiddleware |
超长上下文时将历史消息落盘到 workspace | ✅ | ❌ |
MemoryMaintenanceMiddleware |
对话历史维护与 context 管理 | ✅ | ❌ |
CompactionMiddleware |
token 超限时自动压缩历史(本项目已 disableCompaction()) |
✅ | ❌ |
ToolResultEvictionMiddleware |
清除过旧的 Tool 执行结果 | ✅ | ❌ |
HarnessSkillMiddleware |
按需从 AgentSkillRepository 动态加载 skill code 并执行 |
✅ | ❌ |
SandboxLifecycleMiddleware |
Docker 沙箱容器生命周期管理 | ✅ | ❌ |
SubagentsMiddleware |
Subagent 编排(task / task_output 工具) | ✅ | ❌ |
AsyncToolMiddleware + InboxMiddleware |
异步 Tool 执行与消息收件箱 | ✅ | ❌ |
PlanModeMiddleware |
Plan 模式(只读设计阶段) | ✅ | ❌ |
SkillUsageMiddleware + SkillCuratorMiddleware |
Skill 自学习与自动提升 | ✅ | ❌ |
AgentTraceMiddleware |
执行链路追踪 | ✅ | ❌ |
ReActAgent.build() 仅做轻量装配(Toolkit 复制、Hook 注册、Middleware 排序),不含上述任何层。
源码佐证
// HarnessAgent.java Builder.build() — 部分 middleware 注册片段
inner.middleware(new AgentTraceMiddleware());
inner.middleware(new WorkspaceContextMiddleware(...));
inner.middleware(new AtPathExpansionMiddleware(wsManager));
inner.middleware(new MemoryFlushMiddleware(...));
inner.middleware(new MemoryMaintenanceMiddleware(...));
inner.middleware(new CompactionMiddleware(...)); // disableCompaction() 可跳过
inner.middleware(new ToolResultEvictionMiddleware(...));
inner.middleware(new InboxMiddleware(...));
inner.middleware(new SubagentsMiddleware(...));
inner.middleware(new AsyncToolMiddleware(...));
inner.middleware(new HarnessSkillMiddleware(...)); // Skill 核心
// + PlanModeMiddleware、SkillUsageMiddleware、SkillCuratorMiddleware ...
// ReActAgent.java Builder.build() — 核心装配(精简)
Toolkit agentToolkit = this.toolkit.copy();
if (skillBox != null) configureSkillBox(agentToolkit);
middlewares.sort(Comparator.comparingInt(MiddlewareBase::order).reversed());
return new ReActAgent(this, agentToolkit);
三、功能能力对比

四、实测性能对比
基于 mailanti-ai-antiagent 项目,300 题 × 3 服务的并发压测(seed = 42,并发 5 线程):
v1 基准测试(未优化)
| 服务 | avg | P50 | P90 | P95 | max | 成功率 |
|---|---|---|---|---|---|---|
| spring-ali(ReActAgent) | 7213ms | 6890ms | 10492ms | 12031ms | 16647ms | 100% |
| agentscope(HarnessAgent) | 17805ms | 16173ms | 26824ms | 33724ms | 89380ms | 95.7% |
| 倍率 | 2.47x | 2.35x | 2.56x | 2.80x | — | — |
spring-ali 在 285 对配对中,99.3% 的题目更快,平均领先 10639ms。
性能差距的代码层根因
① 每次请求重建 HarnessAgent(AgentscopeAgentChatProvider.java:55)
try (HarnessAgent agent = agentFactory.create(command.getAgentHost(), command.getModel())) {
// 每次请求都 build() + close(),12+ 层 Middleware 每次重新装配
}
② workspace 文件系统 I / O(AgentFactory.java:43)
HarnessAgent.builder()
.workspace(Path.of(properties.getWorkspaceRoot(), normalizedHost))
// build() 时 WorkspaceManager.validate() + WorkspaceIndex.open() 触发 I/O
③ 默认 JsonFileAgentStateStore
不传 stateStore 时,harness 使用 JsonFileAgentStateStore,每次 build 从 ~/.agentscope/state/<agentId>/ 读写 session 状态文件。
五、优化实践
优化 1:workspace 定时预热
新增 WorkspaceWarmupScheduler,启动时 + 每 20 分钟对所有 agentHost 执行一次 build+close 预热,提前完成 skill 文件落盘:
@Slf4j
@Component
@RequiredArgsConstructor
public class WorkspaceWarmupScheduler {
private final AgentFactory agentFactory;
private final AgentHostMapper agentHostMapper;
private final SkillService skillService;
@PostConstruct
public void warmupOnStartup() {
warmupAll();
}
@Scheduled(fixedDelay = 20 * 60 * 1000L, initialDelay = 20 * 60 * 1000L)
public void warmupOnSchedule() {
warmupAll();
}
private void warmupAll() {
List<AgentHostEntity> hosts = agentHostMapper.selectList(
new LambdaQueryWrapper<AgentHostEntity>().eq(AgentHostEntity::getEnabled, 1));
for (AgentHostEntity host : hosts) {
String normalizedHost = skillService.normalizeAgentHost(host.getAgentHost());
try {
agentFactory.preWarmWorkspace(normalizedHost);
} catch (Exception ignored) {}
}
}
}
优化 2:InMemoryAgentStateStore 缓存
将默认文件持久化改为按 agentHost 缓存的纯内存实现,InMemoryAgentStateStore 内部已按 (userId, sessionId) 隔离:
// AgentFactory.java
private final ConcurrentHashMap<String, InMemoryAgentStateStore> stateStores = new ConcurrentHashMap<>();
private HarnessAgent buildAgent(String normalizedHost, String modelName) {
// ...
InMemoryAgentStateStore stateStore = stateStores.computeIfAbsent(
normalizedHost, k -> new InMemoryAgentStateStore()
);
return HarnessAgent.builder()
.name("agentscope-" + normalizedHost)
.model(model)
.workspace(Path.of(properties.getWorkspaceRoot(), normalizedHost))
.skillRepository(repo)
.stateStore(stateStore) // 纯内存,零文件 I/O
.disableCompaction()
.build();
}
优化效果(v1 → v3.0)
| 指标 | v1(优化前) | v3.0(优化后) | 变化 |
|---|---|---|---|
| avg | 17805ms | 15938ms | ↓1867ms(-10.5%) |
| P50 | 16173ms | 13328ms | ↓2845ms(-17.6%) |
| P75 | 21613ms | 19158ms | ↓2455ms(-11.4%) |
| P95 | 33724ms | 31845ms | ↓1879ms(-5.6%) |
| max | 89380ms | 61324ms | ↓28056ms(-31.4%) |
| ≤10s 占比 | 16.7% | 27.4% | ↑10.7pp |
| 与 spring-ali 差值均值 | 10639ms | 9098ms | ↓1541ms(-14.5%) |
P50 改善最显著(-17.6%),≤10s 快速响应比例大幅提升,说明两项优化在中位数附近效果最明显。
六、剩余差距分析
优化后 agentscope avg 15938ms,仍是 spring-ali(6845ms)的 2.33 倍。
| 优先级 | 根因 | 状态 | 影响 |
|---|---|---|---|
| P0 | HarnessAgent middleware 装配链(12+ 层) | ❌ 未消除 | 高(主因) |
| P1 | workspace WorkspaceManager.validate() 轻量 I / O |
✅ 预热缓解 | 中 |
| P2 | JsonFileAgentStateStore 文件读写 |
✅ 内存化消除 | 低 |
| P3 | HarnessSkillMiddleware vs SkillBox 差异 | ❌ 未优化 | 低 |
进一步优化方向
若需彻底消除差距,核心方案是将 HarnessAgent 换为 ReActAgent(参考 spring-ali 实现),只保留 SkillBox + InMemoryMemory,彻底跳过 12+ 层 harness Middleware 的装配开销,预期 avg 可降至 7-9s 量级。
该方案代价是放弃 HarnessAgent 提供的 workspace 文件上下文、Subagent 编排、Skill 自学习等高级能力 —— 需根据实际业务需求权衡取舍。
七、总结
使用 HarnessAgent 的场景:
✅ 需要 workspace 文件上下文(AGENTS.md 引导 Agent 行为)
✅ 需要 Skill 自学习(SkillCurator 自动提升常用 skill)
✅ 需要多 Agent 协作(Subagent 编排)
✅ 需要 Sandbox 代码执行(Docker 隔离)
使用 ReActAgent 的场景:
✅ 纯问答 / 工具调用 / RAG
✅ Skill 列表固定,无需动态加载
✅ 对延迟敏感,每请求开销要尽量小
✅ 代码更简洁,维护成本低
对于 mailanti-ai-antiagent 这类以单轮问答 + 固定 skill 调用为主的场景,ReActAgent 是更合适的选择。