哈喽各位后端小伙伴👋,Langchain4j系列第三篇干货如约而至!

前面我们搞定了大模型流式返回ChatMemory多轮对话记忆+会话隔离,现在AI项目还剩下两个绕不开的痛点:

  1. 大模型幻觉严重:回答胡编乱造,不知道公司内部业务文档、私有知识库内容

  2. 上下文窗口有限:无法把几十万字内部文档全部塞进Prompt,Token直接爆表

解决这两个问题的核心方案就是RAG检索增强生成,而RAG架构最核心的底层组件,就是今天要讲的:向量数据库

本文全程避开复杂高数公式,用后端能听懂的大白话讲解,同时附上SpringBoot+Langchain4j+Milvus完整实战代码、全局配置类、RAG完整链路,看完直接可以接入自己的AI项目。


一、有MySQL了,为什么还要向量数据库?

1. 传统MySQL关键词检索的致命短板

我们平时用MySQL做like %关键词%模糊查询,只认字面,不认语义

举个业务真实例子:

  • 库存文档内容:账号冻结如何解除限制

  • 用户提问:我的账号被封禁了怎么办

👉 MySQL查询结果:查不到任何数据

原因:冻结封禁字面完全不一样,MySQL无法识别两者语义相同。

2. 向量数据库的核心能力:语义检索

向量数据库不比对文字是否一样,比对文字的含义是否一样

上面的例子,向量数据库可以精准匹配两条内容,因为语义完全一致。

一句话总结区别: MySQL:找长得一样的文字(精确/模糊匹配) 向量数据库:找意思一样的文字(语义相似度匹配)


二、向量、嵌入向量、向量相似度

1. 什么是向量(Embedding)

大模型里的向量,本质就是一串数字数组

嵌入模型(Embedding模型)可以把任意文本,转换成固定长度的多维数字向量:

  • 账号冻结如何解除限制 → [0.12,0.35,0.88,......]

  • 我的账号被封禁了怎么办 → [0.13,0.34,0.87,......]

意思越相近的文本,生成出来的数字向量越接近。

2. 什么是向量相似度计算

向量数据库内置算法(余弦相似度、欧氏距离),自动计算两个向量之间的距离:

  • 向量距离越小 → 文本语义越相似

  • 向量距离越大 → 文本语义差距越大

3. 完整RAG工作流程(必背)

理解了向量,就能看懂整个私有知识库RAG流程:

  1. 文档切片:把内部PDF、Word、网页长文档,切分成小块文本

  2. 向量化:调用Embedding模型,把每一块文本转为向量

  3. 入库存储:向量+原文存入向量数据库

  4. 用户提问:用户输入问题,同样转为向量

  5. 相似检索:向量数据库快速召回相似度最高的知识库原文

  6. 增强Prompt:把检索到的真实文档+用户问题一起发给大模型

  7. 精准回答:大模型基于私有文档回答,彻底杜绝幻觉


三、主流向量数据库选型对比

向量库

特点

适用场景

Milvus

开源、高性能、支持海量数据、企业级首选

线上生产环境、千万级文档知识库(本文实战选用)

Chroma

轻量、开箱即用、部署简单

本地测试、个人项目、小体量知识库

FAISS

Meta开源,检索速度极快,无持久化

临时检索、内存向量计算,不适合线上持久化

RedisVector

依托Redis,无需额外部署服务

中小体量项目,不想额外部署中间件

生产环境无脑选 Milvus,目前Langchain4j生态适配最好、社区最活跃、并发和检索性能拉满。


四、项目环境准备

1. 依赖引入(整合Langchain4j+Milvus)

<!-- Langchain4j 核心依赖 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-spring-boot-starter</artifactId>
    <version>1.14.0</version>
</dependency>
<!-- 百炼/通义大模型 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-dashscope-spring-boot-starter</artifactId>
    <version>1.14.0</version>
</dependency>
<!-- Milvus向量数据库适配 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-milvus</artifactId>
    <version>1.14.0</version>
</dependency>

2. yml配置文件

spring:
  application:
    name: langchain4j-vector-demo

