重新认识 AgentScope-Java 2.0:ReActAgent 负责推理,HarnessAgent 负责运行
很多 Java 开发者第一次接触 Agent 框架,走的是同一条路:接入模型,写 Prompt,注册几个 Tool,再让 ReAct 循环跑起来。
这条路没有错。问题是,如果继续用它理解 AgentScope-Java 2.0,很容易把框架看窄:只盯着 agent.call() 怎么写、支持哪些模型、工具怎么声明,却忽略了一个 Agent 真正进入系统以后还要面对什么。
我的判断是:AgentScope-Java 2.0 的定位,已经从"构建一个 ReAct Agent"上移到了"运行和治理生产级 Agent"。
ReActAgent 仍然是推理内核,负责模型、消息、工具和推理循环;HarnessAgent 则把工作区、记忆、计划、权限、子 Agent、沙箱和状态恢复组织到一起,成为面向真实应用的工程入口。
换句话说,AgentScope-Java 2.0 不只关心 Agent 会不会调用工具。它开始回答另一组更麻烦的问题:这个 Agent 以什么身份运行?文件放在哪里?状态如何保存?子 Agent 能继承哪些权限?任务中断以后怎么恢复?
这才是理解 2.0 的主线。
如果还停留在 ReAct,看到的只是推理内核
把 Agent 简化成下面这条链路,是很自然的:
text
模型 + Prompt + Tool + ReAct 循环
这套结构解决的是"Agent 如何完成一次任务"。模型负责判断下一步,Tool 连接外部能力,ReAct 循环在推理、行动和观察之间不断推进,直到返回结果。
在 AgentScope-Java 2.0 里,这部分能力没有消失。ReActAgent 仍然承担核心推理工作。如果你的需求只是一个短生命周期、边界简单的工具调用 Agent,官方 README 也明确说明,可以只依赖 agentscope-core,直接使用裸 ReActAgent。
但一次调用跑通,不代表 Agent 已经能进入真实应用。
只要任务开始跨越多个用户、多个会话或者多轮执行,新的问题马上会出现:
- 两个用户同时调用同一个 Agent,状态会不会串?
- 工具生成的报告、计划和临时文件应该放在哪里?
- Agent 重启以后,上一轮任务从哪里继续?
- 子 Agent 被委派出去以后,能不能绕过父 Agent 的权限边界?
- 一个任务取消了,事件流、状态和后台执行是否真的结束?
这些问题都不属于 ReAct 算法本身,却决定了 Agent 能不能长期运行。
HarnessAgent 为什么成了 2.0 的工程入口
当前中文 README 的 Maven 快速开始,首先引入的是:
xml
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-harness</artifactId>
<version>2.0.0</version>
</dependency>
第一个示例创建的也不是裸 ReActAgent,而是 HarnessAgent:
java
HarnessAgent agent = HarnessAgent.builder()
.name("assistant")
.sysPrompt("你是一个有用的 AI 助手。")
.model("dashscope:qwen-plus")
.workspace(Paths.get(".agentscope/workspace"))
.build();
RuntimeContext ctx = RuntimeContext.builder()
.sessionId("demo")
.userId("alice")
.build();
agent.call(new UserMessage("你好!"), ctx).block();
这段代码表面上仍然是创建 Agent、传入消息、获取结果,但多了两个不该被忽略的对象:Workspace 和 RuntimeContext。
它们说明这次调用不再发生在一个抽象的推理循环里,而是属于具体用户、具体会话和具体工作空间。
从源码关系看,HarnessAgent 并没有继承 ReActAgent。它实现 Agent 接口,内部持有一个 ReActAgent delegate,再通过 Middleware、Toolkit 和各类 Manager 叠加工程能力。
所以,"薄包装"这个说法只适用于它和推理内核的组合关系,不能理解成它承担的工作很少。恰恰相反,HarnessAgent 增加的都是 Agent 进入真实系统后最难补的部分:
- 基于 Workspace 加载
AGENTS.md、MEMORY.md、知识、技能和子 Agent 定义; - 在本地文件系统、共享存储和沙箱之间切换;
- 进行上下文压缩和大工具结果卸载;
- 支持 Plan Mode;
- 同步或后台委派子 Agent;
- 装配 MCP Server 和工具白名单;
- 管理多会话状态、恢复与并发。
可以把两者的分工简单理解为:
| 层次 | 核心对象 | 主要回答的问题 |
|---|---|---|
| 推理内核 | ReActAgent |
Agent 怎么理解消息、调用工具并完成任务? |
| 工程入口 | HarnessAgent |
Agent 怎么带着身份、状态、文件和权限长期运行? |
AgentScope-Java 2.0 的变化,不是把前一层替换掉,而是在前一层之上补齐了运行环境。
三个对象,划清 Agent 的运行边界
理解 AgentScope-Java 2.0,最关键的不是记住所有 Builder 配置,而是先分清 RuntimeContext、AgentState 和 Workspace。
RuntimeContext:谁在发起这次调用
RuntimeContext 是每次调用的运行上下文,核心标识是 userId 和 sessionId。
HarnessAgent 自身在调用之间不保存用户状态,可以作为单例服务多个用户和会话。真正的隔离依据来自本次调用传入的 (userId, sessionId):同一会话的调用会串行执行,不同会话可以并行。
这和在 Controller 里直接复用一个有状态 Agent 完全不同。多用户服务不能依赖默认 session,也不应该把当前用户藏在一个全局变量里。身份必须跟着每次调用显式进入运行上下文。
AgentState:任务运行到了哪里
AgentState 保存的是运行快照,例如:
- 对话缓冲和摘要;
- 当前迭代位置;
- 工具上下文;
- 权限上下文;
- 子任务状态;
- Plan Mode 上下文;
- 中断标记。
AgentStateStore 负责保存和恢复这些状态。它处理的是"这次任务跑到了哪里",而不是业务系统里所有需要持久化的数据。
例如代码评审系统里的 ReviewJob、审批状态和发布记录,仍然应该属于业务领域;不能因为框架提供了 AgentState,就把业务数据库全部塞进去。
Workspace:Agent 长期留下了什么
Workspace 保存的是跨调用可复用的文件和 Agent 定义,例如:
text
AGENTS.md
MEMORY.md
memory/
skills/
subagents/
plans/
会话日志
任务报告
计划文件、生成报告、长期记忆和技能都更接近 Workspace 产物,而不是一次调用的内存状态。
这三个对象合在一起,形成了 AgentScope-Java 2.0 的运行模型:
text
RuntimeContext:谁在运行
AgentState:任务运行到了哪里
Workspace:任务长期留下了什么
如果这三个边界没有分清,后面的分布式状态、权限和恢复都会混在一起。
Plan Mode 管的不只是计划,而是执行阶段
旧版 PlanNotebook 容易让人把计划理解成一个记录任务清单的组件。当前源码已经删除了这套 API,替代它的是 HarnessAgent.builder().enablePlanMode()。
这不是一次同构替换。
Plan Mode 先让 Agent 进入只读调查阶段。它可以读取资料、分析问题,并通过 plan_write 更新计划文件,但不能直接执行修改。当计划完成后,plan_exit 再通过 ASK / HITL 权限流程请求进入执行阶段。
这里同时存在两种状态:
- 计划文件写入 Workspace,成为可检查、可保留的任务产物;
- 当前是否处于 Plan Mode,写入
AgentState.planModeContext,属于运行状态。
这正好体现了前面的分层:计划内容和执行阶段不是一回事。
Plan Mode 还会影响子 Agent。7 月底的源码已经实现:父 Agent 处于 Plan Mode 时,由 Harness 自动构建和复用的本地子 Agent 也会进入对应的计划阶段;父级的 DENY 权限规则会合并到子 Agent 对应的用户和会话槽位。
这条规则很重要。多 Agent 协作最危险的情况,不是主 Agent 明着越权,而是它把任务委派出去以后,子 Agent 获得了更大的能力。
当前仓库的 plan-mode.md 仍保留一处"子 Agent 不自动继承"的旧说明,但 subagent.md、实现代码和回归测试已经指向继承行为。涉及权限边界时,应以当前源码和测试为准。
权限和沙箱,解决的是 Agent 能走多远
工具注册解决"Agent 能做什么",权限系统解决"这一次允许它做到哪一步"。
在 AgentScope-Java 2.0 里,权限边界已经覆盖:
- 工具允许与拒绝;
- Plan Mode 的只读限制;
- 从计划进入执行的人工确认;
- 父 Agent DENY 规则向子 Agent 继承;
- Workspace 的用户和会话隔离;
- 本地、Docker、Kubernetes、E2B 等文件系统或沙箱后端。
源码还在路径层做了额外防护。AbstractFilesystem.validatePath()、LocalFilesystem.resolveRooted() 和 WorkspaceManager 会拒绝包含 .. 段的路径穿越,并验证解析后的路径仍处于工作区根目录内。启用用户命名空间时,也不能借路径逃逸到其他用户目录。
这并不意味着业务系统可以删除自己的安全检查。
框架知道的是 Workspace、Tool 和 Sandbox 的边界,业务系统知道的则是"这个用户能不能评审这个仓库""这份报告能不能发布""这个审批能不能跳过"。两层防线解决的是不同问题,应该叠加,而不是互相替代。
真正暴露框架定位的,是那些 Demo 看不到的问题
从 RC4 到当前源码,最能说明 AgentScope-Java 2.0 定位的,不是增加了多少模型和 Starter,而是近期修复集中在哪里。
这些提交反复处理的是:
- 用户中断或应用关闭时保存状态;
- 短生命周期 Agent 关闭后解除状态保存器,避免资源累积;
- 连续上下文压缩时保留上一轮摘要,避免用户意图丢失;
- 异步子 Agent 被取消后正确关闭事件流;
- 流式工具参数为 null、文本 delta 丢失和模型 SSE 错误体丢失;
- Windows shell、工作区路径和异常 Unicode 状态文件兼容;
- 沙箱快照、跨节点恢复和分布式执行锁。
这些问题不会出现在最简单的 Hello World 里。Demo 只需要证明 Agent 能给出答案,真实系统却要保证它被取消后真的停止、重启后能够恢复、多个副本不会重复执行、上下文压缩后仍然记得用户要做什么。
所以,AgentScope-Java 2.0 的价值越靠近生产环境,越体现在 ReAct 循环之外。
从 RC4 走过来的项目,不需要推倒重来
框架主入口变化,不等于以前基于 ReActAgent 写的项目全部失效。
以现有 Review Copilot(代码评审助手) 系列为例,RC4 阶段建立的业务结构仍然成立,只是放到当前 2.0 里需要重新划分责任:
| RC4 项目中的做法 | 放到当前 AgentScope-Java 2.0 中怎么理解 |
|---|---|
AgentFactory 封装 ReActAgent |
短任务仍可保留;长期运行场景再评估上移到 HarnessAgent |
| 自建 SSE 进度事件 | 业务事件继续保留;框架执行过程优先接 streamEvents() |
| 手工只读路径守卫 | 继续作为业务防线,框架层再叠加 Workspace、Permission 和 Sandbox |
ModelFactory 隔离模型提供商 |
继续保留;模型 artifact、兼容协议和语义 formatter 是不同层次 |
| Middleware 记录审计信息 | 继续保留,并补充 RuntimeContext、session 和子 Agent 来源 |
ReviewJob 和 Markdown 报告 |
ReviewJob 属于业务状态,报告更接近 Workspace 的持久产物 |
迁移的重点不是把所有 ReActAgent 换成 HarnessAgent,而是先问清楚:现有项目里哪些代码在处理推理,哪些代码在处理运行环境,哪些又是不能交给框架的业务规则。
边界清楚以后,才知道哪些能力应该保留,哪些重复建设可以交还给 Harness。
重新安排 AgentScope-Java 2.0 的学习顺序
如果仍然按照"模型接入---Prompt---Tool Calling---ReAct"一路学到底,很容易在最熟悉的地方停下来。
更适合 2.0 的学习顺序是:
- 用
ReActAgent理解消息、模型、工具和推理循环; - 用
HarnessAgent理解 AgentScope-Java 2.0 的工程入口; - 分清
RuntimeContext、AgentState和Workspace; - 再进入 Plan Mode、Permission、Sandbox 和子 Agent;
- 最后处理状态恢复、沙箱快照和分布式执行。
这条顺序没有否定 ReAct。它只是把 ReAct 放回了正确的位置:推理内核,而不是生产级 Agent 的全部。
什么情况下值得了解 AgentScope-Java 2.0
如果你只想写一个短生命周期、边界简单的工具调用 Agent,直接使用 ReActAgent 就够了。甚至在很多业务里,一个清晰的工作流加几次模型调用,比引入完整的 Harness 更合适。
但如果你想尝试搭建一个 Java 版多 Agent 协作平台,可以去了解一下 AgentScope-Java 2.0。
重点不要只看 agent.call(),而要看 HarnessAgent 如何组织 Workspace、Plan Mode、子 Agent、权限和状态恢复。这些能力,正好对应多 Agent 平台最早会遇到的任务协作、权限继承、过程留痕和失败恢复问题。
它不会替你完成所有业务设计,也不会自动解决多 Agent 协作中的任务划分和结果质量问题,但能提供一套现成的 Agent 运行底座。
这才是 AgentScope-Java 2.0 更值得关注的地方。