Spring AI Agentic Patterns 全景解析:构建企业级智能体的六大核心能力

0 阅读9分钟

从单次对话到持续记忆,从单体Agent到多Agent协作,Spring AI Agent Utils工具包为Java开发者提供了一套完整的智能体构建范式。本文深度解析六大核心模式的设计原理、最佳实践与工程落地要点。

引言:为什么Java开发者需要Agentic Patterns?

大语言模型(LLM)正在从"对话工具"进化为"执行引擎"。然而,将LLM集成到企业应用中并非易事——上下文窗口有限、多步骤任务容易遗漏、跨会话记忆缺失、多Agent协作缺乏标准……这些问题困扰着每一个试图构建生产级AI Agent的开发者。

Spring官方博客近期推出的Agentic Patterns系列文章(共6篇),系统性地回答了这些问题。该系列基于spring-ai-agent-utils工具包,将Claude Code的设计思想移植到Spring AI生态,形成了一套模型无关、可组合、可扩展的智能体构建模式。

本文作为系列综述,将:

  1. 全景式呈现六大模式的核心设计,帮助读者建立系统性认知
  2. 深入剖析工程实现细节,包括版本依赖、配置要点、踩坑指南
  3. 提供组合使用的最佳实践,构建真正可落地的企业级Agent

环境准备

在开始之前,请确保开发环境满足以下要求:

基础环境

组件版本要求说明
JDK17+推荐使用JDK 21(LTS)
Spring Boot3.2+推荐使用3.4.x最新稳定版
Spring AI2.0.0-M2+支持多模型供应商
spring-ai-agent-utils1.0.0+核心工具包

Maven依赖

<dependencies>
    <!-- Spring AI 核心 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-core</artifactId>
        <version>2.0.0-M2</version>
    </dependency>
    
    <!-- Agent Utils 工具包 -->
    <dependency>
        <groupId>org.springframework.experimental.ai</groupId>
        <artifactId>spring-ai-agent-utils</artifactId>
        <version>1.0.0</version>
    </dependency>
    
    <!-- A2A协议支持(可选) -->
    <dependency>
        <groupId>org.springframework.experimental.ai</groupId>
        <artifactId>spring-ai-a2a-server-autoconfigure</artifactId>
        <version>0.2.0</version>
    </dependency>
</dependencies>

💡 提示:各深入系列文章包含更详细的代码示例和配置说明。本文作为综述,聚焦架构设计与模式组合。


系列概览:六大核心能力图谱

篇章核心能力解决的问题关键工具类
Part 1Agent Skills如何让Agent动态加载领域知识?SkillsTool, FileSystemTools, ShellTools
Part 2AskUserQuestionTool如何让Agent主动询问用户需求?AskUserQuestionTool
Part 3TodoWriteTool如何防止多步骤任务遗漏?TodoWriteTool
Part 4Subagent Orchestration如何构建多Agent协作系统?TaskToolCallbackProvider
Part 5A2A Integration如何实现跨平台Agent互操作?spring-ai-a2a-server-autoconfigure
Part 6AutoMemoryTools如何实现跨会话持久记忆?AutoMemoryToolsAdvisor

核心设计理念:六大模式并非孤立存在,而是遵循"感知→规划→执行→协作→记忆"的完整Agent生命周期。下图展示了它们的协作关系:

agent-lifecycle.drawio.png


Part 1: Agent Skills —— 模块化知识注入

核心问题

传统Agent开发中,领域知识往往被硬编码在System Prompt中,导致:

  • 上下文膨胀:所有知识一次性加载,浪费Token
  • 难以维护:修改知识需要重新部署
  • 无法复用:不同项目需要重复编写

设计原理

Agent Skills借鉴了AgentSkills.io规范,采用**渐进式披露(Progressive Disclosure)**策略:

Discovery(发现)→ Activation(激活)→ Execution(执行)
  1. Discovery:启动时仅加载Skill的namedescription,嵌入到Tool Schema中
  2. Activation:当用户请求语义匹配某个Skill时,LLM调用Skill工具加载完整指令
  3. Execution:LLM按指令执行,必要时加载参考文件或执行辅助脚本

