LangChain4j(7):Springboot集成LangChain4j实现知识库RAG

我们之前的直接整合进SpringBoot进行实战,最终其实还会将查询到的内容,和对话上下文组合起来,发给LLM为我们组织语言进行回答:

  1. 配置一个Content Retriever 内容检索器,提供向量数据库和向量模型及其他参数
  2. 将内容检索器绑定到AiServices
  3. 当我们进行LLM对话时,底层会自动为我们检索向量数据库进行回答

基于之前的springboot进行添加:

在Aiconfig中添加Assistant:

    public interface Assistant{
        String chat(String message);
        // 流式响应
        TokenStream stream(String message);
    }

    @Bean
    public EmbeddingStore embeddingStore() {
        return new InMemoryEmbeddingStore();
    }

    @Bean
    public Assistant assistant(ChatLanguageModel qwenChatModel,
                               StreamingChatLanguageModel qwenStreamingChatModel,
                               ToolsService toolsService,
                               EmbeddingStore embeddingStore,
                               QwenEmbeddingModel qwenEmbeddingModel
    ) {
        // 对话记忆
        ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);

        // 内容检索器
        ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
                .embeddingStore(embeddingStore)
                .embeddingModel(qwenEmbeddingModel)
                .maxResults(5) // 最相似的5个结果
                .minScore(0.6) // 只找相似度在0.6以上的内容
                .build();

        // 为Assistant动态代理对象  chat  --->  对话内容存储ChatMemory----> 聊天记录ChatMemory取出来 ---->放入到当前对话中
        Assistant assistant = AiServices.builder(Assistant.class)
                .tools(toolsService)
                .contentRetriever(contentRetriever)
                .chatLanguageModel(qwenChatModel)
                .streamingChatLanguageModel(qwenStreamingChatModel)
                .chatMemory(chatMemory)
                .build();

        return  assistant;
    }

添加端口代码:

    @RequestMapping(value = "/memory_stream_chat",produces ="text/stream;charset=UTF-8")
    public Flux<String> memoryStreamChat(@RequestParam(defaultValue="我是谁") String message, HttpServletResponse response) {
        TokenStream stream = assistant.stream(message);

        return Flux.create(sink -> {
            stream.onPartialResponse(s -> sink.next(s))
                    .onCompleteResponse(c -> sink.complete())
                    .onError(sink::error)
                    .start();

        });
    }

由于是测试,我们直接将代码存放到缓存,但是在实际开发中建议将代码存放的向量数据库中,这边Springboot的启动类中添加代码:

    @Bean
    CommandLineRunner ingestTermOfServiceToVectorStore(
            EmbeddingStore embeddingStore,
            QwenEmbeddingModel qwenEmbeddingModel){


        return args -> {
            Document document = ClassPathDocumentLoader.loadDocument("rag/terms-of-service.txt", new TextDocumentParser());

            DocumentByLineSplitter splitter = new DocumentByLineSplitter(
                    150,
                    30
            );
            List<TextSegment> segments = splitter.split(document);

            // 向量化
            List<Embedding> embeddings = qwenEmbeddingModel.embedAll(segments).content();

            // 存入
            embeddingStore.addAll(embeddings,segments);

        };
    }

测试后运行结果如下:

### 如何在本地创建和管理 LangChain4j 知识库 #### 创建知识库 为了使大模型能够基于私有化的本地知识进行回答,在本地建立知识库是一个重要的步骤。这涉及到将本地知识切片后做 Embedding,再存储到向量数据库中[^1]。 对于LangChain4j而言,实现这一过程的方法之一是通过RAG(Retrieval-Augmented Generation),即检索增强型生成技术来达成。此方法允许定制化特殊场景下的模型应用,比如学校官网AI或个人博客AI等案例,确保这些应用程序仅针对特定领域内的查询提供精准的回答[^2]。 具体操作上,首先需准备要嵌入的知识文件,并将其分割成适合embedding model处理的小片段。接着利用相应的API对这些小片段实施向量化处理,最后将得到的向量数据存入预先设置好的向量数据库内[^4]。 ```java // 假设已经完成了环境配置以及必要的依赖导入 List<Document> documents = loadDocumentsFromSource(); // 加载原始文档集合 List<String> chunks = splitIntoChunks(documents); // 将文档拆分成更小的部分以便于后续处理 VectorStore vectorStore = new VectorDB(); // 初始化一个用于储存向量表示形式的对象实例 for (String chunk : chunks){ float[] embedding = generateEmbedding(chunk); // 使用预训练的语言模型为每个文本块生成对应的向量表达 vectorStore.add(embedding); // 把新产生的向量加入到矢量数据库里去 } ``` #### 查询与响应机制 一旦建立了这样的知识库,下一步就是设计如何有效地从中提取有用信息以回应用户的请求。这里的关键在于定义好合适的检索逻辑——当接收到一个新的询问时,系统会先尝试从已有的知识库里找到最接近的内容作为上下文背景,然后再交给大型语言模型来进行具体的应答创作[^3]。 ```python def get_knowledge_based_answer(query, knowledge_base_path): # 实例化llm_model_ins对象并创建LocalDocQA类的新实体 qa_system = LocalDocQA(llm_model_ins()) # 执行初始化配置动作 qa_system.init_cfg() # 设置待查问句及关联的知识源位置参数 answer_info = qa_system.get_knowledge_based_answer( query=query, kb_root_dir=knowledge_base_path ) return { "answer": answer_info['result'], "source_docs": answer_info['source_documents'] } ``` 上述代码展示了如何构建这样一个问答系统的框架结构,其中包含了加载所需资源、执行初始化工作流、指定查询条件以及最终获取答案的过程描述。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不死鸟.亚历山大.狼崽子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值