「Java AI实战」LangChain4J -文本分类器实践

系列文章目录

第一章 「Java AI实战」LangChain4J - 接入Xinference本地大模型
第二章 「Java AI实战」LangChain4J - ChatAPI 及常用配置
第三章 「Java AI实战」LangChain4J - 向量数据库接入与语义检索
第四章 「Java AI实战」LangChain4J - Agent智能体开发
第五章 「Java AI实战」LangChain4J -记忆缓存



前言:从聊天问答到“性格分析”

很多团队接入 LangChain4j 时,第一步都是做「聊天问答」:

  • 前端给个输入框
  • 后端用 Java 调用大模型
  • 返回一段回答

这种模式简单好用,但有个共性:模型只会“说话”,不会“打标签”

而在很多业务里,“打标签”反而更刚需,比如:

  • 用户这段描述偏 内向 还是 外向
  • 候选人简历更像 分析型工程师 还是 创意型产品
  • 用户反馈属于 功能建议 / 体验吐槽 / Bug 报告 哪一类?

在 LangChain4j 里,这类需求可以非常自然地用:

EmbeddingModelTextClassifier(文本向量分类器)

来实现一个轻量的文本分类服务。

这篇文章,我们就用一个完整的 Spring Boot Demo,做一个:

✨ 基于 LangChain4j + 阿里云百炼 DashScope 的 “性格分析小助手”:输入一句话,输出最可能的性格标签。


一、文本分类器的使用场景

先讲清楚它能做什么,再看代码会更有感觉。

1.1 性格 / 用户画像分析

本文 Demo 的性格维度如下:

  • EXTROVERT —— 外向型
  • INTROVERT —— 内向型
  • ANALYTICAL —— 分析型
  • CREATIVE —— 创意型
  • LEADER —— 领导型
  • TEAM_PLAYER —— 团队合作型

我们给每个标签准备几条典型描述作为样本(few-shot 示例),
然后就可以对一句话做“语义相似度匹配 + 分类”,判断它更接近哪个性格。

可以应用在:

  • 职业性格问卷 / 简历初筛
  • 对话机器人里的用户画像打标
  • 课程 / 岗位推荐系统的性格侧信息

2.2 文本分类器的常见业务玩法

只要是“固定标签集合 + 文本内容”,都可以直接套用这个套路,例如:

  • 情感分析:正向 / 负向 / 中性
  • 意图识别:咨询 / 投诉 / 购买 / 取消
  • 风控打标:高风险 / 中风险 / 正常
  • 主题分类:产品 / 运营 / 技术 / 账号 / 支付

对比关键词 if-else 的优势:

  • 基于 Embedding 做语义相似度,不怕同义词、口语化表达
  • 支持多语言、混合语言场景
  • 不需要维护复杂的规则树,示例数据越多越准

二、代码实践:用 LangChain4j 搭一个性格分析器

3.1 Maven 依赖

<?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>com.text.study</groupId>
        <artifactId>langchain4j-text</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>langchain4j-13chat-embeddingtextclassifier</artifactId>
    <name>langchain4j-13chat-embeddingtextclassifier文本向量化</name>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Spring MVC -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- WebFlux(可选,根据项目需要) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <!-- LangChain4j Reactor(流式、响应式时会用到) -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-reactor</artifactId>
        </dependency>

        <!-- LangChain4j OpenAI Spring Boot Starter -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
        </dependency>

        <!-- LangChain4j Spring Boot 基础集成 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-spring-boot-starter</artifactId>
        </dependency>

        <!-- Qdrant(向量数据库,这个 Demo 没用到,可以复用到别的模块) -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-qdrant</artifactId>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- Hutool 工具类 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>

        <!-- 单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

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

</project>

这里我们用的是 LangChain4j 的 OpenAI 客户端,再通过 baseUrl 配置指向本地Xinference的 OpenAI 兼容接口。

3.2 定义性格枚举

PersonalityTraitEnum.java

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum PersonalityTraitEnum {
    /**
     * 外向型:喜欢社交,从与他人互动中获得能量
     */
    EXTROVERT,

    /**
     * 内向型:倾向于独处,需要安静时间来恢复能量
     */
    INTROVERT,

    /**
     * 分析型:擅长逻辑思考,喜欢解决复杂问题
     */
    ANALYTICAL,

    /**
     * 创意型:富有想象力,常有新颖的想法
     */
    CREATIVE,

    /**
     * 领导型:善于指导他人,乐于承担责任
     */
    LEADER,

    /**
     * 团队合作型:重视协作,善于在团队中工作
     */
    TEAM_PLAYER
}

3.3 配置 Embedding 模型 & 文本分类器

import com.zzyy.study.enums.PersonalityTraitEnum;
import dev.langchain4j.classification.EmbeddingModelTextClassifier;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.Map;

@Configuration(proxyBeanMethods = false)
public class EmbeddingModelConfig {

    /**
     * 1)声明 Embedding 模型
     * 使用本地Xinference 的 bge-large-en-v1.5,
     * 通过 OpenAI 兼容协议接入。
     */
    @Bean
    public EmbeddingModel embeddingModel() {
        return OpenAiEmbeddingModel.builder()
                .apiKey(System.getenv("LANGCHAIN4J_KEY"))
                .modelName("bge-large-en-v1.5")
                .baseUrl("http://本地ip:9997/v1")
                .build();
    }

