Spring AI 的一些配置类怎么去配置

text 复制代码
ai
├── config
│   ├── AiConfig.java
│   ├── ChatMemoryConfig.java
│   └── VectorStoreConfig.java
│
├── advisor
│   ├── MemoryAdvisor.java
│   └── RagAdvisor.java
│
└── rag
    ├── KnowledgeImporter.java
    └── KnowledgeSearchService.java

这几个类不是 Spring AI 强制要求你必须这样创建。

这是我们为了让一个真实项目:

text 复制代码
配置
业务
RAG
Memory
Advisor

彼此解耦,而设计出来的一种比较合理的目录结构。

下面我就按照一个完整的 IELTS AI Tutor 项目,把每个类到底干什么、为什么需要、里面应该放什么代码、它们之间怎么调用讲清楚。


一、先看整体关系

先不要急着看代码。

这几个类实际上分成 3 层:

text 复制代码
                Spring AI
                    │
       ┌────────────┼────────────┐
       ↓            ↓            ↓
     Config       Advisor        RAG
       │            │             │
       │            │             ├── KnowledgeImporter
       │            │             │
       │            │             └── KnowledgeSearchService
       │            │
       │            ├── MemoryAdvisor
       │            │
       │            └── RagAdvisor
       │
       ├── AiConfig
       ├── ChatMemoryConfig
       └── VectorStoreConfig

简单说:

config

负责:

"这些 AI 基础设施怎么创建?"


advisor

负责:

"AI 请求发送之前/过程中,要自动增加什么能力?"


rag

负责:

"我们的知识怎么导入、怎么搜索?"


二、先从 AiConfig.java 开始

这是整个 AI 模块最基础的配置之一。

例如:

java 复制代码
@Configuration
public class AiConfig {

    @Bean
    public ChatClient chatClient(
            ChatClient.Builder builder
    ) {
        return builder.build();
    }
}

看起来非常简单。

但是它实际上解决了一个重要问题:

text 复制代码
ChatClient

到底由谁创建?


三、为什么要自己配置 ChatClient?

你当然可以直接:

java 复制代码
private final ChatClient chatClient;

但是 Spring 必须知道:

这个 ChatClient Bean 从哪里来?

所以:

java 复制代码
@Bean
public ChatClient chatClient(
        ChatClient.Builder builder
) {
    return builder.build();
}

告诉 Spring:

帮我创建一个 ChatClient,并放到 Spring IOC 容器。

以后:

java 复制代码
@Service
public class AiTutorService {

    private final ChatClient chatClient;

    public AiTutorService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
}

Spring 自动注入。


四、AiConfig 不只是创建 ChatClient

实际项目里可以在这里配置:

text 复制代码
默认 System Prompt
默认 Advisor
默认 Tool

例如:

java 复制代码
@Configuration
public class AiConfig {

    @Bean
    public ChatClient chatClient(
            ChatClient.Builder builder,
            ChatMemory chatMemory
    ) {

        return builder
                .defaultSystem("""
                    你是一名专业的雅思AI教师。

                    你的任务是帮助学生学习雅思。
                    """)
                .defaultAdvisors(
                        MessageChatMemoryAdvisor
                                .builder(chatMemory)
                                .build()
                )
                .build();
    }
}

这样:

java 复制代码
chatClient
    .prompt()
    .user("我雅思阅读5.5怎么办?")
    .call();

自动拥有:

text 复制代码
默认 System Prompt
+
Memory

五、但是我更建议把 AiConfig 控制得简单一点

如果项目越来越大:

java 复制代码
AiConfig

里面不要什么都塞。

例如不要最终变成:

java 复制代码
@Configuration
public class AiConfig {

    // ChatClient

    // Memory

    // Redis

    // VectorStore

    // RAG

    // Tools

    // Prompt

    // Embedding

    // ...
}

这样很快就变成:

AIConfig 巨石类。

所以我们才拆出:

text 复制代码
AiConfig
ChatMemoryConfig
VectorStoreConfig

六、ChatMemoryConfig.java

这个类专门负责:

AI 对话记忆怎么创建、怎么存储。


七、先理解 ChatMemory

例如用户:

text 复制代码
用户:
我雅思阅读5.5。

AI:
你的阅读目前基础已经...

下一句话:

text 复制代码
用户:
那我应该重点练什么?

AI 必须知道:

text 复制代码
"那"

指的是:

text 复制代码
阅读5.5

所以需要保存历史:

text 复制代码
User:
我雅思阅读5.5。

