Java中LangChain进行文档检索和问答:数据分析实战案例

云信安装大师
90
AI 质量分
2 5 月, 2025
4 分钟阅读
0 阅读

Java中LangChain进行文档检索和问答:数据分析实战案例

引言

在数据分析领域,我们经常需要从大量文档中快速查找信息并获取答案。LangChain是一个强大的框架,可以帮助我们构建基于大型语言模型(LLM)的文档检索和问答系统。本文将带你使用Java实现一个完整的文档检索和问答系统,特别适合数据分析场景。

准备工作

环境要求

  • JDK 11或更高版本
  • Maven 3.6+
  • OpenAI API密钥(或其他LLM提供商)

Maven依赖

在pom.xml中添加以下依赖:

代码片段
<dependencies>
    <!-- LangChain4j -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>0.25.0</version>
    </dependency>
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai</artifactId>
        <version>0.25.0</version>
    </dependency>

    <!-- 文本处理工具 -->
    <dependency>
        <groupId>org.apache.tika</groupId>
        <artifactId>tika-core</artifactId>
        <version>2.7.0</version>
    </dependency>

    <!-- 向量数据库 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-store-embedding-inmemory</artifactId>
        <version>0.25.0</version>
    </dependency>
</dependencies>

实现步骤

1. 初始化LLM和嵌入模型

代码片段
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;

public class DocumentQASystem {

    private static final String OPENAI_API_KEY = "your-api-key";

    public static void main(String[] args) {
        // 初始化聊天模型
        ChatLanguageModel chatModel = OpenAiChatModel.builder()
                .apiKey(OPENAI_API_KEY)
                .modelName("gpt-3.5-turbo")
                .temperature(0.3) // 控制回答的随机性,较低值使回答更确定
                .build();

        // 初始化嵌入模型(用于将文本转换为向量)
        EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
                .apiKey(OPENAI_API_KEY)
                .modelName("text-embedding-ada-002")
                .build();

        // ...后续代码将在这里添加
    }
}

原理说明
ChatLanguageModel是与LLM交互的接口
EmbeddingModel负责将文本转换为向量表示,便于相似性搜索
temperature参数控制回答的创造性,数据分析场景建议使用较低值(0.2-0.5)

2. 创建文档加载和分割器

代码片段
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentParser;
import dev.langchain4j.data.document.FileSystemDocumentLoader;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.document.splitter.ParagraphSplitter;

// ...在main方法中继续添加代码

// 加载文档(假设我们有一个data_analysis_report.pdf文件)
Document document = FileSystemDocumentLoader.loadDocument(
        Paths.get("data/data_analysis_report.pdf").toAbsolutePath(),
        DocumentParser.of("pdf"));

// 分割文档为段落(适合问答的较小片段)
ParagraphSplitter splitter = DocumentSplitters.paragraphSplitter(500, 50);
List<TextSegment> segments = splitter.split(document);

注意事项
– PDF解析可能需要额外的依赖,如Apache PDFBox
– 段落大小(500字符)和重叠(50字符)可根据文档特点调整
– 对于表格数据密集的文档,可能需要特殊处理

3. 创建嵌入存储并索引文档

代码片段
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;

// ...继续添加代码

// 创建内存中的嵌入存储(生产环境可用Redis或Pinecone等)
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();

// 为每个文本段生成嵌入并存储
for (TextSegment segment : segments) {
    Embedding embedding = embeddingModel.embed(segment.text());
    embeddingStore.add(embedding, segment);
}

实践经验
– InMemoryEmbeddingStore适合小规模数据,生产环境建议使用持久化存储
– 索引过程可能耗时,对于大型文档集应考虑批处理和异步处理

4. 构建问答系统

代码片段
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;

public interface DataAnalysisAssistant {

    String answer(String question);
}

// ...继续添加代码

// 创建带有检索功能的问答服务
DataAnalysisAssistant assistant = AiServices.builder(DataAnalysisAssistant.class)
        .chatLanguageModel(chatModel)
        .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
        .contentRetriever(EmbeddingStoreContentRetriever.builder()
                .embeddingStore(embeddingStore)
                .embeddingModel(embeddingModel)
                .maxResults(3) // 检索最相关的3个片段
                .minScore(0.7) // 最小相似度阈值
                .build())
        .build();

// 示例问题解答
String question = "报告中提到的主要数据分析方法是什么?";
String answer = assistant.answer(question);
System.out.println("问题: " + question);
System.out.println("回答: " + answer);

原理说明
ContentRetriever负责从存储中检索与问题相关的文档片段
maxResults控制返回的相关片段数量,平衡准确性和上下文长度限制
minScore过滤低相关性结果,避免引入噪声

完整示例代码

代码片段
package com.example.documentqa;

import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentParser;
import dev.langchain4j.data.document.FileSystemDocumentLoader;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.document.splitter.ParagraphSplitter;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.embedding.Embedding;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import def.dev.langehain.model.openai.OpenAiEmbeddedingodel;e= new OpenAiEmbeddedingodel.builder()
            apiKey()...build();e= new OpenAiChatModell.builder()...build();...e= new ParagraphSplitter(...);...e= new InMemoryEmbeddedingStore<>();...for (TextSegment segment : segments) {...}...e= AiServices.builder(...)...build();...String answer = assistant.aswer("What are the key findings?"); System.out.println(answer);

public class DocumentQASystem {

private static final String OPENAI_API_KEY = "your-api-key";

public static void main(String[] args) {
// Initialize models 
ChatLanguageModell chatModell = OpenAiChatModell.builder()
.apiKey()...
.build();

Embeddedingodel embeddedingodel = OpenAiEmbeddedingodel.builder()...
.build();

// Load and split document 
Document document = FileSystemDocumentLoader.loadDocument(...); 
ParagraphSplitter splitter = DocumentSplitters.pragraphSplitter(...); 
List<TextSegment> segments = splitter.split(document);

// Create and populate embeddeding store 
InMemoryEmbeddedingStore<TextSegment> embeddedingStore = new InMemoryEmbeddedingStore<>(); 
for (TextSegment segment : segments) { 
embeddeding embeddedingodel..add(...); 
}

// Create QA assistant 
DataAnalysisAssistant assistant = AiServices.builder(...)...build();

// Example QA 
String question1 ="What is the main methodology used in the analysis?"; 
String answer1=assistant.aswer(q1); System.out.println(answer1);

String q2="What were the limitations mentioned?"; String a2=assistant.aswer(q2); System.out.println(a2); } 

interface DataAnalysisAssistant { String aswer(String q); } }

总结

本文介绍了如何使用Java中的LangChain框架构建一个面向数据分析场景的文档检索和问答系统。关键点包括:

1.核心组件
– LLM模型:处理自然语言理解和生成
– Embeddeding模型:将文本转换为向量表示
– Embeddeding存储:高效检索相关内容

2.实践建议
预处理很重要:合理的文档分割能显著提升效果
参数调优:根据数据特点调整temperature、maxResults等参数
成本控制:注意API调用次数,可缓存常用查询结果

3.扩展方向
多格式支持:扩展支持Excel、CSV等数据分析常用格式
可视化集成:将问答结果与数据可视化工具结合
领域微调:针对特定数据分析领域微调模型

这个方案特别适合需要从技术报告、研究论文或业务分析文档中快速提取信息的场景。相比传统全文搜索,它能理解问题的语义并给出整合后的答案。

原创 高质量