Skip to content

Spring Boot + Spring AIRAGAgent 与稳健性治理

当聊天接口、流式输出、工具调用和知识库问答已经跑通后,项目通常会继续往两个方向演进:

  1. 让模型能基于企业知识回答,也就是 RAG
  2. 让模型能做多步任务执行,也就是 Agent

但真正落地时,更容易踩坑的地方反而在后面:

  1. 召回是否稳定
  2. 工具调用是否可控
  3. Agent 是否会失控
  4. 项目是否具备限流、超时、审计和降级能力

如果你现在更关心知识库里的 分片Embedding、召回、Rerank 和向量数据库选型,建议看:

这篇会把 RAGAgent 和“能上线”的治理能力放在一起讲,更偏第三阶段的整体配合和工程边界。

1. RAG 在 Spring AI 里最小怎么落

最常见的最小组成通常是:

  1. EmbeddingModel
  2. VectorStore
  3. 文档导入
  4. 相似度检索
  5. 把检索结果拼进 Prompt

1.1 一个最小文档导入示例

java
package com.example.ai.rag;

import java.util.List;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

/**
 * 应用启动时向向量库导入演示文档。
 */
@Component
public class DemoDocumentLoader implements CommandLineRunner {

    private final VectorStore vectorStore;

    public DemoDocumentLoader(VectorStore vectorStore) {
        this.vectorStore = vectorStore;
    }

    @Override
    public void run(String... args) {
        vectorStore.add(List.of(
                new Document("Redis 支持 string、list、set、zset、hash 等数据结构。"),
                new Document("MySQL 的 MVCC 是多版本并发控制机制。")
        ));
    }
}

1.2 一个最小 RAG Service

java
package com.example.ai.service;

import java.util.stream.Collectors;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Service;

/**
 * 最小检索增强问答服务。
 */
@Service
public class RagService {

    private final ChatClient chatClient;
    private final VectorStore vectorStore;

    public RagService(ChatClient.Builder chatClientBuilder, VectorStore vectorStore) {
        this.chatClient = chatClientBuilder.build();
        this.vectorStore = vectorStore;
    }

    /**
     * 先检索,再基于检索结果生成答案。
     *
     * @param question 用户问题
     * @return 检索增强后的答案
     */
    public String ask(String question) {
        var request = SearchRequest.builder()
                .query(question)
                .topK(3)
                .build();

        var documents = vectorStore.similaritySearch(request);
        String context = documents.stream()
                .map(Document::getText)
                .collect(Collectors.joining("\n"));

        return chatClient.prompt()
                .system("请优先基于资料回答。如果资料不足,要明确说明。")
                .user("""
                        问题:
                        %s

                        资料:
                        %s
                        """.formatted(question, context))
                .call()
                .content();
    }
}

2. 一条完整的 RAG 链路怎么理解

mermaid
flowchart TD
    A[原始文档] --> B[清洗与切分]
    B --> C[生成 Embedding]
    C --> D[写入 VectorStore]
    E[用户问题] --> F[检索相似文档]
    F --> G[选出 TopK 上下文]
    G --> H[拼接 Prompt]
    H --> I[模型生成答案]

这张图最想表达的是:

  1. VectorStore 只是其中一环
  2. 真正的 RAG 不只是“连上一个向量库”
  3. 文档准备、检索、上下文拼接都会直接影响效果

3. Agent 在 Spring Boot 项目里怎么理解

不要一上来把 Agent 理解成一个神秘的大系统。

更贴近工程的理解是:

让模型在一次任务里,不只回答,还能根据目标多步调用工具、查询资料并逐步推进。

在 Spring Boot 项目里,它通常还是会落到:

  1. 一个 Service 负责整体执行主线
  2. Tool Bean 负责外部动作
  3. 必要时加状态、上下文和审计

3.1 一个简化的 Agent Service 骨架

java
package com.example.ai.service;

import com.example.ai.tool.OrderTools;
import com.example.ai.tool.WeatherTools;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;

/**
 * 简化的多工具 Agent 服务。
 */
@Service
public class AgentService {

    private final ChatClient chatClient;
    private final WeatherTools weatherTools;
    private final OrderTools orderTools;

