
概述
如今 AI 智能体已然遍地开花,但绝大多数都基于 Python 或 Node.js 开发。作为 Java 开发者,你或许一直置身局外观望,好奇 Java 生态何时才能迎头赶上。
事实上,JavaClaw 是一款基于 Java 生态构建的本地化个人 AI 智能体平台,其核心定位是:在用户自有硬件上运行,充当多渠道 AI 智能体的控制平面(Control Plane)。它不仅是一个对话机器人,更是一个具备任务调度、工具调用、多渠道接入、记忆管理能力的全功能智能体运行时。
从官方的描述来看,JavaClaw 最初作为 JobRunr 的演示项目诞生,但已发展成为面向 Java 社区的开放式 AI 智能体基础框架,致力于让开发者能以 Java 为母语构建下一代 AI 智能体系统。
项目口号: "让数据留在本地,让能力延伸到无限。"
核心优势
隐私优先的本地化设计
与大多数 AI 助手依赖云端服务不同,JavaClaw 完全在用户本地运行。对话记忆以 YAML 文件形式落盘,任务以 Markdown 文件形式存储,无需外部数据库,所有敏感数据均不出本机(除非用户主动配置 OpenAI/Anthropic 等外部 LLM)。
深度拥抱 Java 生态
JavaClaw 选用当下最先进的 Java 技术栈:Java 25、Spring Boot 4.0.3、Spring AI 2.0.0,完全依托 JVM 生态,无需 Python 环境,开发者可用熟悉的 Spring 开发范式扩展智能体能力。
多 LLM 后端可插拔
通过 Spring AI 的抽象层,JavaClaw 可无缝切换 OpenAI、Anthropic Claude 或本地 Ollama 模型,不需要修改业务代码,只需在 application.yaml 中更换配置项即可。
多渠道统一接入
支持 Web Chat(WebSocket)、Telegram、Discord 三种开箱即用的通信渠道,所有渠道共享同一个智能体内核和对话记忆,用户可以从 Telegram 发起任务,在 Discord 查看进度,体验真正的全渠道智能体。
运行时可扩展的 Skills 机制
通过在 workspace/skills/ 目录下投放 SKILL.md 文件,智能体在无需重启、无需修改代码的情况下即可习得新技能,这是 JavaClaw 最具差异化的能力之一。
企业级后台任务调度
基于 JobRunr 提供一次性、延迟、Cron 周期性三种任务调度模式,并内置可视化 Dashboard(:8081),任务状态实时可查,具备生产级可靠性。
MCP 协议支持
完整实现了 Model Context Protocol(MCP)客户端,支持 stdio 和 streamable-HTTP 两种模式,可无缝接入任何标准 MCP 工具服务器,大幅扩展工具调用能力边界。
架构
整体架构总览
JavaClaw 采用模块化单体(Modular Monolith)架构,借助 Spring Modulith 对模块边界进行约束,在保留单体部署便利性的同时,实现模块间的低耦合。
模块结构划分
Spring Modulith 内部模块边界
技术栈
Agent 运行原理
核心抽象:Agent 接口
Agent 接口是整个智能体的行为契约,定义了两种基本能力:
publicinterfaceAgent {// 自然语言对话:给定会话ID和用户问题,返回智能体回复 String respondTo(String conversationId, String question);// 结构化输出:给定会话ID和提示词,将回复解析为指定Java类型 <T> T prompt(String conversationId, String input, Class<T> result);}DefaultAgent 是其唯一实现,核心逻辑极为简洁——将调用完全委托给 Spring AI 的 ChatClient,真正的复杂性被封装在 Advisor 链中。
ChatClient 的构建与装配
JavaClawConfiguration 是整个系统的"大脑装配车间",它在应用启动时构建出一个功能完备的 ChatClient:
@Bean@DependsOn({"mcpHeaderCustomizer"})public ChatClient chatClient( ChatClient.Builder chatClientBuilder, ChatMemory chatMemory, ObjectProvider<ToolSearchToolCallAdvisor> toolSearchAdvisorProvider, SyncMcpToolCallbackProvider mcpToolProvider, TaskManager taskManager, ConfigurationManager configurationManager,@Value("${agent.workspace:Unknown}") Resource workspace, Set<AutoDiscoveredTool<?>> autoDiscoveredTools)throws IOException {// 1. 加载系统提示词(AGENT.md + INFO.md)StringagentPrompt= agentMd.getContentAsString(UTF_8) + infoMd.getContentAsString(UTF_8);// 2. 决定工具调用模式:动态发现 or 全量暴露ToolCallAdvisortoolCallAdvisor= toolSearchAdvisorProvider.getIfAvailable(ToolCallAdvisor.builder()::build);// 3. 注册所有内置工具 chatClientBuilder .defaultSystem(p -> p.text(agentPrompt) .param(ENVIRONMENT_INFO_KEY, AgentEnvironment.info())) .defaultToolCallbacks(mcpToolProvider.getToolCallbacks()) .defaultToolCallbacks(SkillsTool.builder() .addSkillsDirectory(skillsDir(workspace)).build()) .defaultTools( TaskTool.builder().taskManager(taskManager).build(), CheckListTool.builder().build(), McpTool.builder().configurationManager(configurationManager).build(), FileSystemTools.builder().build(), SmartWebFetchTool.builder(chatClientBuilder.clone().build()).build()) .defaultAdvisors(newSimpleLoggerAdvisor(), toolCallAdvisor, // 工具调用 MessageChatMemoryAdvisor.builder(chatMemory).build()); // 记忆注入// 4. 自动发现并注册插件工具 autoDiscoveredTools.forEach(t -> chatClientBuilder.defaultTools(t.tool()));return chatClientBuilder.build();}完整的消息处理流程
Advisor 链的执行顺序与职责
JavaClaw 的 Advisor 链按以下顺序执行,每个 Advisor 都可以在请求到达 LLM 前后进行拦截和增强:
动态工具发现机制
当 javaclaw.tools.dynamic-discovery.enabled=true 时,系统启用工具搜索模式(Tool Search Pattern):
配置示例:
javaclaw:tools:dynamic-discovery:enabled:truemax-results:8# 最多注入 8 个工具lucene-min-score-threshold:0.25# 相关性最低分阈值后台任务执行流程
后台任务是 JavaClaw 区别于普通聊天机器人的核心特性。任务的创建和执行形成了一个完整的异步闭环:
对话记忆的持久化策略
JavaClaw 采用基于文件系统的对话记忆,对话历史存储为 YAML 文件,支持跨进程重启的记忆持久化:
Skills扩展
JavaClaw 提供了三种层次的扩展方式,从零代码到完整插件,覆盖不同的扩展场景。
扩展方式一:零代码 SKILL.md 技能文件
这是最轻量的扩展方式,无需修改任何代码,无需重启服务,适合快速为 Agent 添加新的知识、流程或行为规范。
工作原理:
SkillsTool 在每次被 LLM 调用时,动态扫描 workspace/skills/ 目录,将所有 SKILL.md 文件的内容作为上下文注入 Agent。
示例:创建一个"每日周报"技能
在 workspace/skills/daily-report/SKILL.md 中写入:
# Daily Report Skill你可以帮助用户生成每日工作总结报告。## 使用场景当用户要求"生成今日报告"、"写工作总结"时,触发此技能。## 报告格式1.**今日完成工作**:列出当天已完成的任务2.**进行中的工作**:当前仍在处理的任务3.**明日计划**:下一个工作日的计划4.**遇到的问题**:任何阻塞项或需要协助的事项报告语言:中文,语气专业简洁。文件放入目录后,Agent 立即具备生成标准化报告的能力,无需任何重启。
扩展方式二:实现 AutoDiscoveredTool 插件工具
当需要实现有状态的工具或调用外部 API 时,通过 Java 代码实现工具类,并注册为 AutoDiscoveredTool Bean,框架会在启动时自动发现并将其注入 ChatClient。
扩展步骤:
第一步:定义工具类
package com.example.tools;import org.springframework.ai.tool.annotation.Tool;import org.springframework.stereotype.Component;/** * 自定义天气查询工具示例 */@ComponentpublicclassWeatherTool {privatefinal WeatherApiClient weatherApiClient;publicWeatherTool(WeatherApiClient weatherApiClient) {this.weatherApiClient = weatherApiClient; }@Tool(name = "getWeather", description = "根据城市名称查询当前天气情况。返回温度、天气状况和湿度信息。")public String getWeather(String city) {try {WeatherDatadata= weatherApiClient.fetchWeather(city);return String.format("城市:%s,温度:%s°C,天气:%s,湿度:%s%%", city, data.temperature(), data.condition(), data.humidity() ); } catch (Exception e) {return"无法获取 " + city + " 的天气信息:" + e.getMessage(); } }@Tool(name = "getWeatherForecast", description = "获取指定城市未来 N 天的天气预报,N 最大为 7。")public String getWeatherForecast(String city, int days) {// 实现天气预报逻辑...return weatherApiClient.fetchForecast(city, Math.min(days, 7)).toString(); }}第二步:注册为 AutoDiscoveredTool
package com.example.config;import ai.javaclaw.tools.AutoDiscoveredTool;import com.example.tools.WeatherTool;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@ConfigurationpublicclassWeatherToolConfiguration {/** * 将 WeatherTool 包装为 AutoDiscoveredTool, * JavaClawConfiguration 会自动发现并注册它。 */@Beanpublic AutoDiscoveredTool<WeatherTool> weatherAutoDiscoveredTool(WeatherTool weatherTool) {returnnewAutoDiscoveredTool<>(weatherTool); }}框架自动发现机制(源码):
在 JavaClawConfiguration.chatClient() 方法中,框架通过如下方式自动注册所有 AutoDiscoveredTool:
// 自动将所有 AutoDiscoveredTool Bean 注册到 ChatClientautoDiscoveredTools.forEach(autoDiscoveredTool -> chatClientBuilder.defaultTools(autoDiscoveredTool.tool()));扩展方式三:实现完整的 Channel 渠道插件
当需要接入新的消息渠道(如企业微信、飞书、SMS 等)时,实现 Channel 接口并将其注册到 ChannelRegistry。
扩展步骤:
第一步:实现 Channel 接口
package com.example.channels;import ai.javaclaw.channels.Channel;import ai.javaclaw.channels.ChannelRegistry;import ai.javaclaw.channels.ChannelMessageReceivedEvent;import ai.javaclaw.agent.Agent;import org.springframework.stereotype.Component;/** * 企业微信渠道插件示例 */@ComponentpublicclassWeChatWorkChannelimplementsChannel {privatestaticfinalStringCONVERSATION_ID="wechat-work-channel";privatefinal Agent agent;privatefinal ChannelRegistry channelRegistry;privatefinal WeChatWorkClient weChatClient;publicWeChatWorkChannel(Agent agent, ChannelRegistry channelRegistry, WeChatWorkClient weChatClient) {this.agent = agent;this.channelRegistry = channelRegistry;this.weChatClient = weChatClient;// 注册自身到渠道注册中心 channelRegistry.registerChannel(this);// 启动消息接收监听 startMessageListener(); }@Overridepublic String getName() {return"WeChatWorkChannel"; }@OverridepublicvoidsendMessage(String message) {// 通过企业微信 API 发送消息 weChatClient.sendTextMessage(message); }privatevoidstartMessageListener() {// 企业微信消息回调处理 weChatClient.onMessageReceived(event -> {StringuserId= event.getUserId();Stringcontent= event.getContent();// 通知 ChannelRegistry 当前活跃渠道 channelRegistry.publishMessageReceivedEvent(newChannelMessageReceivedEvent(this.getName()) );// 转发给 Agent 处理,使用 userId 作为会话ID以隔离对话记忆Stringresponse= agent.respondTo(userId, content);// 回复用户 sendMessage(response); }); }}第二步:添加 Onboarding 步骤(可选)
实现 OnboardingProvider 接口,在引导流程中为用户提供渠道配置 UI:
package com.example.channels;import ai.javaclaw.onboarding.OnboardingProvider;import ai.javaclaw.configuration.ConfigurationManager;import org.springframework.stereotype.Component;import java.util.Map;@ConfigurationpublicclassWeChatWorkOnboardingProviderimplementsOnboardingProvider {privatefinal ConfigurationManager configurationManager;publicWeChatWorkOnboardingProvider(ConfigurationManager configurationManager) {this.configurationManager = configurationManager; }@Overridepublic String getStepId() {return"wechat-work"; }@Overridepublic String getTitle() {return"企业微信配置"; }@OverridepublicbooleanisCompleted() {// 检查配置是否已完成return configurationManager.hasProperty("agent.channels.wechat-work.corp-id"); }publicvoidsaveConfig(String corpId, String agentId, String secret) { configurationManager.updateProperties(Map.of("agent.channels.wechat-work.corp-id", corpId,"agent.channels.wechat-work.agent-id", agentId,"agent.channels.wechat-work.secret", secret )); }}三种扩展方式对比
MCP 服务器动态注册
JavaClaw 支持在运行时通过 McpTool 注册新的 MCP 服务器,这一操作可以直接通过自然语言对话触发:
// 用户对话示例:// "帮我添加一个 MCP 服务器,地址是 http://localhost:8000/mcp,名字叫 my-tools"// Agent 自动调用 McpTool.addStreamableHttpMcpServer()@Tool(description = "添加新的 streamable-HTTP MCP 服务器到应用配置中")public String addStreamableHttpMcpServer(String name, String url, String headers) {// 持久化到 application.private.yaml configurationManager.updateProperties(Map.of("spring.ai.mcp.client.streamable-http.connections." + name + ".url", url ));return"MCP 服务器已添加,重启后生效";}总结
JavaClaw 以其"本地优先、Java 原生、极简扩展"的设计哲学,为 Java 开发者提供了一个生产级的 AI 智能体运行时平台。
在架构层面,它借助 Spring Modulith 实现模块化约束,以 Spring AI 的 ChatClient 和 Advisor 模式为核心,将记忆管理、工具调用、日志追踪等横切关注点优雅地解耦;在智能体运行层面,Advisor 链的洋葱式执行模型和动态工具发现机制使得 Agent 既高效又灵活;在可扩展性层面,从零代码的 SKILL.md 到插件式的 AutoDiscoveredTool,再到渠道级别的 Channel 扩展,形成了层次清晰、门槛渐进的完整扩展体系。
对于 Java 团队而言,JavaClaw 提供的不仅是一个可直接使用的个人助手,更是一套可以作为企业级 AI 智能体平台基础的参考架构,值得深入研究与实践。
夜雨聆风