Assistant:
...

User:
那我应该重点练什么?

这就是:

text 复制代码
ChatMemory

八、ChatMemory 最简单的配置

可以先使用内存实现:

java 复制代码
@Configuration
public class ChatMemoryConfig {

    @Bean
    public ChatMemory chatMemory() {
        return new InMemoryChatMemory();
    }
}

这样:

text 复制代码
Spring Boot
    ↓
ChatMemory
    ↓
内存

但是这个只适合:

text 复制代码
开发
测试
Demo

因为:

text 复制代码
应用重启
    ↓
Memory丢失

九、生产环境为什么通常用 Redis?

你的项目本身就很适合 Redis。

架构:

text 复制代码
Vue
 ↓
Spring Boot
 ↓
ChatClient
 ↓
ChatMemory
 ↓
Redis

例如:

text 复制代码
chat:memory:user:10001:conversation:abc123

里面保存:

json 复制代码
[
    {
        "role": "user",
        "content": "我雅思阅读5.5"
    },
    {
        "role": "assistant",
        "content": "..."
    }
]

十、这里有一个非常重要的概念

Conversation ID

例如:

text 复制代码
conversationId = "abc123"

用户第一次:

text 复制代码
POST /ai/chat

conversationId=abc123
message=我雅思阅读5.5

保存:

text 复制代码
abc123
 ↓
消息1
消息2

下一次:

text 复制代码
conversationId=abc123
message=那我应该重点练什么?

系统根据:

text 复制代码
abc123

找到历史。


十一、MemoryConfig 主要负责什么?

你可以把它理解成:

text 复制代码
ChatMemoryConfig
       │
       ├── Memory实现
       │
       ├── 存储方式
       │
       ├── 消息数量
       │
       └── conversation管理

而:

text 复制代码
MemoryAdvisor

负责:

把 Memory 接入 ChatClient。

这两个不要混。


十二、MemoryConfig 和 MemoryAdvisor 的区别

非常重要。

ChatMemoryConfig

负责:

text 复制代码
"Memory是什么?"

例如:

text 复制代码
Redis

MemoryAdvisor

负责:

text 复制代码
"什么时候使用Memory?"

例如:

text 复制代码
每次调用AI之前:
读取历史

AI调用完成:
保存当前消息

所以:

text 复制代码
ChatMemoryConfig
        ↓
   ChatMemory
        ↓
MemoryAdvisor
        ↓
   ChatClient
        ↓
      LLM

十三、MemoryAdvisor.java

这个类的职责就是:

把 ChatMemory 接入 AI 调用流程。

如果你使用 Spring AI 自带的:

java 复制代码
MessageChatMemoryAdvisor

其实你甚至可以不自己写:

text 复制代码
MemoryAdvisor.java

例如直接:

java 复制代码
.defaultAdvisors(
    MessageChatMemoryAdvisor
        .builder(chatMemory)
        .build()
)

所以:

MemoryAdvisor.java 是项目架构中的一个"业务封装类",不是 Spring AI 强制要求的类。


十四、为什么还要自己封装 MemoryAdvisor?

假设你希望统一处理:

text 复制代码
conversationId
userId
历史消息数量
异常处理
日志

你可以自己封装:

java 复制代码
@Component
public class MemoryAdvisor {

    private final ChatMemory chatMemory;

    public MemoryAdvisor(ChatMemory chatMemory) {
        this.chatMemory = chatMemory;
    }

    // 自己的统一逻辑
}

例如:

text 复制代码
用户ID
+
Conversation ID
+
ChatMemory

组合成你自己的上下文体系。


十五、接下来是 VectorStoreConfig

这个是 RAG 的核心基础设施配置。

先理解:

text 复制代码
VectorStore

它负责:

保存向量,并进行相似度搜索。


十六、为什么需要 VectorStore?

假设你有:

text 复制代码
10000篇雅思文章
5000份课程资料
100000道题目

用户问:

判断题为什么不能根据常识判断?

你不可能:

text 复制代码
把所有资料发给AI

所以:

text 复制代码
用户问题
 ↓
VectorStore
 ↓
找最相关的5条
 ↓
交给LLM

十七、VectorStoreConfig 负责什么?

它主要负责:

text 复制代码
VectorStore
    ↓
Embedding Model
    ↓
Vector Database

例如:

text 复制代码
Spring AI
   ↓
VectorStore
   ↓
PGVector

或者:

text 复制代码
Spring AI
   ↓
VectorStore
   ↓
Milvus

