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...

相关推荐
shdwak....sad20 小时前
版本管理&迁移kali-vmware&知识库
人工智能·网络安全
程序员cxuan20 小时前
OpenAI Linux 版来了!
人工智能·后端·程序员
用户56190350693320 小时前
OpenAI兼容API报401/404/429怎么解决?API Key、Base URL、模型名排查
人工智能
lucky_syq20 小时前
专栏目录与学习路线 | 48 篇正文导览
人工智能·学习
TechEdu20260620 小时前
[人工智能]RLlib:基于Ray的可扩展强化学习框架
人工智能·ai
加多20 小时前
DeepSeek Harness 深度分析:用途、问题、架构原理与使用指南
人工智能·架构
风流 少年21 小时前
Spring AI 2.0:Flux
java·人工智能·spring
小马过河R21 小时前
Graph Engineering 深度解析:模型越强,越需要给它画好“地图”
人工智能·langchain·graph·ai工程化·harness·驾驭工程
leisoo809721 小时前
涨停板次日表现因子怎么挖掘本地化Python全流程实战
大数据·人工智能·python
lucas_AI21 小时前
喂张白纸也能吐出证件号?文档 MLLM 的"关系级泄露"被测出来了
人工智能·算法·掘金技术征文