# 阿里百炼大模型配置
langchain4j:
  dashscope:
    chat-model:
      api-key: 你的百炼key
      model-name: qwen-turbo
    # 嵌入模型:专门用来生成文本向量
    embedding-model:
      api-key: 你的百炼key
      model-name: text-embedding-v3

# Milvus向量数据库连接配置
milvus:
  host: 127.0.0.1
  port: 19530
  database-name: default
  # 知识库集合名称(类似MySQL的表)
  collection-name: ai_knowledge_base

五、全局Milvus向量数据库配置类

统一封装向量库客户端、向量存储仓库、相似度检索参数,业务层无需关心底层连接细节。

import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.store.embedding.milvus.MilvusEmbeddingStore;
import io.milvus.client.MilvusServiceClient;
import io.milvus.param.ConnectParam;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Milvus向量数据库全局配置类
 * 对接Langchain4j,统一管理向量存储、向量检索
 */
@Configuration
@ConfigurationProperties(prefix = "milvus")
@Data
public class MilvusVectorConfig {

    private String host;
    private Integer port;
    private String databaseName;
    private String collectionName;

    /**
     * 构建Milvus客户端连接
     */
    @Bean
    public MilvusServiceClient milvusServiceClient() {
        return new MilvusServiceClient(
                ConnectParam.newBuilder()
                        .withHost(host)
                        .withPort(port)
                        .withDatabaseName(databaseName)
                        .build()
        );
    }

    /**
     * 构建Langchain4j专属向量存储器
     * 自动完成:向量新增、向量相似度检索、文档删除
     */
    @Bean
    public MilvusEmbeddingStore milvusEmbeddingStore(MilvusServiceClient client, EmbeddingModel embeddingModel) {
        return MilvusEmbeddingStore.builder()
                .milvusClient(client)
                .collectionName(collectionName)
                // 检索返回top3相似度最高的文档片段
                .defaultSearchParams("{\"nprobe\": 128}")
                .dimension(1024) // text-embedding-v3向量维度固定1024
                .autoFlushOnInsert(true) // 新增数据自动刷新,立刻可检索
                .build();
    }
}

六、核心业务代码:文档入库 + 语义检索 + RAG问答

1. 封装通用向量知识库Service

import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
import dev.langchain4j.store.embedding.EmbeddingSearchResult;
import dev.langchain4j.store.embedding.milvus.MilvusEmbeddingStore;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 向量知识库服务:文档向量化入库、语义检索、RAG问答
 */
@Service
@RequiredArgsConstructor
public class VectorKnowledgeService {

    // 向量存储器
    private final MilvusEmbeddingStore milvusEmbeddingStore;
    // 嵌入模型:文本转向量
    private final EmbeddingModel embeddingModel;

    /**
     * 1. 上传文档并向量化入库
     * @param content 原始文档全文
     */
    public void importDocument(String content) {
        // 1. 构建文档
        Document document = Document.from(content);
        // 2. 文档切片:长文本切割,避免单次向量过长,重叠部分保证上下文连贯
        DocumentSplitter splitter = DocumentSplitters.recursive(500, 100);
        List<TextSegment> segments = splitter.split(document);
        // 3. 批量向量化并存入Milvus向量数据库
        milvusEmbeddingStore.addAll(segments, embeddingModel);
    }

    /**
     * 2. 根据用户问题,语义检索相关知识库内容
     * @param question 用户提问
     * @return 匹配到的私有文档内容
     */
    public String searchSimilarKnowledge(String question) {
        // 构建检索请求:查询top3最相似内容,相似度阈值0.7,过滤低相关内容
        EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
                .query(question)
                .maxResults(3)
                .minScore(0.7)
                .build();
        // 执行向量检索
        EmbeddingSearchResult<TextSegment> result = milvusEmbeddingStore.search(request, embeddingModel);
        // 拼接检索到的上下文
        return result.matches().stream()
                .map(match -> match.embedded().text())
                .reduce("", String::concat);
    }

    /**
     * 3. 清空当前知识库集合
     */
    public void clearKnowledge() {
        milvusEmbeddingStore.clear();
    }
}