或者其他 Spring AI 支持的向量存储。


十八、为什么还需要 EmbeddingModel?

因为:

text 复制代码
文字

不能直接进行向量相似度搜索。

需要:

text 复制代码
文字
 ↓
Embedding Model
 ↓
向量

例如:

text 复制代码
"如何提高雅思阅读速度"

变成:

text 复制代码
[0.123, 0.521, -0.421, ...]

所以:

text 复制代码
VectorStoreConfig

通常会涉及:

text 复制代码
EmbeddingModel
+
VectorStore

十九、一个概念上的配置

例如:

java 复制代码
@Configuration
public class VectorStoreConfig {

    @Bean
    public VectorStore vectorStore(
            EmbeddingModel embeddingModel
    ) {

        return new SomeVectorStore(
                embeddingModel
        );
    }
}

具体实现取决于你选择:

text 复制代码
PGVector
Milvus
Redis
Elasticsearch
Qdrant
Chroma
...

这里不要死记某个具体 Bean,因为不同 Spring AI 版本和不同向量数据库 Starter 的自动配置方式会不同。

你真正需要记的是:

text 复制代码
EmbeddingModel
        ↓
VectorStore
        ↓
RAG

二十、接下来是 RagAdvisor.java

这个和 MemoryAdvisor 非常像。

它的职责:

把 RAG 检索能力接入 ChatClient。

例如:

text 复制代码
用户:
什么是NOT GIVEN?

普通:

text 复制代码
User
 ↓
LLM

RAG:

text 复制代码
User
 ↓
RAG Advisor
 ↓
VectorStore
 ↓
找到相关资料
 ↓
加入上下文
 ↓
LLM

二十一、RagAdvisor具体干什么?

比如:

java 复制代码
@Component
public class RagAdvisor {

    private final VectorStore vectorStore;

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

    public List<Document> search(String query) {

        return vectorStore.similaritySearch(
                SearchRequest.builder()
                        .query(query)
                        .topK(5)
                        .build()
        );
    }
}

它主要负责:

text 复制代码
接收问题
 ↓
查询 VectorStore
 ↓
返回相关 Document

二十二、但这里有一个重要区别

严格来说:

text 复制代码
RagAdvisor

也可以直接使用 Spring AI 已经提供的 RAG Advisor。

也就是说,你不一定要自己写:

text 复制代码
RagAdvisor.java

Spring AI 已经提供了相应的 RAG 抽象和实现。

我们自己创建:

text 复制代码
RagAdvisor.java

主要是为了:

text 复制代码
业务封装
自定义检索
权限过滤
metadata过滤
不同知识库
日志

二十三、例如你有两个知识库

text 复制代码
IELTS
 ├── 阅读知识库
 ├── 写作知识库
 └── 口语知识库

用户问:

如何提高阅读判断题?

你不能让它搜索:

text 复制代码
所有知识库

而应该:

text 复制代码
knowledgeType = READING

然后:

java 复制代码
SearchRequest.builder()
    .query(query)
    .filterExpression(
        "knowledgeType == 'READING'"
    )
    .topK(5)
    .build();

这时候自己封装 RagAdvisor 就非常有意义。


二十四、接下来是 KnowledgeImporter

这个类非常容易被忽略。

它负责:

把你的原始知识资料导入向量数据库。

比如:

text 复制代码
PDF
Word
Markdown
数据库
网页
课程资料

最终:

text 复制代码
原始资料
 ↓
读取
 ↓
切分
 ↓
Document
 ↓
Embedding
 ↓
VectorStore

二十五、为什么需要切分?

例如一个 PDF:

text 复制代码
雅思阅读技巧大全.pdf

可能有:

text 复制代码
300页

你不能直接:

text 复制代码
PDF
 ↓
一个Document

因为太大。

通常需要:

text 复制代码
PDF
 ↓
Document
 ↓
Chunk

例如:

text 复制代码
Chunk 1
雅思阅读主旨题...

Chunk 2
判断题...

Chunk 3
NOT GIVEN...

Chunk 4
匹配题...

二十六、KnowledgeImporter 的完整职责

你可以把它理解成:

text 复制代码
KnowledgeImporter
       │
       ├── 读取文件
       │
       ├── 文档解析
       │
       ├── 文本切分
       │
       ├── 添加Metadata
       │
       ├── Embedding
       │
       └── 写入VectorStore

二十七、一个具体例子

假设:

text 复制代码
/resources/knowledge/reading/not-given.md

内容:

text 复制代码
NOT GIVEN题主要考察...

