九、AgentScope Runtime:部署与沙箱执行
在前面的章节中,我们一直在本地开发和测试智能体,通过 Spring Boot 的 Controller 暴露 HTTP 接口供外部调用。这种方式对于开发和演示足够了,但当我们想把智能体投入生产环境,面对真实用户的高并发请求时,就会遇到新的挑战:如何保证服务稳定、高效?如何防止恶意用户通过工具调用破坏系统?
AgentScope Runtime 正是为解决这些问题而生的。它是一个专为智能体设计的全栈运行时环境,核心目标是高效部署与服务 以及安全的沙箱执行。本章将带你学习如何使用 AgentScope Runtime 将智能体部署为可靠的服务,并配置沙箱来保护你的系统。
9.1 为什么需要专门的运行时?
9.1.1 部署挑战
想象一下,你的智能体被集成到电商网站的客服系统中,每天有成千上万用户访问。这时你会面临:
- 高并发:多个请求同时到达,你的智能体需要能并行处理,不能阻塞。
- 资源管理:每个请求都会调用大模型 API,如何控制并发度,避免超出 API 限流或导致内存溢出?
- 稳定性:某个请求如果导致智能体死循环(例如 ReAct 无限循环),不能影响其他请求。
9.1.2 安全挑战
智能体的一大优势是能调用工具执行操作。但工具是把双刃剑------如果被恶意利用,可能造成严重破坏。例如:
- 一个文件读取工具,如果被传入
../../etc/passwd,就可能读取系统敏感文件。 - 一个命令执行工具,如果被传入
rm -rf /,后果不堪设想。
因此,工具必须在受控的环境中执行,这就是**沙箱(Sandbox)**的作用。
9.1.3 AgentScope Runtime 的解决方案
AgentScope Runtime 提供了:
- 高效服务:内置请求队列、线程池、负载均衡,支持高并发。
- 智能体管理:可以同时部署多个智能体,通过名称路由。
- 安全沙箱:限制工具执行的权限,例如只能访问特定目录、禁止执行系统命令、限制网络请求等。
- 可观测性:输出指标(QPS、延迟、错误率)供监控系统(如下一章的 Studio)收集。
9.2 将智能体发布为 REST 服务
其实,我们在前面章节中通过 Spring Boot 和 @RestController 已经实现了智能体的 HTTP 服务。AgentScope Runtime 并没有推翻这种方式,而是在此基础上提供了更标准化的部署能力。通常,你仍然可以使用 Spring Boot 作为基础,然后集成 Runtime 的沙箱和监控功能。
9.2.1 回顾:最简单的 HTTP 服务
假设我们有一个智能体 WeatherAgent,我们通过 Controller 暴露:
java
@RestController
public class AgentController {
@Autowired
private WeatherAgent weatherAgent;
@PostMapping("/agent/weather")
public String chat(@RequestBody String query) {
return weatherAgent.run(query);
}
}
启动 Spring Boot 应用后,可以通过 HTTP POST 请求调用。
9.2.2 使用 AgentScope Runtime 管理智能体
AgentScope Runtime 提供了一个 AgentServer 类,可以统一管理多个智能体,并提供统一的 REST API。我们可以在 Spring Boot 启动时初始化它。
首先,引入 Runtime 依赖(假设已经包含在 agentscope-spring-boot-starter 中,但可能需要单独添加)。如果 starter 已包含则无需操作。
然后,创建一个配置类,注册智能体到 Runtime:
java
@Configuration
public class RuntimeConfig {
@Bean
public AgentServer agentServer(List<Agent> agents) {
AgentServer server = new AgentServer();
// 将所有 Spring 容器中的 Agent 注册到服务器
for (Agent agent : agents) {
server.registerAgent(agent.getName(), agent);
}
server.start(); // 启动服务器(非阻塞)
return server;
}
}
AgentServer 会启动一个内置的 HTTP 服务器(比如基于 Netty),提供统一入口:http://host:port/api/agent/{agentName}。这样,我们可以通过这个统一入口调用任何注册的智能体,而不需要为每个智能体编写 Controller。
9.2.3 配置文件定义智能体
除了代码注册,Runtime 还支持通过配置文件定义智能体。在 application.yml 中添加:
yaml
agentscope:
runtime:
agents:
- name: weather_agent
class: com.example.demo.agent.WeatherAgent
max-concurrent: 10
- name: travel_agent
class: com.example.demo.agent.TravelAgent
max-concurrent: 5
Runtime 会自动加载这些类并创建智能体实例,同时限制每个智能体的最大并发请求数。
9.3 沙箱执行机制
9.3.1 为什么需要沙箱?
沙箱是一种安全机制,它将工具的执行环境隔离在一个受限的"盒子"里,限制其对系统资源的访问。例如,我们可以允许工具读取 /data 目录下的文件,但不允许访问 /etc;允许进行 HTTP 请求,但不允许连接到内网 IP。
9.3.2 AgentScope 沙箱的工作原理
AgentScope 的沙箱通过 Java 的 SecurityManager 或自定义的类加载器、权限检查来实现。当工具方法被调用时,Runtime 会检查当前执行上下文是否在沙箱内,并应用预先配置的权限策略。
简化来说,沙箱会在调用工具方法之前,设置一个安全上下文,拦截危险操作。
9.3.3 配置沙箱权限
我们可以在 application.yml 中为每个工具或全局配置沙箱规则:
yaml
agentscope:
runtime:
sandbox:
enabled: true
default-policy: deny # 默认禁止所有
rules:
- tools: ["readFile"] # 对 readFile 工具生效
file:
allowed-paths: ["/data", "/tmp"]
read-only: true
- tools: ["executeCommand"]
enabled: false # 完全禁止 executeCommand 工具
- global: # 全局规则
network:
allowed-hosts: ["api.weather.com", "api.example.com"]
allow-private-ips: false
filesystem:
allowed-paths: ["/app/data"]
这些规则将在工具执行前进行校验,如果违反规则,工具调用会失败并抛出安全异常。
9.3.4 在工具代码中感知沙箱
工具开发者通常不需要关心沙箱,沙箱自动生效。但有时工具需要根据权限调整行为(例如,如果只允许读,则不能写)。可以通过 SandboxContext 获取当前权限信息,但这不是必须的。
9.4 实践:部署一个带沙箱的智能体服务
让我们通过一个例子来体验沙箱的作用。我们将创建一个带有"文件读取"工具的智能体,然后配置沙箱限制它只能读取特定目录。
9.4.1 定义文件读取工具
java
@Component
public class FileTool {
@Tool(name = "readFile", description = "读取指定路径的文件内容")
public String readFile(@Param(description = "文件路径") String path) throws IOException {
// 注意:这里没有安全检查,沙箱会拦截
return Files.readString(Path.of(path));
}
}
9.4.2 创建智能体
java
@Component
public class FileAgent extends BaseAgent {
public FileAgent(ChatClient chatClient) {
super("file_agent", chatClient);
}
@Override
protected String getSystemPrompt() {
return "你是一个文件助手,可以使用 readFile 工具读取文件。";
}
}
9.4.3 配置沙箱规则
在 application.yml 中启用沙箱,并设置规则:
yaml
agentscope:
runtime:
sandbox:
enabled: true
default-policy: deny
rules:
- tools: ["readFile"]
file:
allowed-paths: ["/tmp", "./data"] # 只允许读取 /tmp 和 ./data 目录
read-only: true
9.4.4 注册智能体到 Runtime
使用前面的 AgentServer 配置或通过配置文件注册。
9.4.5 测试
- 在
/tmp目录下创建一个测试文件test.txt,内容为 "Hello Sandbox"。 - 在项目根目录下创建
data/test.txt,内容为 "Project Data"。 - 启动应用。
- 调用智能体,让它读取
/tmp/test.txt:
bash
curl -X POST http://localhost:8080/api/agent/file_agent \
-H "Content-Type: application/json" \
-d '请帮我读取 /tmp/test.txt 的内容'
应该能成功返回内容。
- 尝试读取系统敏感文件,比如
/etc/passwd:
bash
curl -X POST http://localhost:8080/api/agent/file_agent \
-H "Content-Type: application/json" \
-d '请帮我读取 /etc/passwd'
这时,沙箱会拦截,智能体可能返回类似"权限不足,无法读取该文件"的错误信息。
9.4.6 沙箱工作流程
如果路径允许,沙箱放行,工具正常执行。
9.5 可观测性(Runtime 层面)
AgentScope Runtime 内置了指标收集功能,可以记录每个智能体的请求数、平均耗时、错误数等。这些指标可以通过 JMX 或 HTTP 端点暴露,供 Prometheus 等监控系统抓取。
在 application.yml 中开启:
yaml
agentscope:
runtime:
metrics:
enabled: true
endpoint: /metrics # 暴露指标的 HTTP 路径
访问 http://localhost:8080/metrics 可以看到类似:
ini
# HELP agentscope_requests_total Total requests per agent
# TYPE agentscope_requests_total counter
agentscope_requests_total{agent="file_agent",} 10.0
# HELP agentscope_request_duration_seconds Request duration per agent
# TYPE agentscope_request_duration_seconds histogram
agentscope_request_duration_seconds_bucket{agent="file_agent",le="0.1",} 5.0
...
这些指标可以与下一章的 AgentScope Studio 集成,实现可视化监控。
9.6 本章小结
通过本章的学习,你掌握了:
- AgentScope Runtime 的核心作用:高效部署 + 安全沙箱。
- 将智能体发布为服务 :使用 Runtime 的
AgentServer统一管理智能体,通过配置定义并发限制。 - 沙箱机制:为什么需要、如何配置权限规则,以及如何在工具执行时自动应用。
- 实践:部署了一个带文件读取工具的智能体,验证沙箱的访问限制。
- 可观测性:了解 Runtime 提供的指标端点,为监控做准备。
十、AgentScope Studio------可观测性与调试
在上一章中,我们学习了如何将智能体安全高效地部署为服务。但当智能体真正运行在生产环境中,我们如何了解它的内部状态?如何查看它每一步的思考过程?如果回答出错,如何追溯原因?可观测性 正是解决这些问题的关键,而 AgentScope Studio 提供了强大的可视化工具,让你能够像调试代码一样调试智能体。
本章将带你掌握 AgentScope Studio 的使用,包括集成方式、查看执行轨迹、评估智能体性能等。
10.1 为什么需要 Studio?
想象一下,你部署了一个复杂的 ReAct 智能体,它调用多个工具,经历多轮思考循环。某一天,用户投诉它给出了错误的答案。如果没有可观测性工具,你只能查看日志,面对大量混杂的文本,很难还原智能体当时的决策过程。
AgentScope Studio 可以:
- 可视化执行轨迹:以图形化的方式展示智能体的思考步骤、工具调用和观察结果。
- 实时调试:在开发环境中,你可以与智能体交互并实时查看它的思考链条。
- 评估智能体:通过测试集批量运行智能体,生成准确率、相关性等指标报告。
- 管理提示词:与 Nacos 集成,动态调整提示词并观察效果(需要结合配置中心)。
10.2 集成 Studio 到项目
AgentScope Studio 可以以两种方式使用:
- 嵌入模式:作为 Spring Boot 应用的一部分,在本地启动一个 Web 界面。
- 独立模式:部署独立的 Studio 服务,连接到你的智能体服务。
我们主要介绍嵌入模式,因为它简单易用,适合开发和测试。
10.2.1 引入依赖
在 pom.xml 中添加 Studio 依赖(如果尚未包含在 starter 中):
xml
<dependency>
<groupId>com.alibaba.agentscope</groupId>
<artifactId>agentscope-studio-spring-boot-starter</artifactId>
<version>${agentscope.version}</version>
</dependency>
10.2.2 配置文件
在 application.yml 中开启 Studio 并配置访问路径:
yaml
agentscope:
studio:
enabled: true
path: /studio # Studio UI 的访问路径
# 其他配置,如数据存储等(可选)
10.2.3 启动应用
启动 Spring Boot 应用后,访问 http://localhost:8080/studio,你将看到 Studio 的主界面。如果没有看到,请检查控制台日志,确认 Studio 是否正确初始化。
10.3 查看智能体执行轨迹
Studio 的核心功能之一是可视化智能体的执行过程。让我们通过一个示例来体验。
10.3.1 准备一个 ReAct 智能体
复用第七章的代码助手智能体(包含 executeCode 工具)。确保它已经注册为 Spring Bean。
10.3.2 通过 Studio 发起对话
在 Studio 界面左侧,你可以选择一个智能体(如 code_assistant),然后在输入框中输入问题,例如:"请写一个 Python 函数计算斐波那契数列的第 10 项并运行它"。点击发送。
Studio 会在右侧显示执行过程,可能包括:
- 思考:智能体每一步的推理文字。
- 工具调用:显示调用了哪个工具,参数是什么。
- 工具结果:工具返回的内容。
- 最终回答:最终的输出。
这些信息以树形结构或时间线呈现,非常直观。
10.3.3 执行轨迹的 Mermaid 可视化
Studio 内部可以将执行轨迹导出为 Mermaid 格式,方便嵌入文档或分享。一个典型的 ReAct 循环的 Mermaid 图如下:
10.3.4 如何获取这些轨迹数据
Studio 通过监听智能体的事件来收集数据。ReActAgent 在执行过程中会发出事件,Studio 订阅这些事件并存储。如果你使用自定义智能体,可以通过继承 BaseAgent 并在关键步骤发送事件来集成,但通常 ReActAgent 已经内置了。
10.4 评估(Evaluation)功能
除了实时调试,Studio 还支持批量评估智能体。你可以定义一组测试用例(输入和预期输出),让智能体批量运行,然后生成评估报告。
10.4.1 创建测试集
在 Studio UI 中,你可以上传一个 JSON 文件作为测试集。格式如下:
json
[
{
"id": "1",
"input": "计算 123 + 456",
"expected": "579"
},
{
"id": "2",
"input": "上海的天气",
"expected": "多云,28℃"
}
]
10.4.2 运行评估
选择要评估的智能体(如 tool_agent),选择测试集,点击开始评估。Studio 会依次运行每个测试用例,记录输出和预期结果的对比。
10.4.3 评估报告
评估完成后,Studio 会生成报告,包括:
- 准确率:完全匹配的比例。
- 耗时统计:平均/最大/最小响应时间。
- 失败案例:列出不一致的用例,方便分析。
你还可以让智能体自己评估结果(LLM-as-a-judge),对比两个版本的智能体输出。
10.4.4 通过 Java API 触发评估(高级)
除了 UI,你也可以通过 Java API 编程方式触发评估。例如,在单元测试中:
java
@Autowired
private EvaluationService evaluationService;
@Test
void evaluateAgent() {
EvaluationRequest request = new EvaluationRequest();
request.setAgentName("code_assistant");
request.setTestSet(testSet);
EvaluationReport report = evaluationService.evaluate(request);
assertEquals(0.8, report.getAccuracy());
}
这需要引入 agentscope-evaluation 模块,但本文从简。
10.5 实践:使用 Studio 调试多智能体系统
让我们结合第五章的旅游规划多智能体系统,用 Studio 来观察它的协作过程。
10.5.1 确保所有智能体被 Studio 识别
只要智能体是 Spring Bean,Studio 会自动发现它们。在 Studio 界面左侧,你应该能看到 travel_supervisor、weather_worker、hotel_worker、itinerary_worker 等。
10.5.2 发起一次规划请求
选择 travel_supervisor 作为入口智能体(或者直接调用它的 HTTP 接口,Studio 会自动捕获)。输入"我想去北京旅游3天"。
10.5.3 观察多智能体交互轨迹
Studio 可能会将这次调用展示为一个父流程,内部包含多个子流程(每个工人的执行)。你可以展开查看:
- 主管发送给天气工人的消息。
- 天气工人的内部 ReAct 循环(如果有工具)。
- 工人返回结果给主管。
- 最终汇总。
这让你能够清楚地看到整个团队是如何协作的。
10.5.4 可视化多智能体协作图
用 Mermaid 可以这样表示:
10.6 本章小结
通过本章的学习,你掌握了:
- AgentScope Studio 的作用:可视化调试、执行轨迹、评估功能。
- 集成 Studio:通过 starter 快速集成,访问 UI 界面。
- 查看执行轨迹:理解智能体的思考与行动过程。
- 评估功能:批量测试智能体,生成质量报告。
- 实践:用 Studio 调试多智能体协作系统,观察消息传递。
Studio 是你开发智能体的"眼睛",让复杂的智能体行为变得透明可解释。结合前一章的 Runtime,你已经拥有了一个完整的企业级智能体开发和运维平台。
十一、高级特性:多模态与 ReMe 记忆系统
在前面的章节中,我们构建的智能体都只处理文本信息。但现实世界的信息是多样的------图片、语音、视频......要让智能体真正像人一样感知世界,它必须具备多模态 能力。同时,之前的记忆(第六章)只是简单的短期对话历史,无法实现跨会话的个性化长期记忆。本章将带你探索 AgentScope Java 的这两项高级特性:多模态智能体 和 ReMe 记忆系统,让你的智能体既能"看"又能"听",还能真正记住用户。
11.1 多模态智能体概述
11.1.1 什么是多模态?
多模态是指智能体能够处理多种类型的数据,包括文本、图像、音频、视频等。对于大模型来说,多模态意味着模型可以同时理解文本和图像(如 GPT-4V、通义千问 VL),甚至生成图像(如通义万相、DALL·E)。
在智能体应用中,多模态能力可以带来丰富的场景:
- 图像理解:根据一张图片回答用户问题("这张图里有什么?"、"这个产品是什么型号?")。
- 图像生成:根据用户描述生成图片("画一只穿着西服的猫")。
- 图文联合推理:分析图表、识别场景等。
11.1.2 AgentScope Java 对多模态的支持
AgentScope Java 通过统一的 ChatClient 接口支持多模态模型的调用。只要底层模型支持图像输入(如通义千问 VL 系列),你就可以在消息中附加图片。对于图像生成,AgentScope 提供了专门的工具封装,也可以通过自定义工具集成通义万相。
| 能力 | 模型 | AgentScope 支持方式 |
|---|---|---|
| 图像理解 | qwen-vl-plus / qwen-vl-max | 在 UserMessage 中添加图片内容 |
| 图像生成 | 通义万相(wanx) | 通过自定义工具或内置 ImageGenerationTool(如果存在) |
11.2 图像理解:让智能体看懂图片
11.2.1 配置支持视觉的模型
在 application.yml 中配置通义千问 VL 模型:
yaml
agentscope:
llm:
provider: dashscope
api-key: ${DASHSCOPE_API_KEY}
model: qwen-vl-plus # 使用视觉模型
11.2.2 构造包含图片的消息
AgentScope 的 UserMessage 支持包含多模态内容。我们需要使用 MediaMessage 或扩展的消息类型。目前 AgentScope 可能使用 ChatMessage 的子类 MultiModalMessage。我们参考之前 Spring AI Alibaba 的方式,构造一个包含图片的消息。
假设 AgentScope 提供了 ImageContent 类,我们可以这样构建:
java
import com.alibaba.agentscope.message.UserMessage;
import com.alibaba.agentscope.message.MediaContent;
// 从 URL 加载图片
UserMessage userMessage = UserMessage.builder()
.text("请描述这张图片")
.image("https://example.com/cat.jpg") // 假设有 image 方法
.build();
如果没有内置支持,我们可以通过提示词传递图片 URL,让模型自行获取(通义千问 VL 支持 URL)。但更推荐的是将图片转为 Base64 并嵌入消息。我们可以在工具中实现图片处理。
11.2.3 实践:构建图像描述智能体
创建一个专门的 VisionAgent,它能接收图片并回答相关问题。
java
package com.example.demo.agent;
import com.alibaba.agentscope.agent.BaseAgent;
import com.alibaba.agentscope.llm.ChatClient;
import com.alibaba.agentscope.message.UserMessage;
import org.springframework.stereotype.Component;
@Component
public class VisionAgent extends BaseAgent {
public VisionAgent(ChatClient chatClient) {
super("vision_agent", chatClient);
}
@Override
protected String getSystemPrompt() {
return "你是一个视觉助手,可以根据图片回答用户的问题。";
}
// 提供一个专门处理图片的方法
public String describeImage(String imageUrl, String question) {
// 构造提示词,将图片 URL 包含在文本中
String prompt = String.format("图片地址:%s\n问题:%s", imageUrl, question);
return run(prompt);
}
// 如果支持多模态消息,可以用更直接的方式,这里简化
}
注意:由于通义千问 VL 模型可以直接接受图片 URL 作为输入的一部分,我们只需在提示词中包含 URL 即可。更规范的方式是使用多模态消息格式,但目前 AgentScope 可能还未完全封装,我们先用文本方式。
11.2.4 测试
在 Controller 中调用:
java
@RestController
public class VisionController {
@Autowired
private VisionAgent visionAgent;
@GetMapping("/describe")
public String describe(@RequestParam String imageUrl,
@RequestParam(defaultValue = "请描述这张图片") String question) {
return visionAgent.describeImage(imageUrl, question);
}
}
访问 http://localhost:8080/describe?imageUrl=https://example.com/cat.jpg&question=这是什么动物?,智能体应该能回答。
11.3 图像生成:让智能体画出图片
11.3.1 配置通义万相模型
通义万相是阿里云的文生图模型,需要通过单独的 API 调用。我们可以在 AgentScope 中创建一个工具来封装它。
首先,确保你有通义万相的 API 权限(通常与通义千问共用 API Key)。模型名称可能是 wanx-v1。
11.3.2 创建图像生成工具
java
package com.example.demo.tool;
import com.alibaba.agentscope.tool.annotation.Param;
import com.alibaba.agentscope.tool.annotation.Tool;
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis;
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisParam;
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisResult;
import org.springframework.stereotype.Component;
@Component
public class ImageGenerationTool {
@Tool(name = "generateImage", description = "根据文本描述生成一张图片")
public String generateImage(
@Param(description = "图片描述,例如'一只穿着西装的猫'") String prompt) {
try {
ImageSynthesisParam param = ImageSynthesisParam.builder()
.model("wanx-v1")
.prompt(prompt)
.n(1)
.size("1024*1024")
.build();
ImageSynthesis imageSynthesis = new ImageSynthesis();
ImageSynthesisResult result = imageSynthesis.call(param);
// 返回第一张图片的 URL
return result.getOutput().getResults().get(0).getImageUrl();
} catch (Exception e) {
e.printStackTrace();
return "图片生成失败:" + e.getMessage();
}
}
}
注意:上述代码使用了阿里云 DashScope SDK,需要引入依赖:
xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dashscope-sdk-java</artifactId>
<version>2.12.0</version>
</dependency>
11.3.3 创建图像生成智能体
java
@Component
public class ImageGenAgent extends BaseAgent {
public ImageGenAgent(ChatClient chatClient) {
super("image_gen_agent", chatClient);
}
@Override
protected String getSystemPrompt() {
return "你是一个图像生成助手,可以根据用户描述生成图片。使用 generateImage 工具。";
}
}
由于工具自动注册,ImageGenAgent 会自动拥有调用 generateImage 的能力。我们可以用 ReActAgent 或直接让 BaseAgent 调用工具?BaseAgent 默认不会主动调用工具,需要 ReActAgent 的循环。因此,我们应该使用 ReActAgent 来包装,或者将 ImageGenAgent 改为 ReActAgent。
我们可以在配置中创建 ReActAgent Bean:
java
@Bean
public ReActAgent imageGenAgent(ChatClient chatClient) {
return ReActAgent.builder()
.name("image_gen_agent")
.chatClient(chatClient)
.systemPrompt("你是一个图像生成助手,可以根据用户描述生成图片。使用 generateImage 工具。")
.maxIterations(3)
.build();
}
11.3.4 测试
创建控制器:
java
@RestController
public class ImageGenController {
@Autowired
@Qualifier("imageGenAgent")
private ReActAgent imageGenAgent;
@GetMapping("/generate")
public String generate(@RequestParam String prompt) {
return imageGenAgent.run(prompt);
}
}
访问 http://localhost:8080/generate?prompt=一只穿着西装的猫,智能体会返回生成的图片 URL。你可以在浏览器中打开该 URL 查看图片。
11.4 ReMe 记忆系统简介
11.4.1 为什么需要更复杂的记忆?
第六章我们实现的记忆只是简单的对话历史存储,无法区分长期和短期,也不能跨会话保留。真正的智能体需要两种记忆:
- 短期工作记忆:当前对话的上下文,用于保持连贯对话。
- 长期经验记忆:跨会话的用户偏好、习惯、重要事实,让智能体越来越了解用户。
ReMe 是 AgentScope 提出的记忆系统,它模拟人类的记忆机制,包含三个层次:
| 记忆层次 | 功能 | 示例 |
|---|---|---|
| 工作记忆 | 当前对话的短期记忆,类似 TokenWindowMemory | 刚才用户说了什么 |
| 个人记忆 | 关于用户的信息,长期存储 | 用户喜欢 Java、家住上海 |
| 工具记忆 | 工具使用经验的累积 | 用户经常查询天气,可能偏好简洁回答 |
11.4.2 ReMe 的核心设计
ReMe 在 AgentScope 中的设计目标是:
- 持久化:个人记忆和工具记忆存储在外部数据库中(如 Redis、关系库)。
- 结构化:记忆以三元组形式存储(主体、关系、客体),便于检索。
- 自动提取与整合:智能体在对话中自动提取重要信息存入长期记忆,并在需要时检索使用。
目前 AgentScope Java 中 ReMe 的实现可能还在演进中,但我们可以用 Redis 模拟个人记忆存储,让智能体具备简单的长期记忆能力。
11.5 实践:为智能体添加长期记忆
我们通过一个简单的例子展示如何让智能体记住用户的偏好(例如用户喜欢的编程语言)。
11.5.1 设计记忆存储
使用 Redis 存储用户偏好。我们定义一个 UserMemoryService,负责存取用户信息。
java
@Service
public class UserMemoryService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private static final String KEY_PREFIX = "user:pref:";
public void savePreference(String userId, String key, String value) {
String redisKey = KEY_PREFIX + userId + ":" + key;
redisTemplate.opsForValue().set(redisKey, value);
}
public String getPreference(String userId, String key) {
String redisKey = KEY_PREFIX + userId + ":" + key;
return redisTemplate.opsForValue().get(redisKey);
}
}
11.5.2 创建带记忆的智能体
智能体在每次对话时,从 Redis 加载用户偏好,并在对话中根据上下文更新偏好。这需要我们在智能体运行时能够访问用户 ID。
我们设计智能体的 run 方法接收两个参数:userId 和 message。但 BaseAgent.run 只接受一个字符串,所以我们需要自定义接口。
可以创建一个新的 Agent 接口:
java
public interface PersonalAgent {
String run(String userId, String message);
}
然后实现类:
java
@Component
public class PersonalAgentImpl implements PersonalAgent {
@Autowired
private ChatClient chatClient;
@Autowired
private UserMemoryService memoryService;
@Override
public String run(String userId, String message) {
// 1. 加载用户偏好
String langPref = memoryService.getPreference(userId, "language");
// 2. 构建系统提示,融入偏好
String systemPrompt = "你是一个个性化助手。";
if (langPref != null) {
systemPrompt += "用户偏好编程语言:" + langPref;
}
// 3. 调用大模型
// 这里简化,直接构造消息
List<ChatMessage> messages = List.of(
new SystemMessage(systemPrompt),
new UserMessage(message)
);
String response = chatClient.chat(messages);
// 4. 从对话中提取新的偏好(简单实现:如果用户说"我喜欢X语言",则存储)
if (message.contains("我喜欢") && message.contains("语言")) {
// 简单正则提取,实际应用中可以用 LLM 提取
Pattern pattern = Pattern.compile("我喜欢(\\w+)语言");
Matcher matcher = pattern.matcher(message);
if (matcher.find()) {
String lang = matcher.group(1);
memoryService.savePreference(userId, "language", lang);
}
}
return response;
}
}
11.5.3 控制器
java
@RestController
public class PersonalController {
@Autowired
private PersonalAgent personalAgent;
@PostMapping("/personal-chat")
public String chat(@RequestParam String userId, @RequestParam String message) {
return personalAgent.run(userId, message);
}
}
11.5.4 测试
- 第一次对话:
/personal-chat?userId=123&message=我喜欢Java语言 - 智能体可能回答一些内容,同时存储了偏好。
- 第二次对话(同一用户):
/personal-chat?userId=123&message=推荐一本编程书智能体会在系统提示中包含"用户偏好Java语言",从而推荐 Java 相关书籍。
这虽然简单,但展示了长期记忆的基本思想。未来 ReMe 将提供更智能的自动提取和检索机制。
11.6 本章小结
通过本章的学习,你探索了 AgentScope Java 的高级特性:
- 多模态图像理解:使用通义千问 VL 模型,让智能体能够描述图片内容。
- 图像生成:通过工具封装通义万相,让智能体能够根据描述生成图片。
- ReMe 记忆系统:了解了长期记忆的重要性,并通过 Redis 实现了简单的用户偏好记忆。
这些能力让智能体更加接近人类,既能"看"又能"画",还能真正记住用户,提供个性化服务。随着 AgentScope 的发展,多模态和记忆功能将更加强大和完善。
十二、总结与最佳实践
我们已经完整地走完了 AgentScope Java 的学习之旅。从最初的环境搭建到高级的多模态与记忆系统,亲手实践了智能体开发的全过程,构建了从简单聊天到复杂多智能体协作的各类应用。现在,是时候回顾所学、提炼经验,并为未来之路指明方向了。
12.1 AgentScope Java 组件全景回顾
在之前的十一章中,我们逐步探索了以下核心组件,每个组件都在智能体系统中扮演着独特的角色。下表为你提供一个清晰的快速索引:
| 类别 | 核心组件/概念 | 章节 | 核心作用 | 你的实践成果 |
|---|---|---|---|---|
| 基础 | Agent, BaseAgent, ChatClient |
二、三 | 定义智能体基座,统一模型调用 | 第一个 Hello Agent,Java导师助手 |
| 工具 | @Tool, ToolManager |
四 | 让智能体调用外部方法,获取实时信息 | 天气、时间、计算器工具 |
| 多智能体 | MessageHub, 广播/点对点 |
五 | 实现智能体间的通信与协作 | 旅游规划多智能体系统 |
| 记忆 | Memory, ConversationMemory, TokenWindowMemory |
六 | 保持对话上下文,实现短期记忆 | 带记忆的聊天助手 |
| ReAct | ReActAgent, 思考-行动-观察循环 |
七 | 处理多步复杂任务,自我纠错 | 代码编写与调试助手 |
| 工作流 | SequentialPipeline, ParallelPipeline, ConditionalPipeline |
八 | 编排确定性业务流程 | 智能客服路由工作流 |
| 部署 | AgentServer, 沙箱机制 |
九 | 安全高效地部署智能体服务 | 带沙箱的文件读取智能体 |
| 可观测 | Studio, 执行轨迹, 评估 |
十 | 可视化调试与性能评估 | 使用Studio调试多智能体系统 |
| 高级 | 多模态(VL/图像生成), ReMe记忆 | 十一 | 拓展感知与长期个性化记忆 | 图像描述与生成、用户偏好记忆 |
一句话总结:AgentScope Java 提供了一套从基础到高级、从开发到部署的完整工具箱,让你能像搭积木一样构建智能体应用,并确保其可靠、安全、可观测。
12.2 生产环境选型建议
将智能体投入生产前,需要根据实际场景做出明智的决策。以下是一些关键建议:
12.2.1 模型选择
AgentScope Java 支持多种模型提供商,选择时需权衡能力、成本、响应速度。
| 模型系列 | 特点 | 适用场景 | 成本 |
|---|---|---|---|
| 通义千问(DashScope) | 国内访问快,功能全面,支持 VL | 大多数企业应用,对数据隐私要求中等 | 按量计费,中等 |
| OpenAI | 能力最强,但国内访问可能受限 | 需要最前沿能力的场景,有海外业务 | 较高 |
| Ollama(本地) | 数据完全私有,无需网络,低延迟 | 数据敏感行业(金融、医疗),离线环境 | 硬件成本 |
建议:
- 国内通用场景优先选择 通义千问,集成最方便。
- 需要视觉能力时,使用 qwen-vl-plus 或 qwen-vl-max。
- 本地私有化部署可考虑 Ollama + llama3 等,但需注意模型能力可能稍弱。
12.2.2 工具沙箱配置
安全是生产环境的重中之重。务必为工具配置严格的沙箱规则:
- 最小权限原则 :默认禁止所有(
default-policy: deny),然后按需开放。 - 文件系统 :只允许工具访问特定目录(如
/data/app/uploads),且设为只读。 - 网络:只允许访问必要的域名(如天气 API、公司内网服务),禁止内网 IP 探测。
- 进程:除非绝对必要,否则禁止执行系统命令。如需执行,应在单独的容器中运行。
12.2.3 记忆持久化
- 短期记忆 :使用
TokenWindowMemory控制上下文长度,避免超出模型限制。 - 长期记忆 :使用 Redis 或数据库存储用户偏好、关键信息。可参考第十一章的
UserMemoryService。 - 生产环境:建议为每个用户/会话创建独立的记忆实例,并用 Redis 的过期时间自动清理不活跃会话。
12.2.4 性能与成本优化
- 缓存:对重复性问题(如常见 FAQ),在智能体外层加一层缓存(如 Redis),直接返回缓存结果,避免调用模型。
- 并发控制 :在 Runtime 中为每个智能体设置
max-concurrent,防止突发流量压垮后端模型 API。 - Token 监控:通过 Studio 或自定义指标记录 Token 消耗,设置告警阈值。
- 模型降级 :对简单问题使用
qwen-turbo,复杂问题使用qwen-max。可在智能体内根据问题长度或关键词动态选择模型。
12.2.5 可观测性
- 强制在生产环境开启 Studio 的指标收集,但注意不要将 Studio UI 暴露在公网。
- 关键指标:请求量、平均耗时、错误率、Token 用量。
- 使用 Prometheus + Grafana 构建监控大盘,或对接阿里云 ARMS。
12.2.6 多智能体 vs 工作流
- 对于流程确定、需要审计的业务(如订单处理),优先使用 Pipeline 工作流。
- 对于开放、需要动态决策的任务(如个人助手),优先使用 多智能体协作 + ReAct。
- 二者可以结合:外层用 Pipeline 控制流程,内层用 ReAct 智能体处理复杂子任务。
12.3 后续学习路径
你已经掌握了 AgentScope Java 的核心,下一步可以朝以下方向深入:
- 关注官方动态 :AgentScope 正在快速发展,关注 GitHub 仓库 和 官方文档,及时了解新特性。
- 深入 ReAct 与提示词工程:ReAct 的效果高度依赖提示词。学习如何设计高质量的 System Prompt,让智能体更好地遵循指令。
- 探索 AgentScope Python 版:Python 版功能更丰富,可以作为借鉴,了解未来 Java 版可能的发展方向。
- 实践项目:选择一个真实业务场景(如智能客服、代码审查助手、会议纪要助理),用 AgentScope Java 完整实现,并部署上线。
- 参与社区:给项目点 Star,提交 Issue 或 PR,与其他开发者交流。
12.4 写在最后
通过本教程,你不仅学会了 AgentScope Java 的技术细节,更重要的是建立了一套构建智能体应用的思维框架。从零开始,你已经能够:
- 让智能体拥有记忆,记住用户说过的话。
- 让智能体调用工具,获取实时信息、执行操作。
- 让多个智能体协作,像团队一样完成复杂任务。
- 让智能体进入 ReAct 循环,自主思考与纠错。
- 用工作流编排确定性流程,满足企业级要求。
- 将智能体安全部署为服务,并用 Studio 监控它。
- 让智能体看懂图片、画出图片,并记住用户的长期偏好。
AI 技术日新月异,但核心的思维模式------将智能体视为自主的、协作的、有记忆的实体------将伴随你不断前行。
附录
A. 常见问题解答(FAQ)
Q1: 为什么我的智能体不调用工具? A: 检查以下几点:
- 工具类是否有
@Tool注解,且是 Spring Bean(@Component)。 - 工具描述是否清晰,能让模型理解何时调用。
- 如果你用的是
BaseAgent,它默认不会自动调用工具。需要使用ReActAgent或继承BaseAgent并手动处理工具调用逻辑。
Q2: 如何调试 ReAct 智能体的思考过程? A: 启用 Studio(第十章),通过 UI 查看执行轨迹。或者在代码中增加日志,打印智能体每次的输入输出。
Q3: 沙箱报错"权限不足"怎么办? A: 检查沙箱配置(application.yml)中的 allowed-paths 或 allowed-hosts 是否包含了工具需要访问的资源。按需放宽权限,但务必遵循最小权限原则。
Q4: 多智能体系统中,消息收不到? A: 确认所有智能体都注入了同一个 MessageHub Bean(默认是单例)。检查发送时指定的接收者名称是否与接收智能体的 getName() 一致。接收方需要定期调用 receive() 或开启定时任务处理消息。
Q5: Studio 无法访问? A: 检查依赖是否完整,application.yml 中 agentscope.studio.enabled=true。确认端口没有被占用,访问路径是否正确(默认 /studio)。查看启动日志,看 Studio 是否成功初始化。
Q6: 通义千问 VL 模型调用返回"模型不支持"怎么办? A: 确认你开通了 VL 模型的权限。在 DashScope 控制台中,需要单独开通 qwen-vl-plus 或 qwen-vl-max 的体验(通常免费)。检查 model 名称是否拼写正确。
Q7: 如何估算 Token 消耗? A: Studio 的评估报告中会显示 Token 用量。也可以自己在智能体中记录 ChatResponse 的元数据。通义千问的响应中通常包含 usage 字段。
B. 完整代码示例仓库地址
为了方便你查阅和运行,本教程的所有代码示例已整理到一个 Git 仓库中:
仓库按章节组织,每个示例包含完整的 Java 类和配置文件,并附有 README 说明。
C. 参考资源链接
- AgentScope Java GitHub :github.com/agentscope/...
- 官方文档 :agentscope.io/docs/java
- 阿里云 DashScope 文档 :help.aliyun.com/zh/dashscop...
- ReAct 模式论文 :arxiv.org/abs/2210.03...
- AgentScope Python 版 :github.com/agentscope/...