过去两年,大语言模型(LLM)技术飞速发展,从ChatGPT到各种专业领域模型,AI能力正以前所未有的速度重塑软件开发。作为企业级后端的中流砥柱,Java开发者自然需要思考:如何将AI能力无缝集成到现有的Java系统中?
然而,传统的AI集成方式往往面临以下挑战:
- 调用复杂:直接调用大模型API需要手动构建HTTP请求、处理JSON、管理密钥,代码冗长且易出错。
- 缺乏智能体抽象:简单的“请求-响应”模式无法满足多步推理、工具调用、多智能体协作等复杂需求。
- 与Java生态割裂:Python生态有丰富的AI框架(如LangChain),但Java开发者需要一套能融入Spring生态的解决方案。
AgentScope Java的出现,正是为了解决这些问题。
AgentScope Java是阿里巴巴开源的智能体(Agent)开发框架,专为Java生态打造。它提供了一套完整的工具和抽象,让Java开发者能够:
- 用最熟悉的Java代码构建智能体应用
- 轻松集成通义千问、OpenAI等大模型
- 让智能体调用外部工具(如查询天气、操作数据库)
- 编排多智能体协作完成复杂任务
- 在生产环境可靠部署,具备可观测性和沙箱安全
简单来说,AgentScope Java = Java + 大模型 + 智能体 + 工具,让Java开发者像写普通业务代码一样开发AI应用。
让我们先看一段最原始的Java代码,它使用调用大模型API:
这段代码的问题显而易见:
- 硬编码API地址和密钥
- JSON构造和解析繁琐
- 没有错误处理、重试机制
- 难以扩展(如增加多轮对话、工具调用)
现在,看看AgentScope Java如何简化这一切:
短短几行代码,实现了相同功能,且无需处理任何HTTP细节。这还只是开始——AgentScope Java的真正威力在于智能体的自主决策、工具调用和多智能体协作。
下图展示了AgentScope Java的核心组件及其关系:
如果你是一名Java开发者,从未接触过大模型开发,不用担心。本文将带你从零开始,一步一步亲手实践AgentScope Java的所有核心组件。你将学到:
- 基础篇:搭建第一个智能体、配置模型、处理对话
- 工具篇:让智能体调用你的Java方法(函数调用)
- 多智能体篇:构建多个智能体协作完成复杂任务
- 记忆篇:让智能体记住对话历史和用户偏好
- ReAct篇:实现思考-行动-观察循环,应对复杂问题
- 工作流篇:编排结构化多Agent流程
- 部署篇:将智能体发布为服务,安全运行
- 监控篇:使用Studio可视化调试和评估
- 高级篇:多模态、长期记忆(ReMe)等前沿特性
在开始动手之前,我们先确保你的开发环境就绪。本章将带领你完成从零到第一个可运行智能体应用的全过程,全程只需5分钟。
- JDK 17 或更高版本(AgentScope Java 基于 Spring Boot 3.x,要求 JDK 17+)
- Maven(3.6+)或 Gradle(7.x+)—— 任选一种你熟悉的构建工具
- IDE:IntelliJ IDEA、Eclipse 或 VS Code(Java插件)
- 网络连接:能够访问阿里云DashScope API(国内网络一般没问题)
如果你还没有安装 JDK 或 Maven/Gradle,请先自行安装。这里不再赘述。
AgentScope Java 提供了 Spring Boot Starter,可以轻松集成到你的 Spring Boot 应用中。我们将创建一个标准的 Spring Boot 项目,并添加必要的依赖。
2.2.1 使用 Spring Initializr 快速创建项目(推荐)
- 访问 start.spring.io/
- 选择以下选项:
- Project:Maven 或 Gradle(以 Maven 为例)
- Language:Java
- Spring Boot:选择 3.2.x 或更高版本(3.1+ 也可以,但建议 3.2)
- Group:
- Artifact:
- Dependencies:添加 Spring Web(因为我们后面可能需要提供 REST 接口)
- 点击 Generate 下载项目压缩包,解压后导入 IDE。
2.2.2 手动添加 AgentScope Java 依赖
由于 AgentScope Java 尚未发布到 Maven Central,需要添加阿里云仓库和官方仓库。在 中添加以下内容:
2.2.3 Gradle 配置(可选)
如果你使用 Gradle,在 中添加:
AgentScope Java 需要调用大模型 API 来驱动智能体。本教程以阿里云通义千问(DashScope)为例,你也可以使用 OpenAI、Ollama 等,只需更换依赖和配置。
2.3.1 开通阿里云 DashScope 服务
- 访问 阿里云百炼平台(需登录阿里云账号)。
- 如果首次使用,点击“立即开通”,同意服务协议。
- 开通后,在控制台左侧导航栏选择 API-KEY 管理。
2.3.2 创建 API Key
- 点击“创建 API-KEY”,输入名称(如“我的智能体应用”)。
- 生成后,复制密钥字符串(格式如 )。
- 注意:请妥善保管 API Key,不要泄露。
2.3.3 配置 API Key
在 中配置:
为了安全,强烈建议使用环境变量:
- Linux/Mac:在 或 中添加 ,然后执行 。
- Windows:在系统环境变量中添加 。
如果你只是快速测试,可以临时在配置文件中写死,但切记不要提交到代码仓库。
2.3.4 可选:配置其他模型参数
现在我们来创建一个最简单的智能体,让它回答你的问题。
2.4.1 创建智能体类
在 包下创建 :
代码解释:
- 是 AgentScope 提供的基类,我们通过继承它来创建自己的智能体。
- 构造器接收 (由自动配置创建),并传给父类。
- 方法可选,用于设定系统消息,告诉智能体它的角色。
2.4.2 创建 REST 接口调用智能体
创建 :
2.4.3 启动类
确保项目有标准的 Spring Boot 启动类(Initializr 会自动生成):
2.4.4 运行测试
- 启动应用(运行 的 方法)。
- 打开浏览器或使用 curl 访问:
- 你将看到类似如下的响应:
完整流程示意图:
2.4.5 可能遇到的问题及解决
通过本章的学习,你成功搭建了第一个 AgentScope Java 应用,并实现了一个简单的智能体聊天接口。你学会了:
- 使用 Spring Initializr 创建 Spring Boot 项目,并手动添加 AgentScope 依赖。
- 在阿里云百炼平台获取 API Key,并配置到项目中。
- 编写自定义智能体类,继承 并设定系统消息。
- 创建 REST 控制器,注入智能体并调用 方法。
- 运行并测试第一个智能体接口。
在上一章中,我们创建了一个简单的智能体并让它回答了问题。但你可能会好奇:这个智能体内部是如何工作的?它如何理解我的问题?又如何与大模型交互?本章将深入AgentScope Java的三个核心抽象:Agent(智能体)、LLM(大语言模型)和Message(消息)。掌握了这些,你就能像搭积木一样构建各种复杂的智能体应用。
3.1.1 Agent接口:所有智能体的根接口
在AgentScope Java中,所有的智能体都实现了 接口。这个接口定义了智能体的基本行为:
我们之前使用的 就是这个接口的一个实现类,它封装了与大模型交互的通用逻辑。你可以通过继承 快速创建自己的智能体,就像我们在第二章做的那样。
Agent的内部工作流程(简化版):
- 接收用户输入(方法被调用)
- 将输入和系统提示词(如果有)组合成消息列表
- 调用大模型(LLM)获取回复
- 返回回复文本
3.1.2 LLM基座:ChatClient抽象
是AgentScope Java中所有大模型客户端的统一接口。它的作用是屏蔽不同模型提供商的API差异,让你可以用相同的方式调用通义千问、OpenAI、Ollama等模型。
AgentScope Java内置了多种实现:
- :调用阿里云通义千问
- :调用OpenAI(包括兼容接口的服务,如DeepSeek)
- :调用本地Ollama模型
- :调用Azure OpenAI
你可以通过配置文件或代码选择使用哪一个,而你的智能体代码完全不需要修改——这就是抽象的力量。
3.1.3 Message:智能体间通信的标准格式
在多智能体系统中,智能体之间需要交换信息。 类就是用来封装这些信息的标准格式。即使是单智能体,内部也是用消息列表与大模型交互的。
一个 包含以下关键属性:
例如,一个典型的对话历史可以表示为消息列表:
当智能体调用大模型时,它会将这个列表发送给 ,模型根据整个对话历史生成回复。
三种核心消息的类图:
在第二章中,我们通过 配置了LLM客户端。AgentScope的自动配置会根据 的值创建对应的 Bean。让我们更详细地了解各种配置方式。
3.2.1 通过配置文件(推荐)
在 中,你可以配置多种模型提供商:
通义千问(DashScope):
OpenAI:
Ollama(本地模型):
3.2.2 在代码中手动创建LLM实例
如果你不想使用自动配置,也可以手动创建 实例。这在需要动态切换模型或进行单元测试时很有用。
3.2.3 高级参数说明
在第二章中,我们简单地继承了 并重写了 。现在,让我们更深入地了解 的工作原理,并学习如何自定义它的行为。
3.3.1 BaseAgent的核心方法
类提供了几个可以重写的方法,让你可以定制智能体的行为:
最重要的方法是 ,它内部调用了上述方法:
3.3.2 实现自定义Agent:记录对话历史
默认的 是无状态的——它不记得之前的对话。下面我们创建一个能记住对话历史的智能体。这需要用到 的概念,我们将在第六章深入,这里先简单演示。
现在,当我们连续调用这个智能体时,它会记住之前的对话内容。
3.3.3 测试记忆Agent
创建一个新的控制器方法:
测试两轮对话:
- 访问
- 再访问
- 如果智能体回答“你叫小明”,说明记忆功能生效了。
现在,让我们综合运用本章所学,构建一个更实用的问答助手。这个助手将:
- 使用通义千问 模型
- 具备基本的角色设定(Java编程导师)
- 能够记录对话历史(可选)
3.4.1 创建智能体类
3.4.2 创建控制器
3.4.3 测试
启动应用,访问以下URL测试:
你会看到智能体以导师的口吻回答,并附带代码示例。
3.4.4 完整调用流程图
通过本章的学习,你掌握了AgentScope Java的三个核心抽象:
- Agent:智能体的基本单元,通过继承 可以快速创建自定义智能体。
- LLM:通过 统一接口,轻松切换不同的模型提供商。
- Message:标准化的消息格式,用于与LLM交互和多智能体通信。
你还学会了:
- 通过配置文件或代码创建LLM客户端。
- 重写 的方法来自定义智能体行为。
- 构建一个带简单记忆的智能体。
- 实践了一个Java导师问答助手。
在前面的章节中,我们的智能体只能“说话”——基于训练数据回答问题。但如果用户问“现在几点了?”、“帮我查一下订单状态”、“今天天气怎么样”,纯文本模型是无法直接获取这些实时信息的——它没有时钟,也无法访问你的数据库。
工具调用(Tool Calling) 正是为了解决这个问题而生。它允许智能体在需要时调用你编写的 Java 方法,获取实时数据或执行操作,然后将结果整合到回答中。本章将带你掌握 AgentScope Java 的工具调用机制,让你的智能体真正“动手做事”。
工具调用的核心思想是:你提供一组工具(Java 方法),并告诉智能体这些工具的存在、用途以及参数。当智能体认为需要某个工具来回答问题时,它会返回一个特殊的请求,要求执行该工具并提供参数。AgentScope 会自动执行对应方法,并将结果返回给智能体,智能体再根据结果生成最终回答。
工作流程示意图:
在整个流程中,除了定义工具方法外,你几乎不需要额外代码。AgentScope 会自动处理工具调用的握手过程。
AgentScope Java 通过 注解来标记一个方法作为可被智能体调用的工具。你只需将工具类注册为 Spring Bean,框架会自动收集并提供给智能体。
4.2.1 引入依赖
工具调用功能已包含在 中,无需额外依赖。
4.2.2 定义第一个工具
创建一个 Spring 组件,其中的方法用 注解标记。 注解需要指定工具的名称和描述,描述会被传递给模型,帮助模型理解何时调用该工具。
说明:
- :工具名称,建议使用驼峰命名,如 。
- :工具描述,非常重要!智能体会根据描述判断何时调用该工具。描述越清晰,调用准确率越高。
4.2.3 带参数的工具
很多工具需要参数。例如,查询天气需要城市名,查询订单需要订单号。工具方法可以定义参数,智能体在调用时会自动提取参数值。
4.2.4 参数描述的重要性
为了让智能体更准确地填充参数,可以在 注解中通过 属性提供更详细的参数描述。AgentScope Java 支持从方法参数名和 注解中提取说明。
注意: 注解的 会被传递给模型,帮助模型理解参数的含义。
在 AgentScope 中,有两种方式将工具绑定到智能体:自动绑定(通过 Spring 容器)和手动绑定(在创建智能体时指定)。
4.3.1 自动绑定(推荐)
只要你的工具类是一个 Spring Bean(如 、 等),并且你的智能体继承自 ,AgentScope 的自动配置就会将这些工具收集起来,并在智能体需要时自动提供。你不需要在代码中显式绑定。
4.3.2 手动绑定
如果你希望某些工具只在特定智能体中使用,可以在创建智能体时通过 手动注册。这需要你自定义智能体的构造逻辑。
但通常自动绑定更简单,我们采用自动绑定即可。
现在让我们构建一个完整的示例,包含两个工具:获取时间和查询天气。我们将创建一个 REST 接口,用户输入问题,智能体自动决定是否调用工具。
4.4.1 定义工具类
4.4.2 定义智能体
4.4.3 创建 Controller
4.4.4 测试
启动应用,用浏览器或 curl 测试:
4.4.5 观察日志
在控制台,你可能会看到类似以下的日志,表示智能体调用了工具:
4.5.1 工具方法应该是线程安全的
工具类通常是单例 Bean,因此方法需要是线程安全的。上面的例子中, 是纯函数,安全; 也是只读操作,安全。如果工具修改了共享状态(如计数器),需要考虑同步。
4.5.2 工具方法的执行时间
工具方法执行时间不宜过长,因为整个调用是同步的(智能体在等待工具结果)。如果工具需要调用外部 API 或数据库,考虑设置超时,或采用异步方式(但 AgentScope 目前主要支持同步工具调用)。
4.5.3 错误处理
工具方法可能抛出异常。AgentScope 会捕获异常并将错误信息返回给智能体。智能体会根据错误信息决定如何回应(例如提示用户稍后重试)。你可以在工具方法内部处理异常,返回友好的错误消息。
4.5.4 工具数量
不要注册过多无关的工具,因为工具描述会消耗 Token,且可能让智能体混淆。只注册必要且描述清晰的工具。
4.5.5 参数类型
工具方法的参数支持基本类型、String、复杂对象等,但智能体需要能够生成对应的 JSON。建议使用简单类型,并配合清晰描述。对于复杂对象,需要确保模型能理解其结构。
4.5.6 通义千问的特殊性
通义千问模型对工具调用的支持与 OpenAI 类似,但细节可能略有不同。AgentScope Java 已经做了适配,开发者无需关心底层差异。
为了更深入理解,我们来看一下工具调用在 AgentScope Java 中的详细流程:
- 用户请求:用户发送问题
- 构建请求:智能体将用户消息和可用工具列表(由 提供)一起封装成请求,发送给大模型。
- 模型决策:模型判断需要调用 工具,并生成参数 。
- 工具执行:AgentScope 接收到模型返回的工具调用请求,查找对应的 Bean 方法,通过反射调用 。
- 结果返回:工具执行结果("多云,28℃")被封装成新的消息(工具消息)再次发送给模型。
- 生成最终回答:模型结合工具结果和原始问题,生成最终回答:“上海今天多云,28℃。”
- 响应客户端:最终回答返回给用户。
流程图:
现在,请你自己尝试添加一个新工具,比如一个简单的计算器,能够计算两个数字的和、差、积、商。
4.7.1 定义计算器工具
4.7.2 测试
访问 ,智能体应该会调用计算器工具并返回结果。
通过本章的学习,你掌握了:
- 工具调用的概念:让智能体调用外部方法获取实时信息或执行操作。
- 定义工具:使用 注解标记方法,并用 描述参数。
- 工具注册:AgentScope 自动收集所有带 的 Spring Bean,无需手动配置。
- 实践:构建了能查询时间和天气的智能助手,并扩展了计算器工具。
- 注意事项:线程安全、错误处理、参数描述等。
在前面的章节中,我们一直和单个智能体打交道。单个智能体可以完成不少任务,但当面对更复杂、需要多种专业能力的场景时,单打独斗就显得力不从心了。比如,规划一次旅行,需要查天气、查酒店、规划路线、预订门票……如果让一个智能体包揽所有,它可能会手忙脚乱,而且代码会变得异常臃肿。
多智能体协作正是为了解决这类问题:将复杂任务拆解,由多个各有所长的智能体分工合作,像人类团队一样高效协同。AgentScope Java 提供了强大的多智能体通信机制,让你能轻松构建这样的“智能体团队”。
先来看一个现实场景:用户说“我想去北京旅游3天,帮我规划一下”。这个任务其实包含多个子任务:
- 了解北京近期的天气(需要天气查询能力)
- 查找合适的酒店(需要酒店查询能力)
- 制定每日行程(需要景点推荐和路线规划能力)
如果用一个智能体完成所有事情,意味着它要同时具备天气查询、酒店查询、景点知识等多种能力,并且要自己拆解任务、按顺序执行。这不仅对模型要求高,而且代码耦合度极高,难以维护和扩展。
使用多智能体系统,我们可以这样分工:
- 主管智能体:接收用户请求,拆解任务,协调其他智能体工作,汇总结果。
- 天气智能体:专门负责查询天气。
- 酒店智能体:专门负责查询酒店信息。
- 行程智能体:专门负责规划行程。
每个智能体各司其职,代码清晰,易于扩展(比如增加机票查询智能体),而且可以复用(天气智能体也能用于其他场景)。
要让智能体们协同工作,它们之间必须能“交流”。AgentScope Java 提供了 MessageHub(消息总线)作为智能体间通信的中枢。
5.2.1 MessageHub:全局消息总线
是一个全局的消息中心,所有智能体都可以通过它发送和接收消息。你可以把它想象成一个聊天群组:智能体可以向群组广播消息,也可以私聊某个特定智能体。
核心概念:
- 消息(Message):智能体间传递的信息单元,包含发送者、接收者、内容等。
- 发送:智能体调用 将消息放入总线。
- 接收:智能体可以通过轮询或监听的方式从总线获取发给自己的消息。
为了简化,我们可以在智能体内部维护一个收件箱,每次处理完一条消息后,从 拉取下一条消息。
5.2.2 消息类型:广播与点对点
AgentScope 的消息支持两种路由方式:
- 广播(Broadcast):消息的接收者为 或特殊标识,表示所有智能体都能收到。适合发布公告、任务通知等。
- 点对点(P2P):指定接收者的名称,只有该智能体能收到。适合任务分配、结果返回。
5.2.3 在智能体中使用 MessageHub
要让智能体具备通信能力,我们只需在智能体类中注入 的 Bean,然后调用它的方法。下面是一个简单的例子:
实际使用时,我们通常会让智能体在一个循环中不断处理消息,类似于:
但为了与现有的 模型兼容,我们可以设计一种任务驱动的方式:当用户请求到达时,主管智能体开始协调,而工人智能体则被动响应。这样我们不需要独立的消息循环,而是让 方法在需要时触发消息处理。
让我们通过一个简单的示例来感受多智能体协作:用户问“上海的天气怎么样?”,主管智能体将问题转给天气智能体,获取结果后返回。
5.3.1 定义消息类
为了区分不同类型的消息,我们可以定义一个简单的 类,包含任务类型和内容。但为了保持简单,我们直接使用 AgentScope 的 类,并在内容中放入任务信息。
5.3.2 定义天气智能体
天气智能体专门处理天气查询。它从消息中提取城市,调用天气工具(上一章已定义),然后回复结果。
5.3.3 定义主管智能体
主管智能体接收用户输入,然后根据需要向天气智能体发送消息,并等待回复。
5.3.4 注册智能体为 Bean
确保所有智能体都被 Spring 管理,加上 注解。
5.3.5 创建控制器
修改之前的 ,注入主管智能体:
5.3.6 测试
启动应用,访问 ,应该能正确返回天气信息。
多智能体协作流程图:
现在,我们来构建一个更实用的系统:旅游规划助手。它将包含三个专业智能体:天气智能体、酒店智能体和行程智能体,由一个主管智能体协调。
5.4.1 定义工具类
我们需要酒店查询工具和景点推荐工具(用于行程规划)。为简化,我们使用模拟数据。
5.4.2 定义三个工人智能体
天气智能体(复用之前的 ,但改为通过消息处理)。为了代码整洁,我们创建一个基类 封装消息处理逻辑。
然后实现三个工人智能体:
5.4.3 定义主管智能体
主管智能体接收用户请求,解析城市和任务类型,然后并发地向各工人智能体发送任务,收集结果后汇总。
5.4.4 触发工人处理消息
为了让工人智能体能及时处理消息,我们需要在适当的时候调用它们的 方法。简单的方式是在每个工人智能体中添加一个 定时任务,定期处理消息。或者,我们可以在主管发送消息后,手动调用工人的处理方法(但这样耦合度高)。这里采用定时任务方式,简单有效。
在 Spring Boot 主类上启用定时任务:
然后在每个工人智能体中添加定时方法:
同样为 HotelWorker 和 ItineraryWorker 添加定时方法。
5.4.5 创建控制器
5.4.6 测试
启动应用,访问:,会返回类似:
5.4.7 多智能体协作流程图(完整)
通过本章的学习,你掌握了多智能体协作的核心技术:
- 多智能体的价值:将复杂任务拆解,由专业智能体分工合作,提高系统可维护性和扩展性。
- MessageHub 通信机制:利用全局消息总线实现智能体间的松耦合通信。
- 广播与点对点:了解消息的两种路由方式。
- 实践:构建了旅游规划多智能体系统,包含天气、酒店、行程三个专业智能体,由主管智能体统一协调。
在前面的章节中,我们构建的智能体虽然能够回答问题,但它们都是无状态的——每次对话都是全新的开始,完全不记得之前说过什么。这就像和一个每次都忘记你是谁的朋友聊天,体验可想而知。要让智能体真正智能、个性化,它必须拥有记忆:记住用户的偏好、之前的对话内容,甚至从过往交互中学习。
本章将深入探讨 AgentScope Java 的记忆管理机制,让你能够为智能体添加短期和长期记忆,让它们成为用户的“老朋友”。
6.1.1 多轮对话中的上下文保持
想象一下这样的对话:
如果没有记忆,智能体在最后一轮就无法知道用户之前提到过喜欢篮球。有了记忆,智能体可以回顾历史,给出正确答案:“你之前说过喜欢打篮球。”
6.1.2 用户偏好和个性化
记忆可以让智能体记住用户的个性化信息,如:
- 语言偏好(“我喜欢用英文回答”)
- 常用地点(“我住在上海”)
- 特殊要求(“回答要简洁”)
这样,智能体可以逐渐适应每个用户的独特风格,提供更贴心的服务。
6.1.3 长期学习和经验积累
更高级的记忆可以让智能体从过去的交互中学习。例如,用户经常询问 Java 编程问题,智能体可以自动调整回答风格,提供更多代码示例。这种学习通常需要结合长期记忆存储。
AgentScope Java 提供了一个统一的 接口,用于抽象各种记忆存储实现。该接口定义了记忆的基本操作:
任何记忆实现都需要实现这些方法。 是我们在第三章介绍过的消息类,包含角色和内容。
AgentScope Java 提供了几种内置的记忆实现,适用于不同场景。
6.3.1 ConversationMemory:简单的对话历史记忆
是最简单的实现,它将所有消息原封不动地存储在内存列表中。它无限增长,适合对话轮次不多的场景。
优点:简单直接,信息完整。
缺点:无限增长,当对话很长时,可能超出模型上下文窗口。
6.3.2 TokenWindowMemory:基于 Token 窗口的记忆
解决无限增长的问题。它维护一个固定大小的 Token 窗口,当总 Token 数超过限制时,自动丢弃最早的消息,确保上下文长度可控。它需要配合一个 来估算 Token 数。
优点:有效控制上下文长度,避免超出模型限制。
缺点:可能丢失早期重要信息。
6.3.3 SummaryMemory:定期总结压缩记忆
是一种更智能的记忆策略。它会定期(例如每 N 轮对话)调用大模型对之前的对话进行总结,将总结作为新的记忆存储,并丢弃原始对话细节。这样既保留了核心信息,又极大压缩了 Token 占用。
优点:高度压缩,保留关键信息,适合长期对话。
缺点:需要额外调用模型,可能增加成本和延迟。
要让智能体拥有记忆,我们需要在智能体内部持有一个 实例,并在构建消息列表时加入历史消息。AgentScope 的 已经预留了记忆接口,我们可以通过构造器传入或重写相关方法。
6.4.1 在创建智能体时指定 Memory
6.4.2 在配置中定义 Memory Bean
为了灵活切换记忆策略,我们可以将 定义为 Spring Bean:
然后在智能体中通过 注入即可。
现在让我们创建一个使用 的智能体,并测试它的记忆能力。
6.5.1 创建智能体类
6.5.2 创建控制器
6.5.3 测试
- 启动应用。
- 第一轮:
- 第二轮:
你会看到智能体在第二轮正确回答“你叫小明”。这说明智能体记住了之前的对话。
6.5.4 不同记忆策略的对比
你可以将配置中的 Bean 替换为 或 ,观察不同策略对长对话的影响。
目前的所有记忆实现都是内存存储,这意味着一旦应用重启,记忆就会丢失。在生产环境中,我们通常需要将记忆持久化到磁盘或数据库中,以便长期保存。
6.6.1 为什么需要持久化?
- 用户长期体验:用户希望智能体在多次访问后仍然记得自己的偏好。
- 跨会话记忆:比如电商客服,需要记住用户的历史订单和咨询记录。
- 系统恢复:应用重启后,记忆不丢失,无缝继续对话。
6.6.2 使用 Redis 实现持久化记忆
AgentScope Java 支持通过自定义 实现来对接 Redis。下面是一个简单的基于 Redis 的 实现(使用 Spring Data Redis):
首先,添加 Redis 依赖:
然后,实现 接口:
注意: 需要自己实现,可以使用 Jackson 或 Gson 将 与 JSON 互转。
6.6.3 在智能体中使用持久化记忆
由于每个用户应该有独立的记忆,我们需要在智能体中根据用户标识(如 sessionId)来创建不同的 实例。这可以通过在 方法中接收用户 ID 来实现,但 只接受一个字符串。一个常见的设计是:智能体内部持有一个 ,根据上下文动态提供记忆实例。
简化起见,我们可以在控制器层为每个用户创建独立的智能体实例,但这会消耗大量资源。更好的方式是在智能体内部维护一个 ,并在每次调用时根据 获取对应的记忆。这需要修改智能体接口,让它接收两个参数:用户 ID 和消息。
我们将在后续章节中探讨这种设计。目前,理解持久化的概念即可。
通过本章的学习,你掌握了:
- 记忆的重要性:上下文保持、个性化、长期学习。
- Memory 接口:AgentScope Java 统一的记忆抽象。
- 内置记忆实现:(完整历史)、(滑动窗口)、(总结压缩)。
- 为智能体添加记忆:在 中集成 Memory,重写 和 。
- 实践:构建了带记忆的聊天助手,测试多轮对话效果。
- 记忆持久化:了解为何需要持久化,以及如何用 Redis 实现。
在前面的章节中,我们已经学会了让智能体调用工具(第四章)和使用记忆(第六章)。但是,这些工具调用是单次的:智能体一次决策调用一个工具,得到结果后就直接回答。这种模式对于简单查询(如天气、时间)足够了,但对于需要多步推理、根据中间结果调整下一步行动的复杂任务,就显得力不从心。
ReAct 模式正是为了解决这类问题而生的。它让智能体进入一个“思考→行动→观察→再思考”的循环,像人类一样逐步推理,直到完成复杂任务。
ReAct 是 Reasoning + Acting 的缩写,由研究人员提出的一种让大模型通过交替进行“推理”和“行动”来解决复杂任务的范式。其核心思想是:智能体在执行任务时,不仅要生成行动(如调用工具),还要生成推理过程(思考下一步该做什么),并根据行动的结果(观察)调整后续推理。
一个典型例子:用户要求“写一段 Python 代码计算斐波那契数列,并运行它”。
- 思考1:我需要先写代码。
- 行动1:调用代码编写工具(或直接用模型生成)写代码。
- 观察1:代码已生成。
- 思考2:现在需要运行这段代码。
- 行动2:调用代码执行工具运行代码。
- 观察2:代码运行出错,提示“变量未定义”。
- 思考3:错误原因是变量名写错了,我需要修改代码。
- 行动3:调用代码修改工具修正代码。
- 观察3:代码运行成功,输出结果。
- 最终回答:向用户报告结果。
这个循环可以持续多轮,直到任务完成或达到最大尝试次数。
ReAct 循环示意图:
与普通工具调用相比,ReAct 的优势在于:
- 多步决策:可以根据中间结果调整计划。
- 自我纠错:遇到错误可以修正,而不是直接放弃。
- 透明可解释:可以看到智能体的思考过程,便于调试。
AgentScope Java 内置了 类,它继承自 ,并封装了 ReAct 循环的逻辑。你只需要做两件事:
- 提供工具集(通过 注解,与第四章相同)。
- 设置系统提示词,告诉智能体它的任务和可用工具。
7.2.1 ReActAgent 的核心方法
主要增加了以下关键配置:
- 最大迭代次数(maxIterations):防止无限循环,默认通常是 10。
- 工具管理器(ToolManager):与第四章相同,自动收集所有 Bean。
在构造 时,你需要传入 和最大迭代次数。
7.2.2 在 Spring 中定义 ReActAgent
由于 也是 Spring Bean,我们可以通过 或 来创建它。这里我们使用 方式,以便在创建时指定最大迭代次数。
首先,在配置类中定义 Bean:
注意:工具会自动被发现,不需要手动传入。因为 内部会使用 从 Spring 容器中收集所有带 的 Bean。
现在,我们来实现一个能写代码、运行代码、并根据错误修正代码的智能体。为了简化,我们模拟一个代码执行工具,它可以“运行”代码并返回结果或错误信息。
7.3.1 定义代码执行工具
创建一个工具类,包含一个方法模拟运行代码。这里我们不真的执行代码,而是模拟一些常见错误。
为了更真实,我们也可以加入简单的语法检测。这里只是演示目的。
7.3.2 创建 ReAct 智能体
我们已经在 中定义了 Bean。现在需要为它设置合适的系统提示词,指导它如何进行 ReAct 循环。系统提示词非常关键,它告诉智能体应该遵循的格式:思考、行动、观察。
通常,系统提示词会包含以下内容:
- 智能体的角色(代码助手)。
- 可用的工具列表(尽管框架会自动提供,但提示词中最好也说明)。
- ReAct 循环的格式示例,例如每次输出必须包含 和 或 。
由于 内部已经内置了默认的 ReAct 提示词模板,我们只需要简单设置系统消息即可。但为了定制,我们可以重写 方法。不过 本身不直接提供这个方法,我们需要通过 的 方法设置。
修改 :
7.3.3 创建控制器
7.3.4 测试
启动应用,访问:
观察控制台日志,你会看到智能体的思考过程,以及多轮调用 工具的尝试。最终返回的结果应该是成功后的回答。
预期输出(简化):
7.3.5 ReAct 循环详细流程
让我们用序列图展示一次典型的执行过程:
7.4.1 多工具协作
在 ReAct 循环中,智能体可以使用多个不同的工具,根据任务需要动态选择。例如,一个数据分析智能体可能先后使用“查询数据”、“生成图表”、“解释结果”等多个工具。
7.4.2 处理复杂错误
你可以让智能体在遇到错误时,不仅修正代码,还能根据错误类型调整策略。比如,如果是语法错误,可能只需要简单修改;如果是逻辑错误,可能需要重新设计算法。
7.4.3 人机交互(Human-in-the-loop)
在某些关键步骤,可以让智能体暂停并向用户请求确认。虽然 目前不直接支持,但可以通过自定义工具实现:工具可以返回一个需要用户输入的标记,智能体看到这个标记后输出问题,等待用户响应(可以通过外部机制实现)。
- 迭代次数限制:务必设置合理的 ,防止智能体陷入无限循环(例如工具总是返回错误,导致不断重试)。生产环境中可设置为 10 或 20。
- 提示词设计:ReAct 模式高度依赖提示词的质量。系统提示词必须清晰地说明格式要求,并给出示例。如果智能体不按照格式输出(例如缺少 ),框架可能无法解析。
- 工具返回格式:工具返回的结果应该清晰易懂,便于智能体理解。例如,返回 JSON 格式或带有明确错误码的文本。
- 性能考虑:每轮循环都会调用一次大模型,多次循环会增加延迟和 Token 消耗。对于实时性要求高的场景,应尽量减少不必要的循环。
通过本章的学习,你掌握了 ReAct 模式的精髓:
- ReAct 模式:让智能体在思考、行动、观察之间循环,解决多步复杂任务。
- ReActAgent 使用:通过 创建,设置系统提示词和最大迭代次数。
- 实践:构建了一个能自我纠错的代码助手,它可以根据运行错误修改代码,直到成功。
- 流程可视化:用序列图展示了 ReAct 循环的详细步骤。
ReAct 模式是构建强大智能体的关键。现在,你的智能体不仅会调用工具,还能自主地多步推理和纠错,应对更开放、更复杂的任务。
在前几章中,我们学习了多智能体协作(第五章),让智能体们通过消息总线自由交流。这种模式灵活,但有时我们需要更确定的流程——比如客服系统中的“客户问题→分类→分派→处理→回复”,每一步都必须按顺序执行,不允许智能体随意跳转。这种预定义、结构化的执行路径,就是工作流编排。
AgentScope Java 提供了强大的 Pipeline 机制,让你能以声明式的方式组合多个处理单元(可以是智能体、函数,甚至是另一个工作流),实现顺序、并行、条件分支等控制流。
工作流编排,简单说就是定义好一个流程,告诉系统先做什么、后做什么、哪些可以同时做、根据什么条件选择做什么。它与多智能体协作的区别在于:
两者并非互斥,可以结合使用:外层用工作流定义宏观流程,内层用多智能体协作处理复杂子任务。
AgentScope Java 的 包提供了以下核心接口和类:
- :所有工作流的顶级接口,定义了 方法。
- :顺序执行多个节点,前一个的输出作为下一个的输入。
- :并行执行多个节点,等待所有节点完成后,将所有结果合并返回。
- :根据条件选择执行某个分支节点。
每个节点可以是:
- :智能体,执行 方法。
- :嵌套子工作流,实现复用。
- 普通函数:通过 包装,执行任意 Java 代码。
顺序执行是最简单的流程。例如:先调用天气智能体,再将结果传给穿衣建议智能体。
8.3.1 定义节点
假设我们已经有两个智能体(或函数):
- :输入城市,返回天气。
- :输入天气描述,返回穿衣建议。
我们让它们顺序执行。
8.3.2 构建 SequentialPipeline
8.3.3 运行工作流
访问 ,工作流会:
- → 返回 "多云,28℃"
- → 返回 "建议穿短袖,带一件薄外套"
并行执行可以同时执行多个节点,提升效率。例如,在旅游规划中,同时查询天气、酒店、景点,然后汇总。
8.4.1 构建 ParallelPipeline
注意:并行节点的输入相同,都会收到原始输入(城市名)。它们的输出会被收集成一个列表,顺序与节点顺序一致。
8.4.2 处理并行结果
由于并行工作流的输出是一个 ,我们可以再通过一个 来汇总结果。
条件分支根据输入或中间结果,决定执行哪个节点。例如:如果用户问题包含“天气”,走天气查询路径;否则走默认路径。
8.5.1 构建条件分支
需要定义一个决策函数,返回要执行的节点名称。
现在,我们综合运用上述知识,构建一个智能客服系统。流程如下:
- 分类节点:根据用户问题,判断是“订单查询”、“产品咨询”还是“其他”。
- 分支路由:
- 订单查询 → 调用订单智能体
- 产品咨询 → 调用产品智能体
- 其他 → 调用通用智能体
- 汇总节点:将结果统一格式,返回给用户。
8.6.1 定义分类节点(用智能体实现分类)
创建一个 ,专门用于分类。
8.6.2 定义专业智能体
8.6.3 构建条件工作流
首先,分类节点的输出作为决策依据。我们创建一个决策函数,根据分类结果选择不同的专业智能体。
8.6.4 控制器
8.6.5 测试
- → 触发订单智能体。
- → 触发产品智能体。
- → 触发通用智能体。
8.6.6 工作流流程图
AgentScope 的 Pipeline 支持任意层级的嵌套,这意味着你可以构建非常复杂的流程。例如,在客服工作流中,订单智能体内部又可以是一个子工作流(先查物流、再查退换货政策)。这为实现模块化、复用提供了极大便利。
通过本章的学习,你掌握了:
- 工作流编排的概念及其与多智能体协作的区别。
- SequentialPipeline:顺序执行多个节点。
- ParallelPipeline:并行执行多个节点,提升效率。
- ConditionalPipeline:根据条件动态路由。
- 实践:构建了一个智能客服工作流,综合运用了顺序、条件和嵌套。
现在,你已经能够用工作流将多个智能体组装成可靠的业务流程,满足企业级应用的确定性要求。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/232439.html