工程实现

目录结构

my-skill/
├── SKILL.md          # 必需:指令 + 元数据(YAML frontmatter)
├── scripts/          # 可选:辅助脚本
├── references/       # 可选:参考文档
└── assets/           # 可选:模板、资源

SKILL.md示例

---
name: code-reviewer
description: Reviews Java code for best practices, security issues, and Spring Framework conventions.
---

# Code Reviewer

## Instructions
When reviewing code:
1. Check for security vulnerabilities (SQL injection, XSS, etc.)
2. Verify Spring Boot best practices
3. Look for potential null pointer exceptions
4. Suggest improvements for readability

代码配置

ChatClient chatClient = chatClientBuilder
    .defaultToolCallbacks(SkillsTool.builder()
        .addSkillsDirectory(".claude/skills")
        .build())
    .defaultTools(FileSystemTools.builder().build())
    .defaultTools(ShellTools.builder().build())
    .build();

⚠️ 踩坑指南

问题原因解决方案
脚本执行失败缺少运行时环境预装Python/Node.js等运行时,或使用Docker容器隔离
Skills未加载目录路径错误生产环境使用classpath:资源路径:.addSkillsResource(resourceLoader.getResource("classpath:.claude/skills"))
Token超限Skill指令过长精简SKILL.md,将详细文档放入references/按需加载

版本依赖

  • Spring AI: 2.0.0-M2+
  • spring-ai-agent-utils: 0.4.2+

Part 2: AskUserQuestionTool —— 交互式需求澄清

核心问题

传统AI交互遵循"用户提供Prompt → AI假设 → AI输出"模式。当假设与需求不符时,用户被迫反复修正,浪费时间与上下文。

设计原理

AskUserQuestionTool将Agent从"假设型响应者"转变为"协作型伙伴":

用户请求 → Agent生成澄清问题 → 用户选择/输入 → Agent精准响应

每个问题支持:

  • 单选/多选:通过multiSelect标志控制
  • 自由文本:用户始终可以输入自定义答案
  • 选项描述:每个选项附带说明,帮助用户理解后果

工程实现

配置代码

ChatClient chatClient = chatClientBuilder
    .defaultTools(AskUserQuestionTool.builder()
        .questionHandler(this::handleQuestions)
        .build())
    .build();

QuestionHandler实现(控制台版)

private Map<String, String> handleQuestions(List<Question> questions) {
    Map<String, String> answers = new HashMap<>();
    Scanner scanner = new Scanner(System.in);
    
    for (Question q : questions) {
        System.out.println("\n" + q.header() + ": " + q.question());
        
        for (int i = 0; i < q.options().size(); i++) {
            Option opt = q.options().get(i);
            System.out.printf("  %d. %s - %s%n", i + 1, opt.label(), opt.description());
        }
        
        String response = scanner.nextLine().trim();
        // 解析数字选择或作为自由文本
        // ...
    }
    return answers;
}

与MCP Elicitation的关系

特性AskUserQuestionToolMCP Elicitation
触发方式Agent本地决定MCP Server发起
数据格式预定义选项JSON Schema
适用场景Agent主动澄清服务端需要用户输入

Spring AI同时支持两者——AskUserQuestionTool用于Agent本地交互,@McpElicitation注解用于MCP服务端场景。


Part 3: TodoWriteTool —— 结构化任务追踪

核心问题

研究表明,LLM在长上下文中存在"迷失中间"问题——容易遗忘列表中间的任务项。当Agent同时处理文件编辑、测试执行、文档更新时,关键步骤可能悄然消失。

设计原理

TodoWriteTool的核心约束:同一时刻只能有一个任务处于in_progress状态。这强制Agent顺序执行,而非分散尝试。

任务生命周期:

pending → in_progress → completed
                  ↘ cancelled

工程实现

配置代码

ChatClient chatClient = chatClientBuilder
    .defaultTools(TodoWriteTool.builder().build())
    .defaultAdvisors(
        ToolCallAdvisor.builder().conversationHistoryEnabled(false).build(),
        MessageChatMemoryAdvisor.builder(
            MessageWindowChatMemory.builder().build()).build())
    .build();