Importer:

java 复制代码
@Component
public class KnowledgeImporter {

    private final VectorStore vectorStore;

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

    public void importKnowledge(String content) {

        Document document = new Document(content);

        document.getMetadata().put(
                "subject",
                "reading"
        );

        vectorStore.add(
                List.of(document)
        );
    }
}

最终:

text 复制代码
Document
    │
    ├── content
    │
    └── metadata
          └── subject=reading

进入:

text 复制代码
VectorStore

二十八、Metadata 非常重要

这是以后做企业级 RAG 必须掌握的东西。

例如:

text 复制代码
Document

不仅保存:

text 复制代码
content

还可以保存:

json 复制代码
{
  "subject": "reading",
  "type": "course",
  "courseId": 1001,
  "teacherId": 2001,
  "level": "6.5",
  "language": "en"
}

这样用户:

阅读 6 分应该学习什么?

可以过滤:

text 复制代码
subject = reading
level = 6.0

再做语义搜索。


二十九、最后一个:KnowledgeSearchService

这个类和 KnowledgeImporter 正好相反。

KnowledgeImporter

负责:

写进去

KnowledgeSearchService

负责:

查出来

所以:

text 复制代码
KnowledgeImporter
       ↓
VectorStore
       ↑
KnowledgeSearchService

三十、KnowledgeSearchService 具体做什么?

例如:

java 复制代码
@Service
public class KnowledgeSearchService {

    private final VectorStore vectorStore;

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

    public List<Document> search(String query) {

        return vectorStore.similaritySearch(
                SearchRequest.builder()
                        .query(query)
                        .topK(5)
                        .build()
        );
    }
}

调用:

java 复制代码
List<Document> docs =
        knowledgeSearchService.search(
                "为什么NOT GIVEN不能根据常识判断?"
        );

得到:

text 复制代码
Document 1
Document 2
Document 3
Document 4
Document 5

三十一、KnowledgeSearchService 和 RagAdvisor 又有什么区别?

这个一定要分清。

KnowledgeSearchService

负责:

"怎么搜索知识库?"

例如:

java 复制代码
search(query)

RagAdvisor

负责:

"什么时候搜索,以及搜索结果怎么加入 AI 请求?"

所以:

text 复制代码
用户问题
   ↓
RagAdvisor
   ↓
KnowledgeSearchService
   ↓
VectorStore
   ↓
Documents
   ↓
Prompt
   ↓
LLM

三十二、整个 RAG 链路终于完整了

现在把:

text 复制代码
VectorStoreConfig
KnowledgeImporter
KnowledgeSearchService
RagAdvisor

串起来:

text 复制代码
                【知识入库】
                     │
PDF / Word / Markdown
                     ↓
           KnowledgeImporter
                     ↓
             Document切分
                     ↓
               Embedding
                     ↓
                VectorStore
                     │
                     │
                     ↓
                【用户提问】
                     │
                     ↓
                 ChatClient
                     │
                     ↓
                 RagAdvisor
                     │
                     ↓
          KnowledgeSearchService
                     │
                     ↓
                VectorStore
                     │
                     ↓
              相关Documents
                     │
                     ↓
               Prompt增强
                     │
                     ↓
                    LLM

这就是完整的 RAG。


三十三、这几个类之间的关系

现在你应该能看懂整个结构:

text 复制代码
ai
│
├── config
│   │
│   ├── AiConfig
│   │      ↓
│   │   创建ChatClient
│   │
│   ├── ChatMemoryConfig
│   │      ↓
│   │   创建ChatMemory
│   │      ↓
│   │   Redis
│   │
│   └── VectorStoreConfig
│          ↓
│      EmbeddingModel
│          ↓
│      VectorStore
│
├── advisor
│   │
│   ├── MemoryAdvisor
│   │      ↓
│   │   ChatMemory
│   │
│   └── RagAdvisor
│          ↓
│      KnowledgeSearchService
│
└── rag
    │
    ├── KnowledgeImporter
    │      ↓
    │   文档 → VectorStore
    │
    └── KnowledgeSearchService
           ↓
       VectorStore → Documents

三十四、如果按照真实项目,我会稍微调整你的目录

你之前的:

text 复制代码
ai
├── config
├── advisor
└── rag

已经可以。

但随着项目变大,我更推荐:

