03-AgentScope核心概念全景:Agent / Message / Model 与 ReAct

系列第 3 篇 · 启航篇

上两篇我们做到了:知道 AgentScope Java 是什么、还亲手跑通了第一个 HarnessAgent。但说实话------它到底是怎么"想"的?消息在内部怎么流转?模型又是怎么被调用的?

如果你对这三个问题还是模糊的,那后面讲工具调用、记忆、RAG、多 Agent 时,你只能"照着抄代码",一旦报错就无从下手。

所以这一篇,我们把镜头彻底拉远,讲清楚支撑一切的四个核心概念:Agent、Message、Model、ReAct 循环,外加 2.0 一个很 Java 工程师胃口的理念------透明开发。理解了它们,后面所有能力你都会"知其所以然"。


一、先建立一张全景图

AgentScope 的世界里,有四类核心抽象,它们的关系一句话就能说清:

Agent 在 ReAct 循环里,不断用 Message 与 Model 对话,直到产出最终答案。

sql 复制代码
graph TD
    A[Agent 智能体] -->|运行于| R[ReAct 循环]
    R -->|用 Message 与| M[Model 大脑]
    R -->|产出/消费| MSG[Message 消息]
    A -->|两种形态| RA[ReActAgent推理循环]
    A -->|两种形态| HA[HarnessAgent工程封装]

Agent是"执行者",负责把任务跑完;

ReAct是它内部的"运转机制",决定每一步是继续推理还是调用工具;

Message是 Agent 与模型、Agent 与 Agent 之间流通的"通用语言";

Model是 Agent 的"大脑",负责真正的推理与生成。

记住这张图,后面每篇都是在给其中一块"添砖加瓦"。


二、Agent:智能体的两种形态

在 2.0 里,"Agent"不是只有一个类,而是分两层,这也是 2.0 最重要的设计取舍:

1.ReActAgent------ 推理核心

它实现了 ReAct 算法(Reasoning + Acting 循环),负责"这一次推理怎么跑":纯推理、工具调用、记忆读写等原子能力都长在它上面。如果你只是想理解原理、或写个一次性脚本,用它就够了。

2.HarnessAgent------ 工程外壳(2.0 推荐)

它在 ReActAgent 之上,负责"长期运行的 Agent 怎么稳定、安全、可扩展":工作区、会话持久化、长期记忆、上下文压缩、沙箱隔离、权限控制......这些都是通过 Middleware / Toolkit叠加上去的,关键点在于它不改写推理循环。

2.0 一句话定位:推理归 ReAct,运行归 Harness。两者职责分离,所以你既能享受稳定工程能力,又不必担心底层推理被改坏。

cs 复制代码
// 2.0 推荐:直接 HarnessAgent 起步
HarnessAgent agent = HarnessAgent.builder()
        .name("assistant")
        .sysPrompt("你是一个有用的 AI 助手。")
        .model("dashscope:qwen-plus")              // ModelRegistry 解析
        .workspace(Paths.get(".agentscope/workspace"))
        .build();

(如果你只想要"裸推理"做实验,把 HarnessAgent 换成 ReActAgent、workspace(...) 去掉即可,其余写法一致。)


三、Message:Agent 之间的"通用语言"

这是 2.0 变化最大、也最值得理解的一块。很多 1.x 教程里把消息当"一句话",2.0 把它升级成了结构化的对话轮次。

3.1 一个关键认知

Msg(包 io.agentscope.core.message)不是"一句话",而是完整的一轮对话------可以是用户的一句输入、Agent 的一次回复、或一条系统指令。特别重要:一条 assistant 消息对应一次完整的call周期(内含多轮"推理 + 行动",直到最终回复)。

3.2 内容由"内容块"组成

2.0 里消息内容是有序的、带类型的 ContentBlock 列表,而不是一坨字符串。常见块类型:

| 块类型 | 说明 | 出现在哪些角色 | | --- | --- | --- | | TextBlock | 纯文本 | USER / ASSISTANT / SYSTEM | | DataBlock | 多模态:图片/音频/视频(base64 或 URL) | USER / ASSISTANT | | ThinkingBlock | 模型的思维链(推理过程) | ASSISTANT | | ToolUseBlock | 一次工具调用(id / name / input / state) | ASSISTANT | | ToolResultBlock | 工具执行结果 | ASSISTANT | | HintBlock | 以"用户上下文"形式注入循环的指令 | ASSISTANT |

角色约束在构造时就强制生效:USER 只允许文本/数据/媒体块,SYSTEM 只允许 TextBlock,ASSISTANT 则全部允许。

3.3 角色固定子类(2.0 推荐写法)

2.0 推荐直接用按角色固定的子类,而不是通用的 Msg.builder():

java 复制代码
import io.agentscope.core.message.UserMessage;
import io.agentscope.core.message.SystemMessage;
import io.agentscope.core.message.AssistantMessage;
 
// 便捷构造:普通字符串会自动包成 TextBlock
UserMessage userMsg  = new UserMessage("你好,请介绍一下自己");
SystemMessage sysMsg = new SystemMessage("system", "你是一个乐于助人的助手。");
AssistantMessage asstMsg = new AssistantMessage("agent", "好的,我是......");
 
// 读取内容
String text = userMsg.getTextContent();   // 所有 TextBlock 用 \n 拼接

多模态也不复杂,直接往里塞 DataBlock 即可:

bash 复制代码
UserMessage multi = new UserMessage(
        "user",
        TextBlock.builder().text("描述这张图:").build(),
        DataBlock.builder()
                .source(Base64Source.builder()
                        .data("...base64...")
                        .mediaType("image/png")
                        .build())
                .build());

小贴士:2.0 用 DataBlock 统一替代了旧的 ImageBlock/AudioBlock/VideoBlock,新代码建议直接用 DataBlock。


四、Model:Agent 的"大脑"

Model 负责真正的推理与生成。AgentScope 用 Model 接口(各厂商聊天模型继承 ChatModelBase 抽象类)把各家大模型 API 的差异屏蔽掉,让你写业务时不用关心"这是通义千问还是 OpenAI"。

4.1 2.0 新写法:字符串模型

2.0 引入了最省事的写法------字符串模型,由 ModelRegistry 解析并自动读取对应的 API Key(如 DASHSCOPE_API_KEY):

php 复制代码
.model("dashscope:qwen-plus")   // qwen-max / qwen-turbo 同理

4.2 需要精细控制时:传 Model 实例

字符串只能跑默认配置。如果你的场景需要指定温度、超时、代理等,2.0 仍然支持直接传 Model 实例(例如 DashScopeChatModel.builder()...build())------.model()既收字符串、也收Model实例,这点不要被"字符串写法"误导。

4.3 Formatter:你不用关心的适配层

不同厂商的 API 格式天差地别,AgentScope 用 Formatter 在内部自动转换消息格式(DashScopeChatFormatter、OpenAIChatFormatter、AnthropicChatFormatter、GeminiChatFormatter......)。通常你不用手动配,框架按 Model 类型自动选。

一句话:2.0 里"换模型" ≈ 改一个字符串前缀(dashscope: / deepseek: / openai:),前提是装了对应的 agentscope-extensions-model-* 扩展包。


五、ReAct 循环:Agent 到底怎么"思考"

这是整个框架的发动机,也是理解一切能力的前提。

ReAct = Reasoning(推理)+ Acting(行动)。它不像传统"写死的流程图"那样一步步走,而是让模型动态决策:这一步是该直接回答,还是该先调个工具拿数据再说。

一次 call 的典型循环:

sql 复制代码
flowchart TD
    Start([用户消息]) --> Think[Reasoning:模型推理]
    Think --> Decide{需要调用工具?}
    Decide -->|否| Answer([最终回复 / MODEL_STOP])
    Decide -->|是| Action[Acting:执行 Tool]
    Action --> Observe[Observation:拿到工具结果]
    Observe --> Think