⚠️ 关键配置:必须启用ChatMemoryToolCallAdvisor,否则Todo状态无法持久化到对话历史中。

事件驱动的进度更新

ChatClient chatClient = chatClientBuilder
    .defaultTools(TodoWriteTool.builder()
        .todoEventHandler(event ->
            applicationEventPublisher.publishEvent(
                new TodoUpdateEvent(this, event.todos())))
        .build())
    .build();

何时使用?

Tool Schema内置了启发式规则:

"Use this tool when a task requires 3 or more distinct steps."

Agent自主判断是否需要创建任务列表——这是自我治理(Self-Governing) 行为的体现。


Part 4: Subagent Orchestration —— 层级化多Agent架构

核心问题

单体Agent的上下文窗口是有限资源。当Agent需要同时处理代码探索、文件编辑、测试运行、架构规划时,上下文会被无关信息污染,导致性能下降。

设计原理

核心思想:让专业的人做专业的事。将任务委派给专用Subagent,每个Subagent在独立的上下文窗口中执行。

Main Agent (Orchestrator)
    ├── Explore Agent (只读探索)
    ├── Code Agent (读写执行)
    ├── Plan Agent (架构设计)
    └── Bash Agent (命令执行)

内置Subagent

Subagent职责可用工具
Explore快速只读探索代码库Read, Grep, Glob
General-Purpose多步骤研究与执行所有工具
Plan软件架构设计Read-only + search
BashGit操作、构建、终端任务Bash only

工程实现

配置代码

var taskTools = TaskToolCallbackProvider.builder()
    .chatClientBuilder("default", chatClientBuilder)
    .subagentReferences(
        ClaudeSubagentReferences.fromRootDirectory("src/main/resources/agents"))
    .build();

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

