用 200 行 Java 造一个 Claude Code:spring-ai-agent-utils 完全指南

本文基于 Spring AI 2.0.0spring-ai-agent-utils 0.10.0(截至 2026-08-19)编写。该领域迭代极快,请以官方文档为准。

当 Claude Code 被"移植"到了 Java

摘要: 本文带你拆解 spring-ai-agent-utils——一个由 Spring AI Community 出品、把 Claude Code 核心能力用 Spring AI Tool 抽象重新实现的 Java Agent 工具库。文章从项目定位与五分钟上手讲起,梳理其与 Claude Code 一一对应的工具体系,手把手组装 CLI 编码 Agent,并深入架构分层、子 Agent 委派、Markdown 即 Agent、A2A 跨进程协作等核心设计;最后以逆向工程视角解读系统提示词这一"资产",客观总结 0.x 版本的局限,指出它作为 Spring AI 2.0 时代 Agent 工程化教科书的价值。

先看一句官方定位,来自 Spring AI Community 的项目 README:

“reimplements core Claude Code capabilities as Spring AI tools”
(将 Claude Code 的核心能力重新实现为 Spring AI 工具)

Claude Code 是 Anthropic 推出的终端 AI 编码助手,也是目前 Agentic Coding 的标杆产品。但它是一个黑盒产品——你只能用,不能拆。而 spring-ai-agent-utils 做了一件有意思的事:把 Claude Code 的工具体系逐个逆向、拆解,再用 Spring AI 的 Tool 抽象重新实现了一遍

连细节都在复刻:系统提示词模板命名为 MAIN_AGENT_SYSTEM_PROMPT_V2.md,默认子 Agent 叫 general-purposeExplore,技能目录约定为 .claude/skills/——用过 Claude Code 的人会心一笑。

对 Java 开发者而言,这个项目的意义不只是"玩具":它是一个生产级自主 Agent 的参考实现,展示了 2026 年 Java 生态构建 Agentic 应用的完整技术栈。

它到底是什么

先交代背景:

  • 出品方:Spring AI Community(spring-ai-community 组织),是 Spring AI 2.0 GA 发布公告中官方点名的社区扩展项目(另一个是事件溯源记忆库 spring-ai-session);
  • 版本:0.10.0,Apache 2.0 协议(版本还在 0.x,API 可能变动);
  • 基线要求:Java 17+,Spring Boot 3.x / 4.x,Spring AI 2.0.0+,Maven 3.6+;
  • 定位:Spring AI 提供通用 LLM 能力(ChatClient、Advisor、工具调用),agent-utils 在其上补齐"软件工程 Agent"所需的全部工具件。

一个容易混淆的概念先澄清:这里的 “agent” 与 JVM 的 java.lang.instrument Agent、AOP 的 agentmain 毫无关系,指的是 LLM 驱动的自主智能体(AI Agent)。

五分钟上手

引入依赖

推荐用 BOM 统一管理版本:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springaicommunity</groupId>
            <artifactId>spring-ai-agent-utils-bom</artifactId>
            <version>0.10.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springaicommunity</groupId>
        <artifactId>spring-ai-agent-utils</artifactId>
    </dependency>
    <!-- 任选一个 LLM 提供商 starter,比如 Anthropic / OpenAI / Google GenAI -->
</dependencies>

核心库对 Spring AI 的依赖声明为 provided 作用域,不会和你的项目版本打架。

最小配置

# LLM 提供商(以 Anthropic 为例)
spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY}

# 可选:Brave 搜索
BRAVE_API_KEY=${BRAVE_API_KEY}

# 可选:注入到系统提示词的模型元信息
agent.model=claude-sonnet-4-5
agent.model.knowledge.cutoff=2025-09

就这么点东西,下面进入正题。

工具体系:与 Claude Code 一一对应

agent-utils 的工具清单,几乎就是 Claude Code 的能力地图:

agent-utils 工具对应 Claude Code 能力说明
FileSystemToolsRead / Write / Edit分页读文件(带行号)、写文件、精确字符串替换(带唯一性校验)
ShellToolsBashShell 命令执行
GrepToolGrep内容正则搜索
GlobToolGlob文件模式匹配查找
SmartWebFetchToolWebFetch智能网页抓取,内部用一个独立 ChatClient 做 AI 摘要,HTML 转 Markdown
BraveWebSearchToolWebSearchBrave API 网络搜索
TaskToolTask子 Agent 任务委派
TaskOutputTool取回后台异步任务的执行结果
TodoWriteToolTodoWrite结构化任务清单与进度跟踪
AskUserQuestionToolAskUserQuestion向用户提出澄清式问题
SkillsToolSkills加载 Markdown 编写的技能模块
AutoMemoryToolsMemory沙箱化的长期记忆读写

所有工具都通过 XxxTool.builder()...build() 流式构建,标准 Spring AI Tool 抽象,可以直接注册给任何 ChatClient

核心实战:组装你的 CLI 编码 Agent

