基于Spring AI实现法律咨询AI助手

2025-12-12 0 507

1. 技术选型

组件 类型
大语言模型 deepseek r1
embedding模型 bge-m3
框架选择 spring ai 1.0.1(JDK 17以上)
向量数据库 pgvector

2. 项目功能及接口文档

  1. 提供将法律法规文档通过embedding模型将知识导入向量库(导入文件格式只支持pdf和word)

POST http://127.0.0.1:8088/rag/init?filePath=D:downloads中华人民共和国劳动法_20181229.docx

  1. 提供法律咨询问答的接口

GET http://127.0.0.1:8088/rag/query?query=请根据劳动法告诉我,工厂每天早上九点上班,晚上十点下班,且没有支付足够响应报酬补偿的,一周无休,是否违法

3. 项目结构和依赖及配置项

pom.xml

<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<project xmlns=\"http://maven.apache.org/POM/4.0.0\"
         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.4</version>
        <relativePath/> 
    </parent>

    <groupId>com.sikaryofficial</groupId>
    <artifactId>spring-ai-chat</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>17</java.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        
        <spring-boot.version>3.2.4</spring-boot.version>
        
        <spring-ai.version>1.0.1</spring-ai.version>
        
        <spring-ai-alibaba.version>1.0.0.2</spring-ai-alibaba.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud.ai</groupId>
                <artifactId>spring-ai-alibaba-bom</artifactId>
                <version>${spring-ai-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-autoconfigure-model-openai</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-autoconfigure-model-chat-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-pdf-document-reader</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-tika-document-reader</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-pgvector-store</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.projectreactor.netty</groupId>
            <artifactId>reactor-netty-http</artifactId>
        </dependency>

<!--        -->
<!--            org.springframework.ai-->
<!--            spring-ai-ollama-spring-boot-starter-->
<!--            1.0.0-M6-->
<!--        -->

    </dependencies>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
        <repository>
            <id>aliyunmaven</id>
            <name>aliyun</name>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>https://maven.aliyun.com/repository/apache-snapshots</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置文件application.yml

server:
  port: 8088

spring:
  datasource:
    url: jdbc:postgresql://192.168.232.194:5432/ai_data?currentSchema=public
    username: postgres
    password: ske@001
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        format_sql: true
        dialect: org.hibernate.dialect.PostgreSQLDialect
    defer-datasource-initialization: true  # 允许先创建扩展再初始化表
  ai:
    openai:
      api-key: hismk
      base-url: http://192.168.201.230:3045/
      chat:
        options:
          model: deepseek-r1:32b_awq
          max_tokens: 1024
          temperature: 0.2
          top_p: 0.9
      embedding:
        options:
          model: bge-m3
        base-url: http://192.168.201.250:11434
        enabled: true



# 打印日志
logging:
  level:
    com.sikaryofficial: DEBUG

提示词模板

当前日期:{current_date}

请基于以下上下文信息回答问题。请遵循以下规则:
1. 回答要专业、准确
2. 如果上下文不包含答案,请明确说明\"根据提供的信息无法确定\"
3. 使用中文回答
4. 保持回答简洁明了

上下文:
{context}

问题:{input}

请按以下格式回答:
【回答】: (你的回答)
【来源】: (指出回答基于哪些上下文片段,用1,2,3编号)

4. 功能实现

a. 配置相关

  1. chatClient配置
package com.sikaryofficial.ai.config;

/**
 * @author : wuweihong
 * @desc : TODO  请填写你的功能描述
 * @date : 2025-11-04
 */


import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ChatClientConfig {
	@Bean
	public ChatClient chatClient(ChatClient.Builder builder) {
		return builder.defaultAdvisors(new SimpleLoggerAdvisor()).build();
	}

}

2. 向量存储配置

package com.sikaryofficial.ai.config;

/**
 * @author : wuweihong
 * @desc : TODO  请填写你的功能描述
 * @date : 2025-11-04
 */


import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
public class VectorStoreConfig {

	@Bean
	public VectorStore vectorStore(EmbeddingModel embeddingClient, JdbcTemplate jdbcTemplate) {
		return PgVectorStore.builder(jdbcTemplate, embeddingClient).dimensions(1024).vectorTableName(\"law_articles\").build();
	}

	@Bean
	public JdbcTemplate jdbcTemplate(DataSource dataSource) {
		return new JdbcTemplate(dataSource);
	}
}

3. WebClient配置

package com.sikaryofficial.ai.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;

/**
 * @author : wuweihong
 * @desc : TODO  请填写你的功能描述
 * @date : 2025-07-29
 */

@Configuration
public class WebClientConfig {

	@Bean
	public WebClient webClient() {
		// 创建并配置 Netty 的 HttpClient
		HttpClient httpClient = HttpClient.create()
				.headers(headers -> headers
						.remove(\"Transfer-Encoding\")  // 显式移除分块头
						.set(\"Connection\", \"close\")   // 强制关闭连接避免分块
				)
				.compress(false);  // 禁用压缩

		return WebClient.builder()
				.clientConnector(new ReactorClientHttpConnector(httpClient))
				.build();
	}
}

ⅰ. 接口实现

  1. 文档导入向量数据库的接口实现
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.ExtractedTextFormatter;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.reader.pdf.ParagraphPdfDocumentReader;
import org.springframework.ai.reader.pdf.config.PdfDocumentReaderConfig;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;

@Service
@RequiredArgsConstructor
public class DocumentService {

	private final VectorStore vectorStore;

	public void loadAndStoreDocuments(String filePath) throws IOException {
		List documents = null;
		if (StringUtils.isNotBlank(filePath) && filePath.endsWith(\".pdf\")) {
			// 读取PDF文档
			documents = loadPDFDocuments(filePath);
			System.out.println(\"Total number of documents: \" + documents.size());
		} else if (StringUtils.isNotBlank(filePath) && filePath.endsWith(\".docx\")) {
			// 读取DOCX文档
			documents = loadDOCXDocuments(filePath);
			System.out.println(\"Total number of documents: \" + documents.size());
		}

		// 文本分割
		TokenTextSplitter splitter = new TokenTextSplitter();
		List splitDocs = splitter.apply(documents);

		// 存储到向量数据库
		vectorStore.add(splitDocs);
	}

	public List loadPDFDocuments(String filePath) throws IOException {
		// PDF文档读取配置
		PdfDocumentReaderConfig config = PdfDocumentReaderConfig.builder()
				.withPageExtractedTextFormatter(new ExtractedTextFormatter.Builder()
						.withNumberOfTopTextLinesToDelete(0)
						.build())
				.build();

		//先使用目录分段读取方式读取PDF并分段落
		Resource resource = new FileSystemResource(filePath);
		ParagraphPdfDocumentReader pdfReader = new ParagraphPdfDocumentReader(resource, config);
		List documents = pdfReader.get();
		System.out.println(\"Total number of documents1: \" + documents.size());
		if (documents.isEmpty()) {
			//如果沒有获取到目录,在改用分页方式拆分
			PagePdfDocumentReader pdfReader2 = new PagePdfDocumentReader(resource);
			documents = pdfReader2.get();
			System.out.println(\"Total number of documents2: \" + documents.size());
		}
		return documents;
	}

	public List loadDOCXDocuments(String filePath) throws IOException {

		// 读取DOCX文档
		Resource resource = new FileSystemResource(filePath);
		TikaDocumentReader docxReader = new TikaDocumentReader(resource);
		List documents = docxReader.get();
		System.out.println(\"Total number of documents: \" + documents.size());
		return documents;
	}

2. rag问答接口实现类

package com.sikaryofficial.ai.service;

/**
 * @author : wuweihong
 * @desc : TODO  请填写你的功能描述
 * @date : 2025-11-04
 */


import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.document.Document;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class RagService {

	private final ChatClient chatClient;
	private final VectorStore vectorStore;

	@Value(\"classpath:/prompts/rag-prompt-template.st\")
	private Resource ragPromptTemplate;

	public String processQuery(String query) {
		// 1. 检索相关文档
		List similarDocuments = vectorStore.similaritySearch(query);
		System.out.println(\"检索到相关文档:\" + similarDocuments.size());

		// 2. 构建上下文
		String context = similarDocuments.stream()
				.map(Document::getFormattedContent)
				.collect(Collectors.joining(\"nn\"));

		// 3. 构建提示词
		PromptTemplate promptTemplate = new PromptTemplate(ragPromptTemplate);
		Prompt prompt = promptTemplate.create(Map.of(
				\"current_date\", new Date().toLocaleString(),
				\"input\", query,
				\"context\", context
		));
		// 4. 调用LLM生成回答
		return chatClient.prompt(prompt).call().content();
	}
}

5. 效果自测

  1. 导入接口测试

  1. 智能问答接口测试

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 基于Spring AI实现法律咨询AI助手 https://www.zuozi.net/35871.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务