自定义Subagent文件(.claude/agents/code-reviewer.md

---
name: code-reviewer
description: Expert code reviewer. Use proactively after writing code.
tools: Read, Grep, Glob
disallowedTools: Edit, Write
model: sonnet
---

You are a senior code reviewer with expertise in software quality.

**When Invoked:**
1. Run `git diff` to see recent changes
2. Focus analysis on modified files
3. Check surrounding code context

多模型路由

根据任务复杂度分配不同模型:

var taskTools = TaskToolCallbackProvider.builder()
    .chatClientBuilder("default", sonnetBuilder)   // 默认
    .chatClientBuilder("haiku", haikuBuilder)      // 快速廉价
    .chatClientBuilder("opus", opusBuilder)        // 复杂分析
    .build();

Subagent通过model字段声明偏好,Task工具自动路由。

⚠️ 重要约束:Subagent不能再创建Subagent(不能将Task放入tools列表),防止无限嵌套。


Part 5: A2A Integration —— 跨平台Agent互操作

核心问题

前四篇关注单Agent能力增强,但企业场景中,Agent往往需要跨越系统边界协作。不同团队、不同平台、不同技术栈的Agent如何互通?

A2A协议简介

Agent2Agent (A2A) Protocol是一个开放标准,基于HTTP、SSE、JSON-RPC构建,提供:

  • Agent Discovery:通过AgentCard(标准JSON文档)发现能力
  • 标准端点/.well-known/agent-card.json暴露Agent元数据
  • 消息交换:JSON-RPC格式的sendMessage请求

Spring AI A2A集成

目前支持服务端集成——将Spring AI Agent暴露为A2A Server:

@Configuration
public class WeatherAgentConfiguration {

    @Bean
    public AgentCard agentCard(@Value("${server.port:8080}") int port,
            @Value("${server.servlet.context-path:/}") String contextPath) {
        return new AgentCard.Builder()
            .name("Weather Agent")
            .description("Provides weather information for cities")
            .url("http://localhost:" + port + contextPath + "/")
            .skills(List.of(new AgentSkill.Builder()
                .id("weather_search")
                .name("Search weather")
                .description("Get temperature for any city")
                .build()))
            .protocolVersion("0.3.0")
            .build();
    }

    @Bean
    public AgentExecutor agentExecutor(ChatClient.Builder chatClientBuilder, 
            WeatherTools weatherTools) {
        ChatClient chatClient = chatClientBuilder.clone()
            .defaultSystem("You are a weather assistant.")
            .defaultTools(weatherTools)
            .build();

        return new DefaultAgentExecutor(chatClient, (chat, requestContext) -> {
            String userMessage = DefaultAgentExecutor
                .extractTextFromMessage(requestContext.getMessage());
            return chat.prompt().user(userMessage).call().content();
        });
    }
}

自动暴露的端点

POST /                              // JSON-RPC sendMessage
GET  /.well-known/agent-card.json   // Agent Card(标准位置)
GET  /card                          // Agent Card(备用位置)

Agent Client示例

Host Agent发现并调用远程Agent:

@Service
public class RemoteAgentConnections {

    private final Map<String, AgentCard> agentCards = new HashMap<>();

    public RemoteAgentConnections(@Value("${remote.agents.urls}") List<String> agentUrls) {
        for (String url : agentUrls) {
            AgentCard card = A2A.getAgentCard(url, 
                path + ".well-known/agent-card.json", null);
            this.agentCards.put(card.name(), card);
        }
    }

    @Tool(description = "Sends a task to a remote agent.")
    public String sendMessage(String agentName, String task) {
        // 使用A2A Java SDK Client发送消息
        // ...
    }
}

未来规划

Spring AI社区正在探索:

  • 客户端自动配置
  • SSE传输支持(流式响应)
  • Spring Boot Actuator集成(可观测性)
  • 安全认证与授权

Part 6: AutoMemoryTools —— 跨会话持久记忆

核心问题

Spring AI的ChatMemory是对话历史窗口——当窗口满时,旧消息被驱逐。即使即将推出的Session API支持递归摘要,精确事实仍会在压缩中丢失

设计原理

ChatMemory vs AutoMemoryTools

维度ChatMemoryAutoMemoryTools
内容完整对话历史精选的持久事实
淘汰滑动窗口驱逐永久保存
更新自动AI模型主动写入
用途当前任务上下文跨会话知识积累

核心理念:AI模型只写入"值得永久保存"的内容——用户偏好、项目决策、行为修正——形成Markdown文件,无限期存活。

记忆类型

类型内容示例写入时机
user角色、目标、沟通风格用户自我介绍时
feedback"停止总结"、"是的,这样对"用户纠正时
project迁移目标、冻结日期项目决策时
referenceLinear看板、Grafana仪表盘发现外部系统时

记忆结构

索引文件(MEMORY.md)

- [User Profile](user_profile.md) — Alice, backend engineer, prefers short answers
- [Feedback Testing](feedback_testing.md) — always use real DB in integration tests
- [Project Auth Rewrite](project_auth.md) — driven by legal compliance, not tech debt

记忆文件(user_profile.md)

---
name: user profile
description: Alice — backend engineer, prefers short answers
type: user
---

Backend engineer named Alice.
Prefers concise, direct responses without trailing summaries.

三种集成方式

方式特点适用场景
Option A: AutoMemoryToolsAdvisor零样板代码,自动注入System Prompt快速上手
Option B: 手动配置AutoMemoryTools完全控制System Prompt结构需要组合自定义Prompt
Option C: FileSystemTools + ShellTools无专用Memory工具,复用现有工具Agent已有文件系统访问能力

Option A示例

ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultAdvisors(
        AutoMemoryToolsAdvisor.builder()
            .memoriesRootDirectory("/home/user/.agent/memories")
            .build(),
        MessageChatMemoryAdvisor.builder(
            MessageWindowChatMemory.builder().maxMessages(100).build()).build(),
        ToolCallAdvisor.builder().disableInternalConversationHistory().build())
    .build();

记忆整理

长期运行后,记忆库会积累冗余、重叠或过时条目。AutoMemoryToolsAdvisor支持自动触发整理

Instant lastInteraction = Instant.now();

AutoMemoryToolsAdvisor.builder()
    .memoriesRootDirectory(memoryDir)
    .memoryConsolidationTrigger((request, instant) -> {
        // 超过60秒无交互时整理
        if (instant.isAfter(lastInteraction.plusSeconds(60))) {
            return true;
        }
        // 用户说bye时整理
        var msg = request.prompt().getLastUserOrToolResponseMessage().getText();
        return msg != null && msg.toLowerCase().contains("bye");
    })
    .build();

组合使用:构建企业级Agent的完整架构

六大模式并非独立使用,而是组合形成完整的Agent能力栈。以下是一个全功能代码助手Agent的配置示例:

@Configuration
public class EnterpriseAgentConfig {

    @Value("${agent.memory.dir}")
    String memoryDir;

    @Bean
    public ChatClient enterpriseAgent(ChatClient.Builder builder) {
        
        // 1. Skills: 动态加载领域知识
        var skillsTool = SkillsTool.builder()
            .addSkillsDirectory(".claude/skills")
            .build();
        
        // 2. TodoWrite: 多步骤任务追踪
        var todoTool = TodoWriteTool.builder()
            .todoEventHandler(this::handleTodoEvent)
            .build();
        
        // 3. AskUserQuestion: 交互式澄清
        var askTool = AskUserQuestionTool.builder()
            .questionHandler(this::handleQuestions)
            .build();
        
        // 4. Subagents: 任务委派
        var taskTools = TaskToolCallbackProvider.builder()
            .chatClientBuilder("default", builder)
            .subagentReferences(
                ClaudeSubagentReferences.fromRootDirectory("src/main/resources/agents"))
            .build();
        
        // 5. AutoMemory: 跨会话记忆
        var memoryAdvisor = AutoMemoryToolsAdvisor.builder()
            .memoriesRootDirectory(memoryDir)
            .memoryConsolidationTrigger(this::shouldConsolidate)
            .build();

        return builder
            .defaultToolCallbacks(skillsTool, taskTools)
            .defaultTools(todoTool, askTool, 
                FileSystemTools.builder().build(),
                ShellTools.builder().build())
            .defaultAdvisors(
                memoryAdvisor,
                ToolCallAdvisor.builder().conversationHistoryEnabled(false).build(),
                MessageChatMemoryAdvisor.builder(
                    MessageWindowChatMemory.builder().maxMessages(100).build()).build())
            .defaultSystem("""
                You are an enterprise code assistant.
                Use Skills for domain expertise.
                Use TodoWrite for complex tasks.
                Use Task tool to delegate to specialists.
                Use AskUserQuestion when requirements are unclear.
                """)
            .build();
    }
}

依赖版本矩阵

组件版本
Spring Boot3.2+
Spring AI2.0.0-M2+
spring-ai-agent-utils1.0.0+
spring-ai-a2a-server-autoconfigure0.2.0+
JDK17+

⚠️ 注意:Spring Boot 4.0尚未发布,当前稳定版本为3.4.x。spring-ai-agent-utils 1.0.0版本已正式发布,建议使用最新稳定版。


总结:从单次对话到持续智能体

Spring AI Agentic Patterns系列揭示了Agent架构的演进路径:

单次对话 → 多轮对话 → 任务执行 → 多Agent协作 → 跨平台协作 → 持续记忆

这套模式的核心价值在于:

  1. 模型无关性:所有工具支持OpenAI、Anthropic、Google Gemini等多供应商
  2. 可组合性:六大模式可独立使用,也可叠加组合
  3. 渐进式复杂度:从简单Skill开始,逐步添加Todo、Subagent、Memory
  4. 企业级就绪:通过Advisor机制集成Spring生态(安全、监控、配置)

对于Java开发者而言,spring-ai-agent-utils工具包提供了一个从Demo到生产的清晰路径。正如高质量代码的特征——可编译、可运行、易维护、有注释——好的Agent架构同样应该:逻辑自洽、执行可靠、结构清晰、意图明确


资源汇总

官方资源

示例项目

示例说明
skills-demoAgent Skills演示
todo-demoTodoWriteTool演示
subagent-demoSubagent编排演示
memory-tools-advisor-demoAutoMemory完整演示

系列原文


参考资料:Spring Blog官方Agentic Patterns系列,作者Christian Tzolov (Part 1-4,6)、Ilayaperumal Gopinathan (Part 5)