2. RAG问答Service(结合大模型回答问题)

import dev.langchain4j.model.chat.ChatLanguageModel;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class RagChatService {

    private final ChatLanguageModel chatLanguageModel;
    private final VectorKnowledgeService vectorKnowledgeService;

    /**
     * RAG增强问答:基于私有知识库回答问题
     */
    public String ragChat(String question) {
        // 第一步:向量数据库检索私有知识库上下文
        String context = vectorKnowledgeService.searchSimilarKnowledge(question);

        // 第二步:拼接Prompt,约束大模型只能基于知识库回答
        String prompt = String.format("""
                请严格基于下面给出的【知识库上下文】回答用户问题,禁止编造内容。
                如果上下文没有相关信息,请直接回答:暂无相关信息,不要胡说八道。
                【知识库上下文】:%s
                【用户问题】:%s
                """, context, question);

        // 第三步:调用大模型生成答案
        return chatLanguageModel.chat(prompt);
    }
}

3. 对外Controller接口

import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/ai/vector")
@RequiredArgsConstructor
public class VectorController {

    private final VectorKnowledgeService vectorKnowledgeService;
    private final RagChatService ragChatService;

    // 文档入库接口
    @GetMapping("/import")
    public String importDoc(@RequestParam String content) {
        vectorKnowledgeService.importDocument(content);
        return "文档向量化入库成功";
    }

    // RAG知识库问答接口
    @GetMapping("/rag/chat")
    public String ragChat(@RequestParam String question) {
        return ragChatService.ragChat(question);
    }

    // 清空知识库
    @GetMapping("/clear")
    public String clear() {
        vectorKnowledgeService.clearKnowledge();
        return "向量知识库清空成功";
    }
}

七、接口测试流程(直观感受向量检索效果)

第一步:导入私有知识库文档

调用接口导入内容:账号被封禁/冻结,可前往个人中心-安全设置提交申诉,1-3个工作日完成审核解封

第二步:语义提问(字面完全不匹配)

提问:账号被封了怎么解决?

返回结果

账号被封禁/冻结,可前往个人中心-安全设置提交申诉,1-3个工作日完成审核解封。

✅ 向量数据库成功识别语义,字面不一样但意思一致,精准召回文档,MySQL完全做不到。


八、向量数据库常见开发踩坑总结

  1. 向量维度必须和Embedding模型一致:百炼text-embedding-v3固定1024维,写错直接检索报错

  2. 合理设置相似度阈值:建议0.65-0.75,过低会召回无关垃圾文档,过高召回内容太少

  3. 文档必须切片:不要直接把上万字文档直接入库,切片可以提升检索精准度,降低向量生成成本

  4. topN不要设置过大:一般取top3-top5即可,过多上下文会浪费Token、降低回答速度

  5. 向量库和ChatMemory结合使用:RAG知识库检索 + 对话记忆,实现带历史上下文的私有知识库问答

  6. 禁止大模型裸答:生产环境必须拼接检索上下文,从根源杜绝幻觉


九、MySQL、ES、向量数据库三者横向对比

数据库

检索能力

能否语义检索

AI知识库适配度

MySQL

精确匹配、关键词模糊匹配

❌ 不支持

极差,不适合AI语义搜索

ElasticSearch

分词关键词检索

半支持,依赖分词,无法深度语义理解

一般,适合传统全文搜索,不适合大模型RAG

Milvus向量库

向量相似度检索

✅ 原生深度语义理解

满分,RAG架构官方标配


十、博主总结

  1. 向量数据库不是用来替代MySQL,二者各司其职:MySQL存业务结构化数据,向量库存文本向量做语义检索

  2. RAG核心逻辑:向量检索兜底真实数据,大模型负责语言组织,完美解决大模型幻觉

  3. 结合本系列前两篇:流式输出 + ChatMemory会话记忆 + 向量知识库RAG,即可搭建一套完整企业级AI对话系统

  4. 本文全套代码基于Langchain4j原生API开发,无第三方封装,可直接上线生产

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