    public AgentService(
            ChatClient.Builder chatClientBuilder,
            WeatherTools weatherTools,
            OrderTools orderTools) {
        this.chatClient = chatClientBuilder.build();
        this.weatherTools = weatherTools;
        this.orderTools = orderTools;
    }

    /**
     * 让模型在多工具上下文中回答复杂问题。
     *
     * @param task 用户任务
     * @return 模型生成结果
     */
    public String run(String task) {
        return chatClient.prompt()
                .system("你是一名可以按需要调用工具解决任务的企业助手。")
                .user(task)
                .tools(weatherTools, orderTools)
                .call()
                .content();
    }
}

这段代码故意保持最小,因为这里真正要传达的是:

  1. Agent 不一定意味着另一套框架
  2. 在项目初期,它完全可以长在普通 Spring Service 里

4. RAGAgent 在项目里通常怎么配合

很多项目最后不是“只要 RAG”或者“只要 Agent”,而是两者一起出现。

更常见的组合方式是:

  1. RAG 负责提供知识上下文
  2. Agent 负责做多步任务和工具调用

4.1 一张组合流程图

mermaid
flowchart TD
    A[用户任务] --> B{是否需要外部知识}
    B -- 是 --> C[RAG 检索上下文]
    B -- 否 --> D[直接进入 Agent 执行]
    C --> D
    D --> E{是否需要工具调用}
    E -- 是 --> F[调用 Tool / MCP / 外部系统]
    E -- 否 --> G[直接生成答案]
    F --> H[整合工具结果]
    H --> G

5. 一个聚合 Controller 骨架

java
package com.example.ai.web;

import com.example.ai.service.AgentService;
import com.example.ai.service.RagService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * RAG 与 Agent 示例接口。
 */
@RestController
public class AiAdvancedController {

    private final RagService ragService;
    private final AgentService agentService;

    public AiAdvancedController(RagService ragService, AgentService agentService) {
        this.ragService = ragService;
        this.agentService = agentService;
    }

    @GetMapping("/demo/ai/rag")
    public String rag(@RequestParam String q) {
        return ragService.ask(q);
    }

    @GetMapping("/demo/ai/agent")
    public String agent(@RequestParam String q) {
        return agentService.run(q);
    }
}

6. 什么叫“能跑”,什么叫“能上线”

很多 Spring AI 项目真正的分水岭不在功能,而在治理。

6.1 “能跑”通常只意味着

  1. 接口能返回答案
  2. 工具能被调用
  3. 检索能查到文档

6.2 “能上线”通常还要继续补

  1. 超时控制
  2. 限流
  3. 重试与降级
  4. 审计日志
  5. 安全与权限控制
  6. 敏感信息保护
  7. 监控与告警
  8. 成本观测

7. 在 Spring Boot 项目里,这些治理点通常补在哪

能力常见落点
限流网关、Controller 前置层、服务保护层
超时模型调用客户端、外部工具客户端
重试外部工具调用层,不要对有副作用的动作盲目重试
审计Service / Tool 调用链路日志
权限控制Spring Security + 业务权限层
监控Actuator、Micrometer、日志与 tracing

8. 第三阶段最容易踩的坑

8.1 以为有 VectorStore 就等于有 RAG

真正决定效果的还有:

  1. 文档质量
  2. 切分策略
  3. 上下文拼接
  4. 是否做过滤和精排

8.2 把 Agent 当成“自动就很聪明的执行器”

没有边界约束的 Agent,更容易出现:

  1. 工具乱调
  2. 成本暴涨
  3. 执行不稳定

8.3 工具、检索、生成都混在一个大 Service 里

这样很快就会:

  1. 不好维护
  2. 不好测试
  3. 不好排障

9. 这一篇最重要的结论

RAG 负责把知识带进回答过程,Agent 负责让系统能做多步任务执行,但这两者真正落到 Spring Boot 项目里,最终仍然要回到普通的工程问题:分层是否清楚、工具是否可控、检索是否稳定、治理是否补齐。真正能把项目从 demo 带到线上环境的,往往不是更多功能,而是更稳的边界和更完整的治理链路。

基于 VitePress 构建的个人技术笔记。