用 AgentScope Java 开家 AI 奶茶店
作者:屿山 AgentScope 是阿里云推出的一款以开发者为核心,专注于智能体开发的开源框架 。 它的核心目标是解决智能体在构建、运行和管理中的难题,提供一套覆盖“开发、部署、调优”全生命周期的生产级解决方案,让智能体应用的开发更简单、运行更稳定、效果持续优化。 去年 12 月份,社区正式发布了 AgentScope Java 1.0 版本,面向 Java 开发者提供企业级 Agentic 应用构建的能力。在过去的一个多月,社区快速迭代到了 1.0.7 版本,在这 7 个小版本中,我们更新了很多实用的能力,比如: 至此 AgentScope Java 以 ReActAgent 为核心,配合众多强大的能力,已经能够胜任大多数场景的任务。面对如此多的能力,很多同学在社区反馈光看文档和单一功能的 Example 还是不够效率,不能快速地用好这些能力。为此我们用 AgentScope Java 开了一家奶茶店,来作为一个综合的 Example,为大家演示如何更好地使用 AgentScope Java。 首先我们先一起看看这家店能干啥: 首先在总体结构上我们采用了 Supervisor-Worker 架构,同时集成了一些生态组件来达到最终的效果。 其中 AgentScope 多智能体服务层是由一个 Supervisor Agent 和两个 Sub Agent 构成的智能体系统,负责处理店内大大小小的事项;MCP Server 负责处理具体的业务逻辑,可以直接基于传统的业务系统改造;Nacos 负责 Agent 和 MCP 的动态注册和发现;数据持久层负责数据的持久化,包括知识库、会话、记忆、业务数据等。 接下来我们一点一点地来拆解这家店,特别是多智能体服务层。 在这一部分我们来介绍为了实现上述的效果,我们要用到哪些能力,以及要如何进行开发。当然这边我们只能展示一些关键部分的代码片段,完整实现可以移步 agentscope-java/agentscope-examples/boba-tea-shop [ 1] 。 为了能处理店内大大小小的事项,我们就需要一个能思考会行动的 Agent,而一个符合 Reasoning and Acting 范式的 Agent 能很好地完成这个任务。为了构建这个 Agent 如果不借助框架的话我们需要至少完成以下事项: 而在 AgentScope Java 中我们只需要进行一些配置便可以组装出一个 ReActAgent,由 AgentScope 完成上述的事项,同时我们原生支持了多家厂商的协议,包括 DashScope、Anthropic、Gemini、OpenAI。 当我们对 AI 应用的需求从单一的对话交互转向复杂的现实世界问题解决,单体智能系统(Single-Agent Systems)的局限性日益凸显。 为了解决这些问题大家都在逐步探索多智能体架构,我们也借奶茶店这个场景为大家演示如何用 AgentScope Java 开发多智能体系统中 Agent AS Tool 的模式。为了实现这个效果,我们原本需要基于 A2A Java SDK 来构建对应的 Client 和 Server,同时还需要进行一些事件和通讯的适配与对接,繁碎的同时还没有动态注册发现的能力。 所以为了更加便捷地落地 A2A 架构,AgentScope 提供了 A2A extension 来完成 A2A Java SDK 适配和对接,并且集成了 Nacos 来实现动态的 Agent 注册和发现。于是现在在 AgentScope Java 中只需要少量代码就可以完成 A2A 架构的落地。 首先是子 Agent 的注册,只需要定义客制化的内容即可,主要是子 Agent 自身所需要的模型、工具等组件的配置,其他部分由框架搞定。 而对于 Supervisor Agent 来说由于集成了 Nacos,只需要构建一个 AiService 然后做一些简单的配置就可以完成子 Agent 的发现。 然后再把子 Agent 注册成一个工具,便可以像使用普通工具一样调用子 Agent。 MCP 几乎已经成为了远程工具调用的事实标准,很多传统的业务系统也会提供 MCP 的 Endpoint 来使 Agent 能够触达真实业务场景。传统的 MCP 工具的注册方式是一个固定的 Endpoint,在灵活性和高可用上都不能完全满足需求。所以 AgentScope 在传统注册方式的基础上也集成了 Nacos 来实现 MCP 的动态发现。只需要在Business Sub Agent 中通过集成的 NacosMcpServerManager 加上几行代码便可以轻松完成 MCP 工具的注册。 会话通常包含了和模型的多轮对话,与记忆等有状态的内容绑定,如果只存储在内存中,在多实例部署或者重启场景下都会导致丢失或者错乱。所以 AgentScope 提供了基于 MySQL 的会话存储能力,能够随时接着上次聊天继续聊,同一会话无缝衔接,不同会话互相隔离。要在 AgentScope 中启用这个能力只需要部署一个 MySql 数据库,然后创建 MysqlSession 实例,在需要的地方 load 即可恢复到之前的状态,继续对话。 Mem0 是一个长期记忆服务框架,帮助 Agent 持续优化长期记忆,可以使用商业化版本也可以自行部署。在奶茶店的场景下,他能够帮助 Agent 不只拥有当前会话的记忆,还能跨会话记住用户关于饮品、甜度、冰量等偏好。自行对接 Mem0 需要维护与它的通讯以及注入 Agent 的方式和时机。在 AgentScope 中,则只需要配置 Mem0 的BaseUrl 以及 apiKey 即可。 现在的大模型的上下文窗口大小已经从早期的 4k 扩展至 100k 甚至 1M,但其中要存放历史交互、外部知识库检索结果、复杂的任务指令、中间推理步骤以及工具调用的返回结果等等,在复杂的场景中依旧存在着上下文大小焦虑。同时随着上下文窗口的暴涨,模型在检索和利用中间位置关键信息的效果和性能会显著下降。所以我们往往会考虑对上下文进行压缩,但是如果是简单的压缩很有可能会导致有效信息的损失,为了压缩而损失了准确性是不可取的。所以 AgentScope 推出了AutoContextMemory,它是框架提供的智能上下文内存管理组件,通过自动压缩、卸载和摘要对话历史,在成本控制和信息保留之间找到最佳平衡,具体的原理可以参考我们之前发布的文章《AgentScope AutoContextMemory:告别Agent上下文焦虑》。要使用该能力同样只需要配置一些简单参数即可。 为了让大家能够快速体验,同时方便大家拿奶茶店练手,我们提供了多种便捷的部署方式: 如果想使用云产品部署,可以使用 AgentRun,直接拉取镜像部署,所需要配置的环境变量参考 README.md 文档。 这个奶茶店的例子只是 AgentScope Java 能力的冰山一角,用来带大家快速入门。AgentScope Java 框架还支持更多玩法,所有的核心能力都有对应的 Example,欢迎大家体验: 同时社区也在快速演进中,欢迎大家参与讨论和贡献 🚀 Star 一下不迷路! ⭐ 项目地址:AgentScope Java [ 2] Demo 地址: "Talk is cheap, show me the agents." 快来 Clone 下来跑一把,体验一下 AI 给你点奶茶的快感吧! 相关链接: [1] agentscope-java/agentscope-examples/boba-tea-shop https://github.com/agentscope-ai/agentscope-java/tree/main/agentscope-examples/boba-tea-shop [2] AgentScope Java前言
这家店能干啥?