官方仓库 examples/code-agent-demo 是最完整的参考实现——全部核心逻辑集中在一个 156 行的 Application.java 里。下面是整理简化后的骨架(基于官方示例改写):

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    CommandLineRunner commandLineRunner(ChatClient.Builder chatClientBuilder,
            @Value("classpath:/prompt/MAIN_AGENT_SYSTEM_PROMPT_V2.md") Resource systemPrompt,
            @Value("${agent.skills.paths}") List<Resource> skillPaths,
            ToolCallbackProvider mcpTools,          // 外部 MCP 工具,按需注入
            @Value("${BRAVE_API_KEY:}") String braveApiKey) {

        return args -> {
            ChatClient chatClient = chatClientBuilder
                    // 1. 系统提示词:注入运行时环境上下文
                    .defaultSystem(sb -> sb.text(systemPrompt)
                            .param("model", "claude-sonnet-4-5")
                            .param("knowledgeCutoff", "2025-09"))
                    // 2. MCP 外部工具
                    .defaultToolCallbacks(mcpTools)
                    // 3. 技能系统:从 Markdown 加载
                    .defaultToolCallbacks(SkillsTool.builder()
                            .addSkillsResources(skillPaths).build())
                    // 4. 任务清单与用户交互
                    .defaultTools(TodoWriteTool.builder().build())
                    .defaultTools(AskUserQuestionTool.builder()
                            .questionHandler(new CommandLineQuestionHandler())
                            .answersValidation(false)   // 允许自由文本回答
                            .build())
                    // 5. 核心工具:文件、Shell、搜索
                    .defaultTools(FileSystemTools.builder().build())
                    .defaultTools(ShellTools.builder().build())
                    .defaultTools(GrepTool.builder().build())
                    .defaultTools(GlobTool.builder().build())
                    //    SmartWebFetchTool 需要一个独立的 ChatClient 做摘要
                    .defaultTools(SmartWebFetchTool.builder()
                            .chatClient(chatClientBuilder.clone().build())
                            .build())
                    .defaultTools(BraveWebSearchTool.builder()
                            .apiKey(braveApiKey).build())
                    // 6. Advisor:会话记忆(500 条消息窗口)
                    .defaultAdvisors(MessageChatMemoryAdvisor.builder()
                            .maxMessages(500).build())
                    .build();

            // 交互主循环
            System.out.println("I am your assistant.");
            var scanner = new Scanner(System.in);
            while (true) {
                System.out.print("> USER: ");
                String input = scanner.nextLine();
                String answer = chatClient.prompt()
                        .user(input)
                        .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "main"))
                        .call()
                        .content();
                System.out.println(answer);
            }
        };
    }
}

几个值得注意的细节:

  1. 装配顺序有讲究:系统提示词(确立身份)→ 动态工具回调(MCP、Skills)→ 静态工具实例 → Advisor(包裹调用逻辑、管理记忆)。这是官方示例刻意示范的分层。
  2. SmartWebFetchToolchatClientBuilder.clone():它内部需要另一个 LLM 实例把网页内容摘要成 Markdown,克隆 Builder 保证了隔离,不影响主 Agent 配置。
  3. answersValidation(false):让 AskUserQuestionTool 接受预置选项之外的自由文本,CLI 交互更自然。

跑起来之后,你可以让它"帮我看下这个项目的 README 然后总结架构"——它会自己组合 GlobTool 找文件、FileSystemTools 读取、必要时用 TodoWriteTool 拆任务,全程无需你写任何编排代码。编排逻辑完全由 LLM 的工具调用循环驱动,这正是 Agentic 应用的核心特征。

架构拆解

整体架构一张图:

在这里插入图片描述

从上往下四层:

  • 输入层:CLI 交互主循环(也可以换成任何入口);
  • Agent 核心ChatClient + Spring AI 2.0 的 Advisor 链,工具循环由 ToolCallingAdvisor 承载(这是 Spring AI 2.0 最大的架构变化,详见官方发布公告);左侧系统提示词经 AgentEnvironment 注入模型名、Git 状态、知识截止日期等运行时元信息;右侧是分层记忆;
  • 工具层:五大类工具组;
  • 子 Agent 层TaskTool 委派出的隔离执行环境。

四个贯穿全局的架构模式值得单独说:

1. 组合优于继承。高层工具(SkillsToolTaskTool)全部通过组合基础工具实现,没有继承层级——这让每个工具都可以独立替换。

2. 动态工具生成SkillsToolTaskTool 不是静态工具,而是 ToolCallbackProvider 实现:运行时扫描目录里的 Markdown 文件,动态产出工具定义。技能即文件、Agent 即文件,这和 Claude Code 的扩展哲学一脉相承。

3. 隔离上下文窗口。每个子 Agent 拥有独立的 ChatClient 实例,从空历史开始,只把最终结果交还主 Agent——保护主对话不被大量中间过程污染。

4. 回调式集成AskUserQuestionTool 通过 handler 函数把"提问逻辑"与"UI 实现"解耦:CLI 场景传 CommandLineQuestionHandler,换成 Web 前端只需实现自己的 handler。

