欢迎光临
我们一直在努力

手把手带你用 Spring AI 2.0 搭建 AI Agent 平台

基于 Spring Boot 4.0.8 + Spring AI 2.0.1 + DeepSeek,从零搭建一个覆盖 Tool Calling、MCP、RAG、ReAct、Skills、安全认证、弹性容错的 AI Agent 平台。115 个测试用例、五层架构、双环境 Profile,跟着做一遍,Spring AI 2.0 核心能力全部落地。

在这里插入图片描述

一、为什么需要这篇教程?

AI Agent 大火的 2026 年,Java 开发者用 Spring AI 搭建 Agent 平台时,往往会撞上三堵墙:

  • 概念太多落不了地:Tool Calling、MCP、RAG、ReAct、Skill、Advisor……每个词都眼熟,串起来就懵;
  • 版本迭代太快:Spring AI 1.x 到 2.0 大量 API 改名,网上搜到的教程一半已过期(比如 CallAroundAdvisor 已废弃、QuestionAnswerAdvisor 被移除);
  • Demo 跑通就没了:示例项目只管"能跑",认证、限流、熔断、追踪、测试全缺位,离生产差着十万八千里。
  • 本文手把手拆解的这个项目(menghan-agent),开源地址:https://gitee.com/zhang-qing521/menghan-agent.git,就是为了把这三堵墙一次性推倒:在一个结构清晰的代码库里覆盖 Spring AI 全部核心能力,同时把平台化必备的安全认证、弹性容错、可观察性、持久化全部补齐。跟着做完,你得到的不是一个玩具 Demo,而是一个可以直接演进的 Agent 平台骨架。

    技术栈一览:

    类别技术选型
    框架 Spring Boot 4.0.8 / Spring AI 2.0.1 / JDK 21+(已在 Java 25 验证)
    大模型 DeepSeek(deepseek-chat / deepseek-reasoner)
    Embedding Transformers ONNX(all-MiniLM-L6-v2,384 维,首次运行自动下载)
    向量库 dev: SimpleVectorStore 内存版;prod: PgVector(HNSW 索引)
    协议 MCP(Model Context Protocol),Server + Client 双端,SSE 传输
    安全 Spring Security + API Key(常量时间比对 + IP 暴力破解防护)
    容错 Resilience4j(限流 / 重试 / 熔断)
    文档 springdoc-openapi(Swagger UI)
    可观察性 Actuator + Micrometer Tracing(Brave) + Zipkin + 结构化日志
    测试 JUnit5 + Mockito + MockMvc + Testcontainers(115 个用例)

    二、平台架构:先把五层分包立起来

    动手写代码前,先定好分层。平台严格按 Controller → Service → Config/Advisor → Tool/Infra → Domain 分包:

    org.menghan.agent
    ├── config/ # AiConfig、AdvisorConfig、ChatMemoryConfig、VectorStoreConfig、SecurityConfig……
    ├── advisor/ # LoggingAdvisor、SafeGuardAdvisor、SkillAdvisor(拦截器链)
    ├── service/ # ChatService、AgentService、RagService、McpClientService
    ├── controller/ # AgentController、McpController、SkillController(带 Swagger 注解)
    ├── tool/ # WeatherTools、CalculatorTools、KnowledgeBaseTools、SkillTools(@Tool)
    ├── infra/ # McpServerTools、SkillRegistry、KnowledgeLoader、GlobalExceptionHandler
    ├── domain/ # dto(请求响应)+ model(WeatherForecast、Skill)
    └── support/ # ApiResult 统一响应包装

    分层的好处在平台化阶段会集中体现:LLM 相关能力全部收敛在 Service + Advisor + Tool 三层,Web 层和业务 POJO 完全不感知 AI 框架的存在,替换模型提供商、增删工具都只动一个包。

    三、手把手搭建:十大核心模块

    3.1 第一步:装配 ChatClient 与 Advisor 链

    Spring AI 2.0 中,ChatClient 是所有交互的入口,而 Advisor(拦截器)是它的灵魂。在 AiConfig 中完成全量装配:

    @Bean
    public ChatClient chatClient(ChatModel chatModel, ChatMemory chatMemory,
    VectorStore vectorStore,
    LoggingAdvisor loggingAdvisor,
    SafeGuardAdvisor safeGuardAdvisor,
    SkillAdvisor skillAdvisor,
    WeatherTools weatherTools,
    CalculatorTools calculatorTools,
    KnowledgeBaseTools knowledgeBaseTools,
    SkillTools skillTools) {

    // 会话记忆:20 条滑动窗口
    MessageChatMemoryAdvisor memoryAdvisor =
    MessageChatMemoryAdvisor.builder(chatMemory).build();

    // RAG:每次请求前自动检索 topK=3 的文档注入上下文
    Advisor ragAdvisor = RetrievalAugmentationAdvisor.builder()
    .documentRetriever(VectorStoreDocumentRetriever.builder()
    .vectorStore(vectorStore)
    .topK(3)
    .build())
    .build();

    return ChatClient.builder(chatModel)
    .defaultSystem(REACT_SYSTEM_PROMPT) // ReAct 系统提示
    .defaultAdvisors(
    safeGuardAdvisor, // order = HIGHEST_PRECEDENCE + 50 最外层:安全
    loggingAdvisor, // order = HIGHEST_PRECEDENCE + 100 次外层:日志
    skillAdvisor, // order = HIGHEST_PRECEDENCE + 150 技能注入
    memoryAdvisor, // 多轮记忆
    ragAdvisor) // 检索增强
    // @Tool 对象 → ToolCallback[],一行完成工具注册
    .defaultToolCallbacks(
    ToolCallbacks.from(weatherTools, calculatorTools,
    knowledgeBaseTools, skillTools))
    .build();
    }

    这一步有几个 2.0 版本的关键变化,都是实际搭建时踩过的坑:

    • 工具回调工具类是 org.springframework.ai.support.ToolCallbacks,包名与 1.x 不同;
    • RAG 用的是 RetrievalAugmentationAdvisor,1.x 的 QuestionAnswerAdvisor 已被移除;
    • ToolCallingAdvisor 不需要手动添加,DefaultChatClient 会自动把它接到链尾,驱动工具调用循环;
    • 自定义 Advisor 的接口是 CallAdvisor / StreamAdvisor,老的 CallAroundAdvisor 已废弃。

    3.2 第二步:用系统提示 + 工具循环实现 ReAct

    Agent 平台的精髓在于自主决策。用一段系统提示引导模型遵循 ReAct 范式:

    你是一个会自主规划的 AI Agent。对每个任务按 ReAct 循环:
    1. Thought: 思考需要哪些信息或动作
    2. Action: 调用合适的工具 (天气查询 / 计算器 / 本地知识库检索 / MCP 远程工具)
    3. Observation: 观察工具返回结果
    4. 重复 1-3 直到有充分依据
    5. Final Answer: 给出最终答案

    规则:
    – 不要臆造未通过工具获取的事实性数据。
    – 若需要多个信息, 分步调用多个工具。
    – 工具调用完毕后, 综合观察结果给出最终答案。

    然后在 AgentService 中把本地工具和远程 MCP 工具合并成一个工具池交给模型:

    public String run(String task, String sessionId) {
    List<ToolCallback> tools = new ArrayList<>(Arrays.asList(
    ToolCallbacks.from(weatherTools, calculatorTools,
    knowledgeBaseTools, skillTools)));
    // 远程 MCP 工具(可选注入,client 关闭时为空列表)
    for (ToolCallbackProvider provider : mcpProviders) {
    tools.addAll(Arrays.asList(provider.getToolCallbacks()));
    }

    return chatClient.prompt()
    .user(task)
    .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, sessionId))
    .toolCallbacks(tools.toArray(new ToolCallback[0]))
    .call()
    .content();
    }

    效果是什么?用户发一句"查一下上海的天气,再帮我算 45 加 55 等于多少",模型会自主决定:先调天气工具 → 观察结果 → 再调计算器 → 综合两次观察输出最终答案。整个循环不需要你写任何编排代码,ToolCallingAdvisor 会在"模型请求工具 → 执行工具 → 回填结果 → 再次请求模型"之间自动轮转,直到模型不再请求工具。

    3.3 第三步:Advisor 洋葱模型,安全日志各就各位

    自定义 Advisor 通过 getOrder() 控制位置,形成洋葱式拦截:

    AdvisorOrder职责
    SafeGuardAdvisor HIGHEST_PRECEDENCE + 50 最外层,越狱/敏感关键词拦截
    LoggingAdvisor HIGHEST_PRECEDENCE + 100 全链路入参、出参、耗时记录
    SkillAdvisor HIGHEST_PRECEDENCE + 150 关键词命中后注入技能指令
    MessageChatMemoryAdvisor 多轮会话记忆
    RetrievalAugmentationAdvisor RAG 检索

    把安全放在最外层,意味着任何被拦截的恶意请求根本不会进入日志、记忆、LLM 调用,既省 token 又防注入。

    3.4 第四步:Skills —— Tool、RAG 之外的第三种能力

    这是平台化过程中最有价值的一个模块。Agent 有三类知识:

    • Tool(工具):可执行的动作,如"查天气";
    • RAG(检索):静态事实知识,如文档片段;
    • Skill(技能):程序性知识,即"做某类任务的标准工作流程",如"怎么做代码审查"“怎么优化 SQL”。

    技能用 Markdown 文件定义(YAML frontmatter + 正文指令),平台上线后新增技能只需加文件、零代码改动、零重启发版:


    name: code-review
    description: 代码审查工作流
    keywords: 代码审查, code review, review, CR

    审查代码时按以下顺序检查:
    1. 正确性:边界条件、空值、并发……
    2. 安全性:输入校验、权限、注入……
    3. 可维护性:命名、重复、圈复杂度……

    SkillAdvisor 实现"被动注入"——用户输入命中关键词,自动把技能指令拼进系统提示。这里有一个 Spring AI 2.0.1 的大坑,搭建时务必注意:

    // ⚠️ 注意:augmentSystemMessage(String) 是【替换】语义(mutate().text(…)),
    // 直接传字符串会把原有系统提示整个覆盖掉!
    // 必须用 Function 重载,先读原文本再拼接:
    Prompt augmented = request.prompt().augmentSystemMessage(sm -> sm.mutate()
    .text((sm.getText() == null ? "" : sm.getText()) + injection)
    .build());
    return request.mutate().prompt(augmented).build();

    这种官方文档语焉不详的版本陷阱,恰恰是跟着完整项目搭建一遍才能避开的。此外还有"主动读取"路径:SkillTools.readSkill(name) 暴露为 @Tool,模型在 ReAct 循环中可以自己决定按名加载技能。

    3.5 第五步:MCP —— 把工具能力标准化、跨进程化

    MCP(Model Context Protocol)是 2025 年以来 AI 工具生态的事实标准。平台同时实现双端:

    Server 端——用 @McpTool 注解,方法自动通过 /sse 端点暴露给 Claude Desktop 等外部客户端:

    @Component
    public class McpServerTools {

    @McpTool(description = "获取当前服务器时间, 用于演示 MCP server 暴露工具")
    public String serverTime() {
    return LocalDateTime.now().toString();
    }

    @McpTool(description = "生成指定长度的随机字符串")
    public String randomString(
    @McpToolParam(description = "结果字符串长度, 范围 1-64", required = true) int length) {
    int len = Math.max(1, Math.min(64, length));
    return UUID.randomUUID().toString().replace("-", "").substring(0, len);
    }
    }

    Client 端——消费远程 MCP Server 的工具,自动包装成 ToolCallbackProvider Bean,合入 3.2 节 AgentService 的工具池。本地工具和跨进程工具在模型眼里毫无差别,这就是协议标准化的威力:你的平台从此可以接入整个 MCP 工具生态。

    3.6 第六步:RAG —— 双模式检索 + 双向量库

    RAG 做了两条路径,覆盖不同场景:

    • 被动 RAG:RetrievalAugmentationAdvisor 在每次请求前自动检索,模型无感知;
    • 主动 RAG:KnowledgeBaseTools 是一个 @Tool,模型在需要时显式调用检索。

    知识库在启动时由 KnowledgeLoader 从 classpath:data/*.md 加载切片入向量库。向量库按环境切换,这是平台能"开发零依赖、生产可持久化"的关键:

    • dev:SimpleVectorStore 内存实现(@Profile("!prod")),clone 即跑;
    • prod:PgVector,HNSW 索引 + cosine 距离 + 384 维,持久化到 PostgreSQL。

    3.7 第七步:结构化输出与流式,两个一行 API

    // 结构化:LLM 返回的 JSON 直接反序列化为 Java record,类型安全
    public WeatherForecast structured(String city) {
    return chatClient.prompt()
    .user("查询 " + city + " 的天气, 请以结构化对象返回……")
    .call()
    .entity(WeatherForecast.class); // ← 关键 API
    }

    // 流式:Flux<String> 天然适配 SSE 打字机效果
    public Flux<String> stream(String message, String sessionId) {
    return chatClient.prompt()
    .user(message)
    .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, sessionId))
    .stream()
    .content();
    }

    WeatherForecast 是一个 record,包含城市、温度、天气状况、湿度、穿衣建议——非结构化文本到类型安全对象的转换,框架全包了。

    3.8 第八步:生产安全 —— API Key 认证的四个细节

    平台要对外提供服务,认证是绕不过去的。SecurityConfig 仅在 prod profile 激活,四个细节缺一不可:

  • 常量时间比对防时序攻击(CWE-208):不用 String.equals,而用 MessageDigest.isEqual 逐字节比较,避免攻击者通过响应耗时差异逐位猜出 Key;
  • IP 级暴力破解防护:同一 IP 连续失败 10 次直接返回 429,计数用 Caffeine 缓存、TTL 5 分钟自动驱逐(防内存泄漏 + 给冷却机会);
  • 真实 IP 提取:依次解析 X-Forwarded-For(取代理链第一个)、X-Real-IP、remoteAddr,兼容 K8s/Nginx 反代;
  • 启动即校验:API Key 为空还是默认占位值 change-me-in-production 时直接拒绝启动,杜绝"忘配置就裸奔上线"。
  • 另外无状态会话(STATELESS)、HSTS、CSP、X-Frame-Options: DENY 等安全响应头一应俱全;CSRF 禁用也附带了依据(无状态 API Key 认证不依赖 Cookie,无 CSRF 攻击向量,注释里直接贴了 Spring Security 官方文档链接)。

    3.9 第九步:弹性容错 —— 三个注解守住 LLM 调用

    LLM 调用慢、贵、还会抖。ChatService 上叠加 Resilience4j 三件套:

    @RateLimiter(name = "llm-rate-limit") // 限流:20 次/秒
    @Retry(name = "llm-retry") // 重试:3 次,指数退避 1s→2s→4s,仅网络/超时异常
    @CircuitBreaker(name = "llm-circuit-breaker") // 熔断:50% 失败率开启,30s 后半开恢复
    public String chat(String message, String sessionId) { ... }

    一个容易写错的细节:流式接口不加 @Retry——Flux 的中间状态不可重放,重试会导致内容重复,所以流式方法只保留限流和熔断。

    3.10 第十步:可观察性与测试保障

    • Actuator:/actuator/health 内置 liveness/readiness 探针,直接对接 K8s;
    • 分布式追踪:Micrometer Tracing(Brave) + Zipkin Reporter,采样率可配(默认 0.1);
    • 结构化日志:logback-spring.xml 中 prod 环境输出 JSON;
    • 测试:115 个用例覆盖 domain / tool / advisor / service / controller / infra / config 全部分层,另有 5 个 Testcontainers 集成测试用真实 PostgreSQL + PgVector 验证检索链路。纯单元测试不启动 Spring 上下文,3 秒跑完。

    四、平台 API 一览

    方法路径说明
    POST /api/chat 多轮对话(20 条滑动窗口记忆)
    POST /api/agent ReAct Agent 工具调用(本地 + MCP)
    POST /api/rag RAG 知识库问答
    GET /api/structured?city=北京 结构化输出 WeatherForecast
    GET /api/stream?message=你好&sessionId=s1 SSE 流式输出
    GET /api/skills、/api/skills/{name} 技能列表 / 详情
    POST /api/skills/match 关键词匹配演示(不调 LLM,免 Key 验证)
    GET/POST /api/mcp/tools、/api/mcp/call 远程 MCP 工具发现与调用
    GET /swagger-ui.html 在线接口文档(内置 X-API-Key 调试)

    五、三分钟把平台跑起来

    # 1. 准备 JDK 21+、Maven 3.9+,申请 DeepSeek API Key
    # https://platform.deepseek.com/api_keys

    # 2. 设置 Key(Windows PowerShell)
    $env:DEEPSEEK_API_KEY="sk-你的key"

    # 3. 启动(默认 dev profile:内存向量库、免认证、免 PostgreSQL)
    mvn spring-boot:run

    # 4. 验证
    curl http://localhost:8087/actuator/health
    curl -X POST http://localhost:8087/api/chat `
    -H "Content-Type: application/json" `

    -d '{"message":"你好","sessionId":"s1"}'

    生产部署切换 SPRING_PROFILES_ACTIVE=prod 即可:API Key 认证、PgVector 持久化、JSON 日志、CORS 白名单自动生效,项目自带 Dockerfile、docker-compose.yml(含 pgvector)和 DEPLOYMENT.md。

    六、建议的动手路线

  • 先跑通:按第五节启动,依次试 /api/chat → /api/agent(观察模型怎么自己选工具)→ /api/stream;
  • 读装配:AiConfig,理解 Advisor 链怎么像洋葱一样层层包裹;
  • 写 Advisor:照着 SafeGuardAdvisor 和 SkillAdvisor,实现 CallAdvisor/StreamAdvisor 双接口加一个自己的拦截器;
  • 接 MCP:读 McpServerTools + McpClientService,把你的一个内部系统能力通过 MCP 暴露出去;
  • 补生产能力:对照 SecurityConfig 的 ApiKeyFilter 和 ChatService 的三个注解,检查自己项目的认证与容错缺口;
  • 扩技能:往 resources/skills/ 丢一个自己的 SKILL.md,零代码体验平台热扩展。
  • 七、总结

    跟着这套骨架搭完,你会发现一个 Agent 平台的核心并不神秘:

    • 交互层:ChatClient + Advisor 洋葱链,横切关注点(安全、日志、记忆、检索)全部可插拔;
    • 能力层:@Tool 本地工具 + MCP 远程工具 + Skill 程序性知识,三类能力统一编排;
    • 知识层:RAG 双模式检索 + dev/prod 双向量库;
    • 保障层:API Key 认证、Resilience4j 容错、Micrometer 追踪、115 个测试兜底。

    AI 时代,Java 工程师不需要转 Python 才能做 Agent。Spring AI 2.0 已经把平台级能力准备妥当,差的只是一个把这些能力串起来、且认真对待生产细节的参考实现——希望这个项目能成为你搭建自己 Agent 平台的起点。

    项目 MIT 协议开源,欢迎 Star、Fork、提 Issue 交流。你的每一个 ⭐ 都是作者继续更新的动力!


    技术栈:Spring Boot 4.0.8 · Spring AI 2.0.1 · DeepSeek · MCP · PgVector · Resilience4j · Spring Security

    赞(0)
    未经允许不得转载:171主机测评 » 手把手带你用 Spring AI 2.0 搭建 AI Agent 平台
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址