text 复制代码
ai
├── config
│   ├── AiModelConfig.java
│   ├── ChatClientConfig.java
│   ├── ChatMemoryConfig.java
│   └── VectorStoreConfig.java
│
├── advisor
│   ├── MemoryAdvisor.java
│   ├── RagAdvisor.java
│   └── SecurityAdvisor.java
│
├── prompt
│   ├── reading-analysis.st
│   ├── study-plan.st
│   └── tutor.st
│
├── memory
│   └── ChatMemoryService.java
│
├── rag
│   ├── KnowledgeImporter.java
│   ├── KnowledgeSearchService.java
│   ├── DocumentProcessor.java
│   └── DocumentChunker.java
│
├── tool
│   ├── ScoreTools.java
│   ├── WrongQuestionTools.java
│   └── StudyPlanTools.java
│
└── service
    └── AiTutorService.java

这样职责更加清晰。


三十五、最重要的是不要把这些类理解成"Spring AI规定的固定模板"

这是我特别想提醒你的。

例如:

text 复制代码
AiConfig.java
ChatMemoryConfig.java
VectorStoreConfig.java
MemoryAdvisor.java
RagAdvisor.java
KnowledgeImporter.java
KnowledgeSearchService.java

这些类名都是我们自己定义的。

Spring AI 真正提供的是各种:

text 复制代码
ChatClient
ChatModel
ChatMemory
Advisor
VectorStore
EmbeddingModel
Document
Tool

以及对应的实现和 Starter。

我们创建这些 Java 类,是为了把 Spring AI 的能力组织进我们自己的项目。

所以你应该理解为:

text 复制代码
Spring AI提供能力
       ↓
我们设计项目结构
       ↓
Config负责组装
       ↓
Service负责业务
       ↓
Advisor负责AI调用增强
       ↓
RAG负责知识库
       ↓
Tool负责业务能力

三十六、最终你可以这样理解这几个类

类 核心职责 一句话理解
AiConfig 创建/组装 ChatClient AI总入口怎么配置
ChatMemoryConfig 创建 ChatMemory AI记忆存哪里
VectorStoreConfig 创建 VectorStore AI知识库存哪里
MemoryAdvisor 将 Memory 接入调用链 每次AI调用怎么带历史
RagAdvisor 将 RAG 接入调用链 每次AI调用怎么查知识
KnowledgeImporter 知识入库 资料怎么放进向量库
KnowledgeSearchService 知识检索 怎么从向量库找资料

最终就是:

text 复制代码
                 ChatClient
                     │
             ┌───────┴───────┐
             ↓               ↓
        MemoryAdvisor    RagAdvisor
             ↓               ↓
         ChatMemory     KnowledgeSearch
             ↓               ↓
           Redis        VectorStore
                             ↑
                             │
                    KnowledgeImporter

其中最关键的一条链你要记住:

text 复制代码
KnowledgeImporter
       ↓
VectorStore
       ↓
KnowledgeSearchService
       ↓
RagAdvisor
       ↓
ChatClient
       ↓
LLM

这条链搞明白之后,你对 Spring AI RAG 的整体架构基本就真正入门了。

相关推荐
归秋1421 分钟前
2026企业AI办公工具选型指南:从场景匹配到平台评估
大数据·运维·人工智能
2601_9689007715 分钟前
Agent沙盒基础设施拆解:三层镜像与按需加载的工程取舍
人工智能
楚楚25123 分钟前
2026实测:智能体办公平台三周上手真实体验
人工智能
智圣新创0132 分钟前
教育数据要素流通刚需下 智圣新创高校数据中台解决方案的全域建设落地框架
大数据·人工智能·物联网
xianghongtao011637 分钟前
如何选择一台适合你的本地 AI 硬件设备?Lucy AI Studio——从本地 AI 办公到家庭影音的完整指南
人工智能·端脑科技·本地ai硬件设备·kickstarter众筹项目·lucy ai studio·lucy aios
ZhangJun9543 分钟前
Mobike 共享单车分析项目
人工智能·python·算法·kmeans·聚类·knn
互联网资讯1 小时前
本地创业者入局 AI 短剧,本地化部署怎么选更省钱
大数据·人工智能
唐维康1 小时前
昆工计算机408考研2027招285人,比去年少6人
人工智能·考研·昆明理工大学
Martina_03211 小时前
AI生成的过山车轨道导入后频繁脱轨?用5步检查样条、轨距与碰撞
图像处理·人工智能·游戏·3d·材质·游戏策划·关卡设计
小猴子爱上树1 小时前
跨马翻译:批量图片翻译+视频字幕+智能抠图,跨境电商在线图片翻译工具
大数据·人工智能·python·音视频