☰
AgentScope 学习系列 - 02:ReActAgent 配置、消息与事件
2026/10/1 15:43:38 网站建设 项目流程

1. 写在前面

为了后续的学习,我们先来看两个概念,ReActAgent和HarnessAgent。

Agent(接口位于io.agentscope.core.agent.Agent,默认实现是ReActAgent)是 AgentScope 的核心抽象——一个推理-行动循环引擎,将模型、工具、权限系统、人机交互、上下文管理、中间件、状态管理和事件系统整合到一个统一接口中。

HarnessAgent是ReActAgent的一层薄包装,把长期运行 agent 必备的工程能力打包进单一 builder:工作区驱动的人格、长期记忆、子 agent 编排、沙箱隔离、技能装配、计划模式、Channel 路由。裸的ReActAgent只解决”一次请求 → 推理 → 工具 → 回复”。Harness 要回答的是另一组问题:下一轮怎么接着上一轮、上下文如何保持有界、多用户如何隔离、危险操作如何先 review 再执行、可复用能力如何沉淀。

有点类似于Deep Agents和LangChain的关系,HarnessAgent是针对ReActAgent的进一步包装。

整体的学习路线,我们将快速的过一遍ReActAgent的知识点,然后核心放到HarnessAgent。

2. ReActAgent配置介绍

上一篇搭建了一个简单的demo。那么这一篇我们一起看看ReActAgent具体有哪些参数和配置。

参数说明

参数类型默认值描述
nameString必填智能体标识符,用于消息和日志
sysPromptString必填智能体的基础系统提示词
modelModel必填用于推理的大语言模型(继承自ChatModelBase)
toolkitToolkitnew Toolkit()管理工具、MCP 客户端、技能和工具组
middlewaresList<? extends MiddlewareBase>List.of()应用于 agent / reasoning / acting / model call / system prompt 钩子
stateStoreAgentStateStorenull(不持久化)配置后 agent 在每次call后自动加载/保存AgentState,按该次调用RuntimeContext的(userId, sessionId)寻址
defaultSessionIdStringagentname当某次调用的RuntimeContext没带sessionId时的兜底值
permissionContextPermissionContextState默认DEFAULT模式工具执行的细粒度规则
modelConfigModelConfig默认值模型重试次数和备用模型
reactConfigReactConfig默认值最大迭代次数和拒绝处理方式
maxItersint10ReAct 主循环最大迭代次数(也可放在reactConfig中)

有一些基础的参数我们就不展开赘述了。这里先大体一览,后面我们会逐渐介绍。

本篇所有的代码,下面会用到,不再一一贴了:

packagecom.maple.agent.demo;importcom.maple.agent.MapleAgentApplication;importcom.maple.agent.config.OpenAiModelConfig;importio.agentscope.core.ReActAgent;importio.agentscope.core.event.*;importio.agentscope.core.message.*;importio.agentscope.extensions.model.openai.OpenAIChatModel;importorg.springframework.boot.SpringApplication;importorg.springframework.context.ConfigurableApplicationContext;publicclassReActAgent_02{publicstaticvoidmain(String[]args){// 为了方便提及代码,不暴露隐私信息,密钥放到application-pro.yml中ConfigurableApplicationContextctx=SpringApplication.run(MapleAgentApplication.class,args);OpenAiModelConfigprops=ctx.getBean(OpenAiModelConfig.class);OpenAIChatModelmodel=OpenAIChatModel.builder().baseUrl(props.getBaseUrl()).apiKey(props.getApiKey()).modelName(props.getModelName()).stream(true).build();ReActAgentagent=ReActAgent.builder().name("笑小枫的学习助手").model(model).sysPrompt("你是笑小枫的学习助手,可以帮助用户快速学习使用AgentScope开发智能体。").build();// call(agent);streamEvents(agent);}// 多模态消息,直接返回结果privatestaticvoidcall(ReActAgentagent){UserMessageuserMessage=newUserMessage("user",TextBlock.builder().text("这张图片是什么?").build(),DataBlock.builder().source(URLSource.builder().url("https://image.xiaoxiaofeng.site/blog/image/image-20260719154443011.png?xiaoxiaofeng").build()).build());Msgreply=agent.call(userMessage).block();System.out.println(reply.getTextContent());}// 流式返回结果privatestaticvoidstreamEvents(ReActAgentagent){agent.streamEvents(newUserMessage("user","帮我制定学习计划")).doOnNext(event->{if(eventinstanceofAgentStartEventstart){System.out.println("[start replyId="+start.getReplyId()+"]");}elseif(eventinstanceofTextBlockDeltaEventdelta){System.out.print(delta.getDelta());}elseif(eventinstanceofAgentEndEventend){System.out.println("\n[完成]");}}).blockLast();}// 演示执行事件,流式返回结果privatestaticvoidstreamEvents2(ReActAgentagent){StringBuilderaccumulated=newStringBuilder();agent.streamEvents(newUserMessage("user","你是谁?")).doOnNext(event->{if(eventinstanceofAgentStartEventstart){System.out.println("[start replyId="+start.getReplyId()+"]");}elseif(eventinstanceofThinkingBlockStartEventthinkingBlockStartEvent){System.out.println("[思考开始 replyId="+thinkingBlockStartEvent.getReplyId()+"]");}elseif(eventinstanceofThinkingBlockDeltaEventthinkingBlockDeltaEvent){System.out.println("[思考内容 ="+thinkingBlockDeltaEvent.getDelta()+"]");}elseif(eventinstanceofThinkingBlockEndEventthinkingBlockEndEvent){System.out.println("[思考完成 replyId="+thinkingBlockEndEvent.getReplyId()+"]");}elseif(eventinstanceofTextBlockDeltaEventdelta){accumulated.append(delta.getDelta());}elseif(eventinstanceofToolCallStartEventtc){System.out.println("[tool] "+tc.getToolCallName());}elseif(eventinstanceofToolResultEndEventend){System.out.println("[tool result state="+end.getState()+"]");}elseif(eventinstanceofAgentEndEventend){System.out.println("\n[end] full text:\n"+accumulated);}}).blockLast();}}

3. 消息类型

Msg(位于io.agentscope.core.message)代表对话中的一个轮次——用户输入、智能体回复或系统指令,内容以有序的类型化块(ContentBlock)列表表示。

Msg类的核心字段(getter)如下:

方法类型说明
getId()String唯一消息标识符
getName()String发送方名称(可空)
getRole()MsgRoleUSER/ASSISTANT/SYSTEM/TOOL
getContent()List<ContentBlock>有序内容块列表(不可变)
getMetadata()Map<String, Object>任意键值元数据
getTimestamp()String创建时间(yyyy-MM-dd HH:mm:ss.SSS)
getUsage()ChatUsageToken 用量(仅 assistant 消息)
getGenerateReason()GenerateReason退出原因:MODEL_STOP/TOOL_SUSPENDED/REASONING_STOP_REQUESTED/ACTING_STOP_REQUESTED/ALL_TOOLS_DENIED/INTERRUPTED/MAX_ITERATIONS

通过断点图,可以比较直观的看到上面的内容。

内容块

消息内容由类型化的块组成,每种块代表一类独立信息。块类位于io.agentscope.core.message:

块类型说明允许出现在
TextBlock纯文本内容USER、ASSISTANT、SYSTEM
DataBlock二进制数据(图片、音频、视频),通过 base64 或 URL;统一替代旧的 ImageBlock/AudioBlock/VideoBlockUSER、ASSISTANT
ThinkingBlock模型推理过程(思维链)ASSISTANT
ToolUseBlock工具调用,包含id/name/input/state(ToolCallState)ASSISTANT
ToolResultBlock工具执行结果,包含state(ToolResultState)ASSISTANT
HintBlock以用户上下文形式注入循环的指令ASSISTANT

我们用到的比较多的也就是前面两个,看一下怎么使用:

privatestaticvoidcall(ReActAgentagent){UserMessageuserMessage=newUserMessage("user",TextBlock.builder().text("这张图片是什么?").build(),DataBlock.builder().source(URLSource.builder().url("https://image.xiaoxiaofeng.site/blog/image/image-20260719154443011.png?xiaoxiaofeng").build()).build());Msgreply=agent.call(userMessage).block();System.out.println(reply.getTextContent());}

返回的结果如下:

关于ThinkingBlock和Tool相关(后面讲到工具再说)的消息,只有在streamEvents方式中能更好的体现。

4. 输出方式

我们上一篇演示的demo,直接返回了结果,如果我们想要打字机的那种展示怎么做呢,这里我们详细的讲一讲

  • call

call在内部消费所有事件,当智能体完成或因外部交互暂停时返回最终Msg。

  • streamEvents

    构建流式输出。streamEvents逐一产出AgentEvent对象,让你实时将文本输出、工具调用进度和生命周期事件流式传输给用户。

5. 执行事件

在上面我们看到了各种执行过程中的事件,事件是消息的流式对应物。每种类型的事件,都遵循start → delta → end模式。

其中delta可能产生多次,属于增量内容片段。

关于事件的执行顺序和生命周期,这里就不展开了,可以前往AgentScope官网查看。

https://java.agentscope.io/v2/zh/docs/building-blocks/message-and-event

6. 本章小结

本篇围绕ReActAgent展开,主要讲了三件事:

1. 概念区分:ReActAgent是 AgentScope 的核心抽象,负责“一次请求 → 推理 → 工具 → 回复”的循环;HarnessAgent是它的薄包装,额外打包了工作区、长期记忆、子 agent、沙箱等工程能力。

2. 消息体系:Msg代表对话中的一个轮次,由有序的ContentBlock组成。常用的有TextBlock(文本)和DataBlock(图片/音频/视频等多模态数据),此外还有ThinkingBlock(思维链)、ToolUseBlock/ToolResultBlock(工具调用与结果)、HintBlock(注入指令)。

3. 输出方式和执行事件:call会内部消费所有事件,等智能体完成或暂停后返回最终Msg,适合一次性拿结果;streamEvents则逐一产出AgentEvent,遵循start → delta → end模式,适合打字机式的实时展示。

本篇就到这里了,下一篇会深入介绍下ReActAgent的Middleware的扩展能力。

本系列源码https://gitee.com/hack-feng/maple-agent-demo

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询