Appearance
Spring Boot + Spring AI:RAG、Agent 与稳健性治理
当聊天接口、流式输出、工具调用和知识库问答已经跑通后,项目通常会继续往两个方向演进:
- 让模型能基于企业知识回答,也就是
RAG - 让模型能做多步任务执行,也就是
Agent
但真正落地时,更容易踩坑的地方反而在后面:
- 召回是否稳定
- 工具调用是否可控
- Agent 是否会失控
- 项目是否具备限流、超时、审计和降级能力
如果你现在更关心知识库里的 分片、Embedding、召回、Rerank 和向量数据库选型,建议看:
这篇会把 RAG、Agent 和“能上线”的治理能力放在一起讲,更偏第三阶段的整体配合和工程边界。
1. RAG 在 Spring AI 里最小怎么落
最常见的最小组成通常是:
EmbeddingModelVectorStore- 文档导入
- 相似度检索
- 把检索结果拼进 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[模型生成答案]这张图最想表达的是:
VectorStore只是其中一环- 真正的 RAG 不只是“连上一个向量库”
- 文档准备、检索、上下文拼接都会直接影响效果
3. Agent 在 Spring Boot 项目里怎么理解
不要一上来把 Agent 理解成一个神秘的大系统。
更贴近工程的理解是:
让模型在一次任务里,不只回答,还能根据目标多步调用工具、查询资料并逐步推进。
在 Spring Boot 项目里,它通常还是会落到:
- 一个 Service 负责整体执行主线
- Tool Bean 负责外部动作
- 必要时加状态、上下文和审计
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();
}
}这段代码故意保持最小,因为这里真正要传达的是:
Agent不一定意味着另一套框架- 在项目初期,它完全可以长在普通 Spring Service 里
4. RAG 和 Agent 在项目里通常怎么配合
很多项目最后不是“只要 RAG”或者“只要 Agent”,而是两者一起出现。
更常见的组合方式是:
RAG负责提供知识上下文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 --> G5. 一个聚合 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 “能跑”通常只意味着
- 接口能返回答案
- 工具能被调用
- 检索能查到文档
6.2 “能上线”通常还要继续补
- 超时控制
- 限流
- 重试与降级
- 审计日志
- 安全与权限控制
- 敏感信息保护
- 监控与告警
- 成本观测
7. 在 Spring Boot 项目里,这些治理点通常补在哪
| 能力 | 常见落点 |
|---|---|
| 限流 | 网关、Controller 前置层、服务保护层 |
| 超时 | 模型调用客户端、外部工具客户端 |
| 重试 | 外部工具调用层,不要对有副作用的动作盲目重试 |
| 审计 | Service / Tool 调用链路日志 |
| 权限控制 | Spring Security + 业务权限层 |
| 监控 | Actuator、Micrometer、日志与 tracing |
8. 第三阶段最容易踩的坑
8.1 以为有 VectorStore 就等于有 RAG
真正决定效果的还有:
- 文档质量
- 切分策略
- 上下文拼接
- 是否做过滤和精排
8.2 把 Agent 当成“自动就很聪明的执行器”
没有边界约束的 Agent,更容易出现:
- 工具乱调
- 成本暴涨
- 执行不稳定
8.3 工具、检索、生成都混在一个大 Service 里
这样很快就会:
- 不好维护
- 不好测试
- 不好排障
9. 这一篇最重要的结论
RAG 负责把知识带进回答过程,Agent 负责让系统能做多步任务执行,但这两者真正落到 Spring Boot 项目里,最终仍然要回到普通的工程问题:分层是否清楚、工具是否可控、检索是否稳定、治理是否补齐。真正能把项目从 demo 带到线上环境的,往往不是更多功能,而是更稳的边界和更完整的治理链路。