Spring AI 手搓 RAG:文档上传 → 向量化 → 检索增强,全链路 Java 实现

上篇写了 Spring AI 多模型切换,这篇补上后半段------RAG 知识库 。不用 Python、不用 LangChain、不用 Milvus,纯 Spring AI + Java 一把梭。 代码已更新 👉 spring-ai-qa-service

整体流程

css 复制代码
上传 PDF/MD/TXT
    ↓
PagePdfDocumentReader / 纯文本读取
    ↓
TokenTextSplitter 分块(按 Token 数切分)
    ↓
DashScopeEmbeddingModel 向量化
    ↓
SimpleVectorStore 存储(本地 JSON 文件)
    ↓
用户提问 → QuestionAnswerAdvisor 检索 Top-K → 注入 Prompt → 大模型回答

1. 文档上传与解析

java 复制代码
public synchronized KnowledgeDocumentInfo upload(MultipartFile file) throws IOException {
    // 校验文件类型:只允许 txt / md / pdf
    String extension = extractExtension(originalFilename);
    if (!ALLOWED_EXTENSIONS.contains(extension)) {
        throw new IllegalArgumentException("不支持的文件类型");
    }

    // 保存到本地
    Path storedPath = storageDirectory.resolve(storedFilename);
    file.transferTo(storedPath);

    // 按类型解析文档
    List<Document> sourceDocuments = readDocuments(storedPath, extension);
    // 分块
    List<Document> chunks = textSplitter.apply(sourceDocuments);
    // 写入向量库
    vectorStore.add(chunks);
}

PDF 用 Spring AI 自带的 PagePdfDocumentReader,纯文本文档直接按段落切分。

2. 向量化(Embedding)

用了通义千问的 DashScope Embedding,和 Chat 共用同一个 API Key,不用额外注册:

java 复制代码
@Bean
@ConditionalOnNonEmptyApiKey(property = "spring.ai.dashscope.api-key", env = "AI_DASHSCOPE_API_KEY")
DashScopeEmbeddingModel ragEmbeddingModel(...) {
    DashScopeApi api = DashScopeApi.builder()
            .apiKey(resolved.apiKey())
            .baseUrl(resolved.baseUrl())
            .build();
    return DashScopeEmbeddingModel.builder()
            .dashScopeApi(api)
            .build();
}

3. 向量存储

选的是 SimpleVectorStore------纯内存 + JSON 文件持久化,零外部依赖:

java 复制代码
@Bean
SimpleVectorStore vectorStore(DashScopeEmbeddingModel embeddingModel, RagProperties props) {
    SimpleVectorStore store = SimpleVectorStore.builder(embeddingModel).build();
    // 启动时从文件恢复
    Path storePath = Path.of(props.storagePath()).resolve("vector-store.json");
    if (Files.exists(storePath)) {
        store.load(storePath.toFile());
    }
    return store;
}

生产环境可以换成 Elasticsearch / PostgreSQL pgvector / Milvus,接口不变,改个 Bean 就行。

4. 检索增强(最核心的一行)

java 复制代码
private ChatClient.CallResponseSpec buildPrompt(ChatClient chatClient, ChatRequest request) {
    var spec = chatClient.prompt()
            .system(isRagMode ? RAG_SYSTEM_PROMPT : DEFAULT_SYSTEM_PROMPT)
            .messages(toMessages(request.history(), request.message()));

    // 如果用户开启了知识库模式,注入 QuestionAnswerAdvisor
    if (isRagMode) {
        VectorStore store = vectorStore.getIfAvailable();
        if (store != null) {
            spec.advisors(new QuestionAnswerAdvisor(
                store,
                SearchRequest.builder().topK(4).build()
            ));
        }
    }
    return spec;
}

QuestionAnswerAdvisor 是 Spring AI 内置的 RAG Advisor------它自动做三件事:

  1. 把用户问题用同一个 Embedding 模型向量化
  2. 在 VectorStore 里检索 Top-K 相似文档块
  3. 把检索结果拼到 Prompt 里作为上下文

你完全不需要写检索逻辑。

5. System Prompt 区分

java 复制代码
// 普通模式
"你是一个有帮助的 AI 助手。用简洁、准确的中文回答。"

// RAG 模式
"你是企业规则问答助手。请优先依据检索到的知识库内容回答。
 若文档中没有相关信息,请明确说明「未在已导入的规则文档中找到依据」,不要编造。"

这是 RAG 落地最关键的一步------告诉模型「不知道就说不知道」,否则它会在检索不到的时候瞎编。

6. 前端知识库面板

Vue 3 写的侧边栏组件 KnowledgePanel.vue

  • 启动时调 /api/rag/status 检查 RAG 是否可用(没配 API Key 就隐藏面板)
  • 支持拖拽/选择文件上传,实时显示文档列表和分块数
  • 聊天框新增「知识库模式」开关,开启后 AI 用 RAG System Prompt

踩坑

  • SimpleVectorStore 的 save/load :需要手动在启动时 load(),关闭时 save()。不 save 的话重启后向量库就没了
  • PDF 解析的依赖PagePdfDocumentReader 需要 pdfbox,pom.xml 里别忘了加
  • Embedding 和 Chat 共用一个 API Key:DashScope 的 Embedding 和 Chat 都走同一个 Key,但自动配置里它们是分开的------Embedding 的自动配置也要排除,自己手动装配

下一步

  • 支持更多文档格式(Word / HTML)
  • 向量库切换为 PostgreSQL pgvector(SimpleVectorStore 适合 Demo,生产量大了内存扛不住)
  • 对话中展示检索到的参考段落

GitHub: github.com/zgqstory/sp...

相关推荐
米小虾1 小时前
Claude Code Loop Engineering 深度解读:从写 Prompt 到设计 Loop
人工智能·agent
科技侃谈1 小时前
上海、安徽、浙江、江苏制造业智能仓储服务商选型指南:机器人零部件企业的破局之选
人工智能
重庆传粉科技2 小时前
传粉科技助力美国房产经纪企业Homequest开拓中国市场
大数据·人工智能
2501_930296992 小时前
模型驱动创作全链路梳理:2026上半年图像与视频生成AI模型全景盘点
人工智能·音视频
Java小白笔记2 小时前
Codex Skills 分类整理
大数据·人工智能·elasticsearch·搜索引擎·ai·ai编程·ai写作
qzhqbb2 小时前
Agent 系统架构与核心技术要点
人工智能·系统架构
love530love2 小时前
用自然语言让 AI Agent 卸载软件 —— 以卸载 Visual Studio 2026 为例
ide·人工智能·windows·agent·visual studio·ai agent·marvis
猿类生物2 小时前
从 Prompt Engineering 到 Loop Engineering:AI 编码的下一个边界
人工智能·ai编程