最近,受到大环境的影响,很多朋友被降薪,被裁员等等不公正待遇。想要仲裁,却不知道哪些法律条文可以支撑我们的诉求。所以,我做了一个普及劳动法规的RAG知识库。通过这个知识库,我们可以通过大模型,迅速的查找相关的法律法规。
首先,我们还是引入SpringAI相关的pom依赖:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-rag</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>
然后,我们构建向量数据库中的数据。这里我们可以访问国家法律法规数据库。这里有所有的法律法规。可是文件太多了怎么办,我们可以筛选一下现在有效的,还有过滤掉地方性的。这样,就只剩了342个文件。
还是有点多,不相关的太多了,我们可以上deepseek里问一下,保障劳动者的相关法律都有什么。
这样我们将这些文件在刚才的网站中下载下来。
接下来,就是读取文件,构建向量数据库了。代码如下:
TikaDocumentReader tikaReader = new TikaDocumentReader(resource);
List<Document> docbatch = tikaReader.read();
// Sending batch of documents to vector store
// applying tokenizer
docbatch = TokenTextSplitter.builder().withChunkSize(256).withMaxNumChunks(10000).build().apply(docbatch);
log.info("Adding {} documents to vector store", docbatch.size());
docbatch.forEach(doc -> {
log.info("Adding document to vector store: {}", doc.getText());
doc.getMetadata().put("label",label);
doc.getMetadata().put("source",name);
vectorStore.doAdd(ListUtil.of(doc));
});
注意这里在做文档切分时,不要写的太大,比如我现在用的模型最大支持token是512,这里withChunkSize(256)不要定格设置成512,一半最稳妥。
构建完数据库后,我们就可以开始编写搜索代码了。
public String queryLLM(String question, String label) {
SearchRequest searchRequest = SearchRequest.builder().filterExpression(new FilterExpressionBuilder().eq("label", label).build()).query(question).similarityThreshold(0.5d).topK(5).build();
// Calling the chat model with the question
ChatResponse chatResponse =chatClient.prompt()
.system("你是一个法律专家顾问,请用中文回答相关法律问题。")
.advisors(
QuestionAnswerAdvisor.builder(vectorStore).searchRequest(searchRequest).build(),
new SimpleLoggerAdvisor()
)
.user(question)
.call().chatResponse();
String response = Optional.ofNullable(chatResponse)
.map(ChatResponse::getResult)
.map(Generation::getOutput)
.map(AbstractMessage::getText)
.orElse("");
StringJoiner stringJoiner = new StringJoiner(System.lineSeparator());
Set<String> fileNames = new HashSet<>();
Optional.ofNullable(chatResponse)
.map(ChatResponse::getMetadata)
.map(metadata -> (List<Document>)metadata.get(QuestionAnswerAdvisor.RETRIEVED_DOCUMENTS))
.orElse(new ArrayList<>())
.stream().forEach(doc -> {
Object value = doc.getMetadata().getOrDefault(TikaDocumentReader.METADATA_SOURCE,"");
if(null != value && !fileNames.contains(value.toString())) {
stringJoiner.add(value.toString());
fileNames.add(value.toString());
}
});
if(stringJoiner.length() == 0){
stringJoiner.add("无");
}
return response
+ System.lineSeparator() + System.lineSeparator() +
"答案仅供参考相关文件查阅: " + System.lineSeparator() +
stringJoiner
;
}
首先,我们通过label和问题来过滤相关数据,然后喂给大模型进行回答。这样最主要核心的代码就完成了。
接下来,就要考虑一些其他的问题,比如数据源上可以增加一些最高院的典型案例;法律法规的动态加载,以及时效问题等等。这样,一个辅助劳动者的法律顾问就诞生了。我们看一下效果。