子 Agent 委派:最值得学的设计

多 Agent 编排是 2026 年 Agent 框架的竞争焦点,agent-utils 用一套非常轻的机制实现了它。

三个核心组件

组件职责
TaskToolCallbackProvider工厂,同时产出 TaskToolTaskOutputTool
TaskTool启动子 Agent,按配置过滤其可用工具
TaskOutputTool检索后台异步任务的结果

用法

// 子 Agent 从主 Builder 克隆,天然隔离
var taskTools = TaskToolCallbackProvider.builder()
        .chatClientBuilder(chatClientBuilder.clone())
        // 自定义子 Agent 定义目录(Markdown 文件)
        .agentDirectories(".claude/agents")
        // 子 Agent 也可以加载技能
        .skillsDirectories(".claude/skills")
        .build()
        .getToolCallbacks();   // TaskTool + TaskOutputTool

ChatClient agent = chatClientBuilder
        .defaultToolCallbacks(taskTools)
        .build();

子 Agent 也是 Markdown

自定义子 Agent 放在 .claude/agents/ 目录,一个 .md 文件就是一个 Agent——YAML front-matter 定义元信息,正文就是它的系统提示词:

---
name: code-reviewer
description: 专注代码审查,输出结构化审查报告
tools: [Read, Grep, Glob]     # 最小权限:只给读和搜索
---

你是一名资深 Java 代码审查员。收到代码后按以下维度输出:
1. 正确性风险  2. 并发问题  3. 性能隐患  4. 风格建议

框架启动时会递归扫描目录、解析 front-matter、注册为可委派的 Agent 类型。工具过滤有两条关键规则:tools() 为空表示全部工具可用;指定了列表则精确匹配、只给子集——这就是按 Agent 粒度的最小权限控制。TaskType 中还有 permissionModeskills() 字段,目前标注"尚未实现",属于预留设计。

隔离到什么程度

维度主 Agent子 Agent
上下文窗口会话内共享每任务专用,从空历史开始
工具访问全部注册工具tools() 过滤
系统提示词MAIN_AGENT_SYSTEM_PROMPT_V2TaskType 正文
会话记忆MessageChatMemoryAdvisor无(除非显式添加)
Advisors完整链最小化集合

还支持异步模式:LLM 调 TaskTool 时传 run_in_background=true,立即拿到任务 ID 继续干别的,之后用 TaskOutputTool 轮询取结果——后台任务存在 TaskRepository(默认内存实现,可替换)。

A2A:委派可以跨进程

多模块结构里有个 spring-ai-agent-utils-a2a 模块,实现了 A2A 协议(Agent2Agent)远程子 Agent——Task 委派的目标不一定是本地进程,可以是另一台机器上用完全不同框架写的 Agent。“Agent 的微服务化”,这就是雏形。A2A 协议本身值得单独写一篇,这里先埋个坑。

逆向工程视角:提示词也是资产

这个项目最有学习价值的部分,其实是 MAIN_AGENT_SYSTEM_PROMPT_V2.md 这个系统提示词模板——它完整展示了 Claude Code 这类产品如何用提示词工程定义 Agent 行为:

  • 环境感知:通过 AgentEnvironment 把模型名、知识截止日期、Git 状态注入提示词,让模型"知道自己是谁、在哪、能用什么";
  • 工具使用指引:明确告诉 LLM 什么时候该用 TaskTool 委派、什么时候直接用 Read/Grep,降低误判;
  • 行为约束:任务规划、进度同步、提问澄清的时机全写进了提示词。

一个顶级 Agent 产品的核心竞争力,一半在模型,一半在提示词。能读到一份工业级的提示词模板并观察它如何与工具体系咬合,是比任何教程都珍贵的学习材料。

局限与展望

客观说几个不足:

  1. 版本 0.x:API 不稳定,permissionMode、子 Agent 级 skills() 等字段尚未实现,生产使用需谨慎锁定版本;
  2. 安全边界依赖自觉ShellToolsFileSystemTools 执行的都是高危操作,沙箱隔离要自己做(对比之下,Spring AI Alibaba 的 Sandbox 组件做了专门设计);
  3. 与 Claude Code 的差距:复刻的是工具体系和提示词设计,Claude Code 的模型侧优化(工具选择的微调、上下文管理策略)依然是不公开的。

但作为 Spring AI 2.0 时代 Agent 工程化的教科书,它的价值已经足够:Builder 模式的工具 API、Markdown 即 Agent 的扩展机制、隔离上下文的多 Agent 委派、A2A 远程协作——这四件事对应着 2026 年 Java Agent 开发的四个核心命题,每个都值得展开写。

小结

spring-ai-agent-utils 证明了"用 Java 造 Claude Code"不是噱头:Spring AI 2.0 把工具循环做进 Advisor 链之后,Agent 的骨架已经就位,剩下的就是工具件与工程化——而这份答卷来自官方社区,可信度拉满。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lbl_lambert

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值