用"查天气"举个具体例子:

Reasoning(思考):用户问"北京今天天气?"→ 模型判断:我得先查天气,不能直接编。

Acting(行动):调用 get_weather(city="北京")。

Observation(观察):工具返回"北京:晴,25℃"。

Reasoning 再思考:信息齐了,可以作答。

最终回复:"北京今天晴,25℃,注意防晒。"

如果信息还不够,模型会带着新观察再走一轮循环------这就是"自主规划、动态决策",也是它比刚性工作流强的地方。

每轮 call 结束时,框架会给出一个 GenerateReason(终止原因),常见的有:MODEL_STOP(正常答完)、TOOL_SUSPENDED(工具执行被挂起,常见于需要人工确认)、MAX_ITERATIONS(到达最大循环次数)、INTERRUPTED 等。生产代码一定要处理这些状态,别默认"每次都能拿到正常回答"。


六、透明开发:用 Middleware 窥探 ReAct 全过程

企业落地的老大难是:Agent "黑盒决策",出了错查不到为什么。AgentScope 的解法是Middleware(中间件)体系------在 Agent 生命周期的 5 个关键执行点挂上你自己的逻辑(日志、监控、改消息、改系统提示词),把推理全过程"摊开"给你看。

2.0 的 MiddlewareBase 接口暴露了 5 个钩子("洋葱模型",before/after 包裹执行):

| 钩子 | 拦截点 | 常用场景 | | --- | --- | --- | | onAgent | 整个 Agent 调用 | 入口日志、鉴权 | | onReasoning | 推理 / 模型调用阶段 | 打印推理文本、耗时 | | onActing | 单次工具调用执行 | 打印工具入参 / 结果 | | onModelCall | 原始模型 API 调用 | 改请求、归一化输出 | | onSystemPrompt | 系统提示词(管道式) | 动态注入上下文 |

旧版 Hook 接口自 2.0.0 起已标记 @Deprecated(forRemoval = true),官方推荐统一改用 Middleware。

来看一个"调试中间件",把推理流式文本和工具调用实时打印出来------这就是"透明开发"最直观的体现:

typescript 复制代码
import io.agentscope.core.middleware.MiddlewareBase;
import io.agentscope.core.middleware.ReasoningInput;
import io.agentscope.core.middleware.ActingInput;
import io.agentscope.core.agent.Agent;
import io.agentscope.core.agent.RuntimeContext;
import io.agentscope.core.event.AgentEvent;
import io.agentscope.core.event.TextBlockDeltaEvent;
import io.agentscope.core.event.ToolResultEndEvent;
import java.util.function.Function;
import reactor.core.publisher.Flux;
 
MiddlewareBase debugMiddleware = new MiddlewareBase() {
    @Override
    public Flux onReasoning(
            Agent agent, RuntimeContext ctx, ReasoningInput input,
            Function> next) {
        System.out.println("\n[思考] Agent 开始推理 (session=" + ctx.getSessionId() + ")");
        return next.apply(input)
                .doOnNext(event -> {
                    if (event instanceof TextBlockDeltaEvent e) {
                        System.out.print(e.getDelta());      // 推理流式文本增量
                    }
                })
                .doOnComplete(() -> System.out.println("\n[思考] 推理结束"));
    }
 
    @Override
    public Flux onActing(
            Agent agent, RuntimeContext ctx, ActingInput input,
            Function> next) {
        input.toolCalls().forEach(tc ->
                System.out.println("[行动] 执行工具 → " + tc.getName()));
        return next.apply(input)
                .doOnNext(event -> {
                    if (event instanceof ToolResultEndEvent e) {
                        System.out.println("[行动] 工具 " + e.getToolCallName()
                                + " 结果状态=" + e.getState());
                    }
                });
    }
};
 
