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

相关推荐
迪菲赫尔曼6 小时前
【基础篇 26】第一次在服务器完成训练:准备数据、断线继续、检查成果与备份
运维·服务器·人工智能·机器学习·计算机视觉
小年糕是糕手6 小时前
【AI】用 AI 做自己的个人网站(上):选模板、写提示词,做出第一版
人工智能·app·网页开发·codex·index·styles·0基础教程
硅谷秋水6 小时前
RoboAtom:机器人学习的大规模原子-动作监督
人工智能·机器学习·计算机视觉·机器人
vipxieliang6 小时前
具身智能2026:从实验室演示到万台级量产
人工智能
lucas_AI6 小时前
花旗银行教你算 AI 的账:省下的时间要和审查成本、残余风险记在同一本账上
人工智能
lucas_AI7 小时前
没人教过它化学立体几何,但它悄悄学会了:前沿 LLM 排构象已经超过经典力场
人工智能
kaixin_啊啊7 小时前
【零基础学AI】第 26 章——注意力机制怎样工作
人工智能
硅谷秋水7 小时前
OpenRUA 方法分析
人工智能·机器学习·语言模型·机器人