    /**
     * 2)声明文本分类器
     *
     * 核心就是传入:
     * - EmbeddingModel
     * - Map<标签, List<示例文本>>
     */
    @Bean
    public EmbeddingModelTextClassifier<PersonalityTraitEnum> textClassifier(EmbeddingModel embeddingModel) {
        return new EmbeddingModelTextClassifier<>(embeddingModel, examplesByLabel);
    }

    /**
     * 3)每个性格标签的一组“典型语句”
     *
     * 可以理解为 few-shot 示例,
     * 分类器会将这些示例和待分类文本一起向量化,
     * 通过相似度来判断更接近哪个标签。
     */
    public static final Map<PersonalityTraitEnum, List<String>> examplesByLabel = Map.of(
            PersonalityTraitEnum.EXTROVERT, List.of(
                    "我喜欢结识新朋友",
                    "团体活动让我充满活力",
                    "我经常是聚会的焦点",
                    "我喜欢在热闹的社交环境中工作"
            ),
            PersonalityTraitEnum.INTROVERT, List.of(
                    "我更喜欢独自工作",
                    "我需要安静的时间来充电",
                    "大型社交聚会让我感到压抑",
                    "我喜欢深入的一对一谈话"
            ),
            PersonalityTraitEnum.ANALYTICAL, List.of(
                    "我喜欢解决复杂的问题",
                    "数据驱动的决策至关重要",
                    "我总是寻找信息中的模式和联系",
                    "我倾向于在采取行动之前彻底分析情况"
            ),
            PersonalityTraitEnum.CREATIVE, List.of(
                    "我常常跳出框架思考",
                    "我总是想出新的点子",
                    "我喜欢寻找创新的解决方案",
                    "我受到周围艺术和美的启发"
            ),
            PersonalityTraitEnum.LEADER, List.of(
                    "我能自信地领导项目",
                    "我激励他人实现目标",
                    "我喜欢指导和培养团队成员",
                    "我不怕做出艰难的决定"
            ),
            PersonalityTraitEnum.TEAM_PLAYER, List.of(
                    "合作是成功的关键",
                    "我重视所有团队成员的意见",
                    "我总是愿意帮助我的同事",
                    "我相信团队中多样化视角的力量"
            )
    );
}

3.4 Controller:来测一测分类效果

import com.zzyy.study.enums.PersonalityTraitEnum;
import dev.langchain4j.classification.EmbeddingModelTextClassifier;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@Slf4j
public class EmbedTextClassifierController {

    @Resource
    private EmbeddingModelTextClassifier<PersonalityTraitEnum> textClassifier;

    @GetMapping(value = "/textClassifier/ask")
    public void ask() {

        List<PersonalityTraitEnum> personalityTraitDesc =
                textClassifier.classify("我喜欢数学,刷题高手,尤其喜欢动脑子");
        System.out.println(personalityTraitDesc);

        personalityTraitDesc =
                textClassifier.classify("喜欢一个人独处,安静的看书");
        System.out.println(personalityTraitDesc);
    }
}

3.5 启动类 & 测试流程

项目启动类:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Langchain4j13chatEmbeddingtextclassifierApplication {

    public static void main(String[] args) {
        SpringApplication.run(Langchain4j13chatEmbeddingtextclassifierApplication.class, args);
    }
}

调用测试

启动 Spring Boot 后,请求接口:

curl “http://localhost:8080/textClassifier/ask”

控制台可能输出类似(示例):

[ANALYTICAL]
[INTROVERT]

  • “我喜欢数学,刷题高手,尤其喜欢动脑子” → 更偏 分析型 ANALYTICAL
  • “喜欢一个人独处,安静的看书” → 更偏 内向型 INTROVERT

实际结果会随着示例语料略有变化,你可以自己多写几条,感受一下分类效果。


总结

这篇文章,我们用一个精简 Demo 走通了整个链路:

1. 模型接入:
- 用 LangChain4j 的 OpenAiEmbeddingModel
- 通过 baseUrl 对接阿里云 DashScope 的 Embedding 模型

2. 分类器封装:
- 用 EmbeddingModelTextClassifier
- 使用 Map<Enum, List> 构建示例库
- 完全在 Java 端就能完成“语义分类”

3. 接口暴露:
- 提供简单的 HTTP 接口
- 可以控制台调试,也可以对接前端做一个“性格分析小工具”

接下来在真实项目里,你可以进一步扩展:

  • 加上 Top-N + 置信度:比如返回 [ANALYTICAL(0.82), INTROVERT(0.63)]、前端可以做雷达图 / 标签权重展示
  • 结合用户画像 / 推荐系统:把性格信息写入用户画像表、在岗位推荐 / 课程推荐 / 内容推荐里综合使用
  • 做成通用的“文本分类平台”:把“标签 + 示例”的配置做成页面可配置、支持多个业务线复用同一套 Embedding 能力

有了 Embedding 文本分类器,LangChain4j 不止能“聊天”,还能优雅地“给文本打标签”。
在 Java 项目里,这类能力非常适合做成微服务 / 组件,逐步渗透进各类业务场景中

更多完整实战案例: https://wx.zsxq.com/group/48885482144828

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值