// 挂到 Agent 上(HarnessAgent / ReActAgent 通用)
HarnessAgent agent = HarnessAgent.builder()
        .name("assistant")
        .sysPrompt("你是一个有用的 AI 助手。")
        .model("dashscope:qwen-plus")
        .workspace(Paths.get(".agentscope/workspace"))
        .middleware(debugMiddleware)   // 2.0 推荐:用 Middleware 而非已弃用的 Hook
        .build();

中间件的返回值走 Project Reactor(Flux<AgentEvent> / Mono<String>),生产里你完全可以把这些事件推到 OpenTelemetry 或 AgentScope Studio 做可视化调试------更完整的可观测能力我们放到"生产篇"再展开。


七、新手最常误解的 5 个点

把Msg当成"一句话"------ 它是完整的"一轮对话",一条 assistant 消息可能内含多轮推理+工具调用。

还在用Msg.builder()通用写法------ 2.0 推荐角色固定子类(UserMessage/AssistantMessage/SystemMessage/ToolResultMessage),约束更清晰、不易写错。

以为.model()只认字符串------ 它也能收 ChatModel 实例,需要精细配置温度/超时/代理时用后者。

非 DashScope 模型却没装扩展包------ dashscope: 适配器也要单独引 agentscope-extensions-model-dashscope,并非 harness 内置;换 DeepSeek / OpenAI 等同样要补对应的 agentscope-extensions-model-*。

忽视GenerateReason------ 别假设每次都 MODEL_STOP;TOOL_SUSPENDED、MAX_ITERATIONS 等中断状态要在业务里妥善处理。


小结

这一篇你建立起了 AgentScope Java 2.0 的心智模型:

Agent分两层:ReActAgent(推理核心)与 HarnessAgent(工程外壳,2.0 推荐);

Message是结构化对话轮次,由带类型的 ContentBlock 组成,2.0 推荐角色固定子类;

Model是大脑,ChatModel 屏蔽厂商差异,2.0 用字符串 + ModelRegistry 极简接入;

ReAct 循环= 推理→行动→观察 的不断迭代,支持动态决策与自主规划;

透明开发靠 Middleware 把推理全过程"摊开"给你看,这是企业落地可控性的关键。

理解这四块,后面所有能力------工具、记忆、RAG、多 Agent------本质上都是"给 Agent 接更多 Message 来源 / 更多 Model 能力 / 更丰富的循环分支"。

下一篇,我们就从最实用的一块切入:让 Agent 真正"动手"------Tool Calling 工具调用实战。你会看到 ReAct 循环里那个 "Acting" 步骤,是怎么被你自己的 Java 方法填满的。

下篇预告:《让 Agent 会"用工具":Tool Calling 实战》


本篇基于 AgentScope Java 2.0。API 与概念以官方文档(java.agentscope.io)最新 2.0.x 为准,建议结合对应版本动手实验。

相关推荐
liulilittle1 小时前
短期内不存在通用 AI 工作流魔法
大数据·开发语言·c++·人工智能·llm·agent·tools
BenedictHook2 小时前
技能商店 SkillHub:Windows端 AI Skill 管理工具,支持搜索、查看与安装
c++·agent·桌面应用·skill·windows开发·skillhub
方方洛2 小时前
ai-agent教程-03-大模型接口与工具调用
人工智能·llm·agent
深蓝AI2 小时前
说完才转写已经过时了:微软 MAI-Transcribe-2-Streaming 把流式转录延迟压到 0.13 秒
人工智能·agent
方方洛2 小时前
ai-agent教程-00-前言与导读
人工智能·llm·agent
方方洛2 小时前
ai-agent教程-01-认识AI-Agent
人工智能·llm·agent
方方洛2 小时前
ai-agent教程-02-核心原理与架构
人工智能·llm·agent
小盆女神节奶粉2 小时前
对LangGraph的invoke的一些理解
agent
方方洛2 小时前
ai-agent教程-04-记忆管理
人工智能·llm·agent