这家店怎么做的?
架构解析

能力解析
ReActAgent:能思考会行动
DashScopeChatModel.Builder builder =
DashScopeChatModel.builder()
.apiKey(dashscopeApiKey)
.modelName(dashscopeModelName)
.formatter(new DashScopeChatFormatter());
DashScopeChatModel model = builder.build();
ReActAgent agent = ReActAgent.builder()
.name("supervisor_agent")
.sysPrompt(sysPrompt)
.toolkit(toolkit) // 挂载工具
.model(model) // 配置大模型
.memory(memory) // 短期记忆模块
.longTermMemory(longTermMemory) //长期记忆模块
.build();集成 Nacos 的 A2A 架构:专业的事情让专业的 Agent 来做
@Bean
public AgentRunner agentRunner(
AgentPromptConfig promptConfig,
ConsultTools consultTools,
Knowledge knowledge,
Model model) {
Toolkit toolkit = new NacosToolkit();
toolkit.registerTool(consultTools);
AutoContextConfig autoContextConfig =
AutoContextConfig.builder().tokenRatio(0.4).lastKeep(10).build();
// Use AutoContextMemory, support context auto compression
AutoContextMemory memory = new AutoContextMemory(autoContextConfig, model);
ReActAgent.Builder builder =
ReActAgent.builder()
.name("consult_agent")
.sysPrompt(promptConfig.getConsultAgentInstruction())
.memory(memory)
.hooks(List.of(new MonitoringHook()))
.model(model)
.toolkit(toolkit)
.knowledge(knowledge)
.ragMode(RAGMode.AGENTIC);
return new CustomAgentRunner(builder);
}@Bean
public AiService nacosA2aService() throws NacosException {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, serverAddress);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
return AiFactory.createAiService(properties);
}
@Bean
public A2aAgent consultAgent(AiService a2aService) {
return A2aAgent.builder()
.name("consult_agent")
.agentCardResolver(new NacosAgentCardResolver(a2aService))
.build();
}@Tool(description =
"Agent for handling consultation-related requests, can process all"
+ " consultation-related requests, requires passing the complete context in"
+ " the context parameter")
public String callConsultAgent(
@ToolParam(name = "context", description = "Complete context") String context,
@ToolParam(name = "userId", description = "User's UserId") String userId) {
Msg msg = Msg.builder().content(TextBlock.builder().text(context).build()).build();
A2aAgent consultAgent = consultAgentProvider.getObject();
return combineAgentResponse(consultAgent.call(msg).block());
}集成 Nacos 的 MCP 调用:动态注册&发现
Toolkit toolkit = new NacosToolkit();
NacosMcpServerManager mcpServerManager = new NacosMcpServerManager(aiService);
NacosMcpClientWrapper mcpClientWrapper =
NacosMcpClientBuilder.create("business-mcp-server", mcpServerManager).build();
toolkit.registerMcpClient(mcpClientWrapper).block();会话持久化:重启不丢失
MysqlSession mysqlSession =
new MysqlSession(dataSource, System.getenv("DB_NAME"), null, true);
ReActAgent agent = createAgent(toolkit, memory);
agent.loadIfExists(mysqlSession, sessionId);Mem0 长期记忆:记住每一位顾客
Mem0LongTermMemory longTermMemory =
Mem0LongTermMemory.builder()
.agentName("BusinessAgent")
.userId(userId)
.apiBaseUrl("https://api.mem0.ai")
.apiKey(System.getenv("MEM0_API_KEY"))
.build();AutoContextMemory:上下文压缩
AutoContextConfig autoContextConfig =
AutoContextConfig.builder().tokenRatio(0.4).lastKeep(10).build();
// Use AutoContextMemory, support context auto compression
AutoContextMemory memory = new AutoContextMemory(autoContextConfig, model);快速开始
本地开发推荐
# 配置环境变量
cp local-env.example local-env.sh
vim local-env.sh
# 一键启动
source local-env.sh && ./local-deploy.sh startK8s 生产推荐
# 配置变量
vim values.yaml
# Helm 一键部署
helm install agentscope helm/ --namespace agentscopeDocker 极简
# 配置环境变量
cp docker-env.example .env
# 容器一把梭
docker-compose up -d云产品(AgentRun)部署
最后的最后
agentscope-examples/boba-tea-shop