公司动态
LangChain4j全集-13-Classification
Classification梳理classification下面我按这篇 LangChain4j 文档里的内容结合你是 Spring Boot 开发者的背景帮你用通俗一点的方式梳理。这篇文档的主题是如何使用 LangChain4j 做文本分类 Classification。所谓“分类”就是把一段文本自动归到某个预定义类别里。比如场景输入文本分类结果情感分析“这个产品太好用了”POSITIVE情绪判断“这次体验很糟糕”NEGATIVE意图识别“我想退货”REFUND工单分类“登录失败提示密码错误”ACCOUNT_PROBLEM内容审核“这段话是否违规”SAFE / UNSAFE这篇文档主要用“情感分类”作为例子。一、Classification 是干什么的文档开头说Classification is essential for categorizing text into predefined labels.意思是分类的作用是把文本归入提前定义好的标签中。比如你提前定义好三个标签POSITIVENEUTRALNEGATIVE然后用户输入一句话I love this product!AI 会判断它属于POSITIVE在实际项目中这种能力很常见。比如在 Spring Boot 后端里你可能会做用户评论情感分析客服消息意图识别工单自动分派文章内容标签分类风险内容识别商品评价好评/中评/差评分类邮件自动分类用户反馈优先级判断二、LangChain4j 支持两种常见分类方式文档里提到 LangChain4j 支持两种常见的文本分类方式。方式一使用 LLM AI Services也就是直接让大语言模型帮你判断文本属于哪个类别。比如你问模型Analyze sentiment of I love this product!模型返回POSITIVE然后 LangChain4j 会帮你把模型返回值转换成 Java 的 enum。这种方式适合分类标准比较模糊需要理解上下文需要自然语言推理类别不只是关键词匹配输入内容很自由比如这家店的服务真是“太棒了”等了两个小时都没人理我。这句话表面有“太棒了”但实际上是反讽真实情感是负面的。这种情况用大模型判断会更合适。方式二使用 Embeddings TextClassifier文档还提到了另一种方式Use embeddings through TextClassifier and EmbeddingModelTextClassifier when you have labeled examples for each category and want to classify by semantic similarity.意思是如果你已经有一批带标签的样本可以用 Embedding 向量相似度来分类。简单理解你准备一些例子我想退款 - REFUND 我要退货 - REFUND 物流什么时候到 - SHIPPING 快递还没收到 - SHIPPING 怎么修改密码 - ACCOUNT然后新来一句我买错了能不能把钱退给我系统会把这句话变成向量然后和你已有的样本做相似度比较最后发现它和 REFUND 相关的样本最像于是分类为REFUND这种方式适合你有比较多的历史样本分类类别比较固定想根据语义相似度分类不想每次都完全依赖大模型推理成本和速度比较敏感三、这篇文档主要演示的是情感分类服务文档中的目标是做一个情感分析系统把文本分为POSITIVENEUTRALNEGATIVE也就是枚举值含义POSITIVE正面情绪NEUTRAL中性情绪NEGATIVE负面情绪例如I love this product!结果POSITIVEThis is a terrible experience.结果NEGATIVE四、完整代码大概长这样文档中的示例代码如下importdev.langchain4j.model.chat.ChatModel;importdev.langchain4j.model.openai.OpenAiChatModel;importdev.langchain4j.service.AiServices;importdev.langchain4j.service.UserMessage;publicclassSentimentClassification{// Initialize the chat model using OpenAIstaticChatModelchatModelOpenAiChatModel.withApiKey(YOUR_OPENAI_API_KEY);// Define the Sentiment enumenumSentiment{POSITIVE,NEUTRAL,NEGATIVE}// Define the AI-powered Sentiment Analyzer interfaceinterfaceSentimentAnalyzer{UserMessage(Analyze sentiment of {{it}})SentimentanalyzeSentimentOf(Stringtext);UserMessage(Does {{it}} have a positive sentiment?)booleanisPositive(Stringtext);}publicstaticvoidmain(String[]args){// Create an AI-powered Sentiment Analyzer instanceSentimentAnalyzersentimentAnalyzerAiServices.create(SentimentAnalyzer.class,chatModel);// Example Sentiment AnalysisSentimentsentimentsentimentAnalyzer.analyzeSentimentOf(I love this product!);System.out.println(sentiment);// Expected Output: POSITIVEbooleanpositivesentimentAnalyzer.isPositive(This is a terrible experience.);System.out.println(positive);// Expected Output: false}}下面我们逐块拆解。五、代码拆解说明1. 导入相关类importdev.langchain4j.model.chat.ChatModel;importdev.langchain4j.model.openai.OpenAiChatModel;importdev.langchain4j.service.AiServices;importdev.langchain4j.service.UserMessage;这些类分别负责类作用ChatModel聊天模型接口可以理解为 LangChain4j 对大模型的统一抽象OpenAiChatModelOpenAI 聊天模型的具体实现AiServicesLangChain4j 的核心功能之一可以根据 Java 接口自动创建 AI 服务UserMessage用来写提示词也就是告诉 AI 要干什么六、Chat Model 初始化文档中这段代码staticChatModelchatModelOpenAiChatModel.withApiKey(YOUR_OPENAI_API_KEY);它的作用是创建一个 OpenAI 的聊天模型客户端。你可以把它理解为 Spring Boot 里创建一个第三方 API Client。类似于RestTemplaterestTemplatenewRestTemplate();或者WebClientwebClientWebClient.builder().build();只不过这里创建的是一个可以和大模型对话的对象。这里的YOUR_OPENAI_API_KEY是什么这是 OpenAI 的 API Key。真实项目里不要直接写死在代码中。不推荐OpenAiChatModel.withApiKey(sk-xxxx);推荐放到配置文件或环境变量里。比如 Spring Boot 中openai:api-key:${OPENAI_API_KEY}然后在配置类里读取。七、定义分类结果 enum文档中这段enumSentiment{POSITIVE,NEUTRAL,NEGATIVE}它的作用是定义分类结果只能是这三个值之一。这点很重要。如果不用 enum模型可能返回positive 正面 很积极 This is positive.这样你后端还得自己解析字符串。但是用了 enum 之后LangChain4j 会尝试把模型返回值转换成Sentiment.POSITIVESentiment.NEUTRALSentiment.NEGATIVE这样后端代码就更类型安全。为什么 enum 很适合分类因为分类任务本质上就是在有限个标签里选一个。所以用 Java enum 表示非常自然。比如做工单分类enumTicketType{PAYMENT,REFUND,SHIPPING,ACCOUNT,OTHER}做用户意图识别enumIntent{ORDER_QUERY,REFUND_REQUEST,HUMAN_SERVICE,PRODUCT_CONSULTATION,COMPLAINT}做内容审核enumSafetyLabel{SAFE,VIOLENCE,SPAM,ADULT,POLITICAL}八、定义 AI 服务接口文档中这段很关键interfaceSentimentAnalyzer{UserMessage(Analyze sentiment of {{it}})SentimentanalyzeSentimentOf(Stringtext);UserMessage(Does {{it}} have a positive sentiment?)booleanisPositive(Stringtext);}这个接口不是普通接口。它是 LangChain4j 的 AI Service 接口。你只需要定义方法LangChain4j 会自动帮你生成实现类。有点像 Spring Data JPAinterfaceUserRepositoryextendsJpaRepositoryUser,Long{UserfindByUsername(Stringusername);}你没有写实现类但 Spring Data JPA 会帮你生成。LangChain4j 的AiServices也是类似思想你写接口SentimentanalyzeSentimentOf(Stringtext);LangChain4j 根据注解、参数、返回值自动帮你完成拼接提示词调用大模型获取大模型响应解析返回结果转成 Java 类型九、UserMessage是干什么的UserMessage(Analyze sentiment of {{it}})它的作用是定义发送给大模型的用户消息也就是 prompt。当你调用sentimentAnalyzer.analyzeSentimentOf(I love this product!);LangChain4j 实际上会构造类似这样的提示词Analyze sentiment of I love this product!然后发送给 OpenAI 模型。十、{{it}}是什么意思UserMessage(Analyze sentiment of {{it}})这里的{{it}}是占位符。因为方法只有一个参数SentimentanalyzeSentimentOf(Stringtext);所以{{it}}表示这个参数的值。调用analyzeSentimentOf(I love this product!)实际 prompt 类似Analyze sentiment of I love this product!如果方法有多个参数通常可以使用具名参数方式这样更清晰。例如概念上可以写成UserMessage(Classify this text: {{text}})SentimentanalyzeSentimentOf(V(text)Stringtext);十一、方法返回 enumLangChain4j 会帮你转换这个方法SentimentanalyzeSentimentOf(Stringtext);返回的是Sentiment不是字符串。也就是说你希望最后拿到的是 Java 枚举Sentiment.POSITIVE而不是POSITIVELangChain4j 会根据返回类型要求或引导模型返回对应格式并尝试解析。这就是 AI Services 很方便的地方。你不需要自己写StringresponsecallOpenAi(prompt);if(response.contains(positive)){returnSentiment.POSITIVE;}这些事情 LangChain4j 帮你做了。十二、返回 boolean 的方法文档里还有一个方法UserMessage(Does {{it}} have a positive sentiment?)booleanisPositive(Stringtext);这个方法是问模型这句话是正面情绪吗比如调用booleanpositivesentimentAnalyzer.isPositive(This is a terrible experience.);模型应该判断false这说明 LangChain4j 不只能返回 enum也可以返回基础类型比如booleanStringintdouble以及一些结构化类型。不过做分类时最常用的是 enum。十三、创建 AI 服务对象文档中这句很重要SentimentAnalyzersentimentAnalyzerAiServices.create(SentimentAnalyzer.class,chatModel);它的作用是基于接口SentimentAnalyzer和模型chatModel创建一个真正可用的 AI 服务对象。这里你没有手动实现classSentimentAnalyzerImplimplementsSentimentAnalyzer{...}LangChain4j 自动帮你创建了代理对象。你可以把它理解成SentimentAnalyzersentimentAnalyzerLangChain4jProxyFactory.create(...);之后你就可以像调用普通 Java 方法一样调用 AIsentimentAnalyzer.analyzeSentimentOf(I love this product!);这就是 LangChain4j 的核心体验把大模型能力包装成 Java 接口方法。十四、实际调用分类文档中示例SentimentsentimentsentimentAnalyzer.analyzeSentimentOf(I love this product!);System.out.println(sentiment);// Expected Output: POSITIVE这句话执行流程是你调用 Java 方法analyzeSentimentOf(I love this product!)LangChain4j 根据注解生成 promptAnalyze sentiment of I love this product!调用 OpenAI 模型模型判断这句话是正面情绪返回结果POSITIVELangChain4j 把它转成Sentiment.POSITIVE你的 Java 代码拿到结果十五、第二个调用示例booleanpositivesentimentAnalyzer.isPositive(This is a terrible experience.);System.out.println(positive);// Expected Output: false这段的意思是用户输入This is a terrible experience.这句话明显是负面情绪。方法问的是这句话是不是正面情绪所以返回false十六、整体调用链路可以这样理解整个流程Spring Boot Controller / Service | v SentimentAnalyzer.analyzeSentimentOf(text) | v LangChain4j AI Service 代理对象 | v 根据 UserMessage 生成 Prompt | v 调用 OpenAI ChatModel | v 大模型返回结果 | v LangChain4j 解析成 Java enum / boolean | v 返回给业务代码十七、如果放到 Spring Boot 里大概怎么写文档是普通 Java main 方法示例。如果你是 Spring Boot 开发者更可能这样组织代码。1. 配置 ChatModelConfigurationpublicclassAiConfig{Value(${openai.api-key})privateStringapiKey;BeanpublicChatModelchatModel(){returnOpenAiChatModel.withApiKey(apiKey);}BeanpublicSentimentAnalyzersentimentAnalyzer(ChatModelchatModel){returnAiServices.create(SentimentAnalyzer.class,chatModel);}}2. 定义 enumpublicenumSentiment{POSITIVE,NEUTRAL,NEGATIVE}3. 定义 AI Service 接口publicinterfaceSentimentAnalyzer{UserMessage(Analyze sentiment of {{it}}. Return only one of: POSITIVE, NEUTRAL, NEGATIVE.)SentimentanalyzeSentimentOf(Stringtext);UserMessage(Does {{it}} have a positive sentiment? Answer true or false.)booleanisPositive(Stringtext);}我这里建议把 prompt 写得更明确一些Return only one of: POSITIVE, NEUTRAL, NEGATIVE.这样模型更不容易返回多余文本。4. 写业务 ServiceServicepublicclassCommentService{privatefinalSentimentAnalyzersentimentAnalyzer;publicCommentService(SentimentAnalyzersentimentAnalyzer){this.sentimentAnalyzersentimentAnalyzer;}publicSentimentanalyzeComment(Stringcomment){returnsentimentAnalyzer.analyzeSentimentOf(comment);}}5. 写 ControllerRestControllerRequestMapping(/comments)publicclassCommentController{privatefinalCommentServicecommentService;publicCommentController(CommentServicecommentService){this.commentServicecommentService;}PostMapping(/sentiment)publicSentimentanalyze(RequestBodyStringcomment){returncommentService.analyzeComment(comment);}}调用接口POST /comments/sentiment 这个产品真的很好用下次还会买。返回POSITIVE十八、这篇文档的重点总结这篇文档其实想告诉你几个核心点。1. 分类任务可以直接用大模型完成你不一定要自己写规则。以前可能会写if(text.contains(好用)||text.contains(喜欢)){returnPOSITIVE;}但这种方式很脆弱。大模型可以理解更复杂的表达比如反讽、上下文、隐含情绪等。2. LangChain4j 可以把 AI 能力包装成 Java 接口你定义interfaceSentimentAnalyzer{SentimentanalyzeSentimentOf(Stringtext);}LangChain4j 帮你生成实现。这对 Java/Spring Boot 开发者非常友好。3. enum 很适合做分类标签分类结果最好用 enum。例如enumSentiment{POSITIVE,NEUTRAL,NEGATIVE}这样业务代码更安全、更清晰。4.UserMessage就是 prompt 模板UserMessage(Analyze sentiment of {{it}})它决定了模型要做什么。prompt 写得越清楚结果越稳定。建议写成UserMessage( Classify the sentiment of the following text. Text: {{it}} Return only one of: POSITIVE, NEUTRAL, NEGATIVE )SentimentanalyzeSentimentOf(Stringtext);比简单一句更稳。5.AiServices.create()创建 AI 代理对象SentimentAnalyzeranalyzerAiServices.create(SentimentAnalyzer.class,chatModel);它的作用类似于根据接口动态创建一个可以调用大模型的实现类。十九、实际项目中的建议如果你准备用在 Spring Boot 项目里我建议你注意下面几点。1. API Key 不要写死不要这样OpenAiChatModel.withApiKey(sk-xxx);建议openai:api-key:${OPENAI_API_KEY}2. prompt 要明确要求输出格式比如UserMessage( Analyze the sentiment of this text: {{it}} Return only one of these exact labels: POSITIVE NEUTRAL NEGATIVE )SentimentanalyzeSentimentOf(Stringtext);这样比UserMessage(Analyze sentiment of {{it}})更稳定。3. 分类标签不要太模糊例如这三个标签比较清晰POSITIVENEUTRALNEGATIVE但如果你定义GOODOKBADNORMAL模型可能会混淆。所以分类标签要语义明确。4. 类别很多时要给模型解释如果你的 enum 很多比如enumTicketType{PAYMENT,REFUND,SHIPPING,ACCOUNT,COMPLAINT,PRODUCT,OTHER}最好在 prompt 中解释每个分类是什么意思。例如UserMessage( Classify the customer message into one ticket type. Types: PAYMENT - payment, invoice, transaction issues REFUND - refund or return requests SHIPPING - delivery, logistics, package tracking ACCOUNT - login, password, account settings COMPLAINT - user is complaining about service or experience PRODUCT - product usage or product details OTHER - none of the above Customer message: {{it}} Return only the enum name. )TicketTypeclassify(Stringtext);5. 生产环境要考虑失败情况大模型偶尔可能返回不符合预期的内容。比如你希望它返回POSITIVE但它可能返回The sentiment is POSITIVE.虽然 LangChain4j 通常会尝试解析但生产环境中仍然建议记录日志设置超时设置重试兜底返回UNKNOWN对重要结果做人工审核用测试集验证准确率二十、你可以怎么理解这篇文档用一句话总结这篇文档展示了如何用 LangChain4j 把大模型封装成一个 Java 分类服务让你像调用普通 Java 方法一样完成文本分类。核心代码就是这几部分ChatModelchatModelOpenAiChatModel.withApiKey(YOUR_OPENAI_API_KEY);创建模型。enumSentiment{POSITIVE,NEUTRAL,NEGATIVE}定义分类标签。interfaceSentimentAnalyzer{UserMessage(Analyze sentiment of {{it}})SentimentanalyzeSentimentOf(Stringtext);}定义 AI 服务接口。SentimentAnalyzeranalyzerAiServices.create(SentimentAnalyzer.class,chatModel);创建 AI 服务对象。Sentimentresultanalyzer.analyzeSentimentOf(I love this product!);执行分类。二十一、和传统 Java 开发思维的类比你可以这样类比传统 Spring BootLangChain4jController 接收请求Controller 接收用户文本Service 处理业务逻辑AI Service 调用大模型处理语义Repository 查询数据库ChatModel 调用模型服务DTO/Enum 接收结果Enum/boolean 接收 AI 分类结果注解配置行为UserMessage配置 promptLangChain4j 的价值是把大模型调用变成 Java 接口调用降低集成复杂度。最后总结这篇文档主要讲的是 LangChain4j 的文本分类能力。你需要重点掌握分类就是把文本归到预定义标签中。LangChain4j 支持用 LLM 或 Embedding 做分类。LLM 分类适合需要理解自然语言的复杂场景。Embedding 分类适合有大量已标注样本、基于相似度判断的场景。示例中定义了Sentiment枚举作为分类标签。UserMessage用来定义 prompt。AiServices.create()根据接口自动生成 AI 服务对象。返回值可以是 enum也可以是 boolean。在 Spring Boot 项目中建议把ChatModel和 AI Service 注册成 Bean。生产环境要注意 API Key 管理、prompt 稳定性、日志、异常兜底和结果验证。