继续我们的langchain4j学习之旅,很多“智能客服”之类的AI应用,“问题分类”是非常重要的功能之一。比如:客人进来咨询问题,得判断出客人的问题是“订单相关”(比如:我要取消订单),还是“支付相关”(比如:我要退款),还是“投诉相关”(比如:你们的服务太差了,我要投诉到相关部门)。识别出对应分类后,就可以交给相应的流程(或细分的sub agent)做进一步处理。
langchain4j 提供了2种分类方法:
一、基于LLM的语义理解
1.1 定义分类枚举- enum CustomerServiceCategory {
- PRODUCT("产品相关"),
- ORDER("订单相关"),
- ACCOUNT("账户相关"),
- MEMBER("会员相关"),
- PAYMENT("支付相关"),
- OTHERS("其它问题");
- @Getter
- private final String desc;
- CustomerServiceCategory(String desc) {
- this.desc = desc;
- }
- }
复制代码 1.2 定义AIService的接口- interface CustomerServiceCategoryClassifier {
- @UserMessage("将客人遇到的问题【{{text}}】归类")
- CustomerServiceCategory classify(String text);
- }
复制代码 1.3 测试- @GetMapping(value = "/classify", produces = MediaType.APPLICATION_JSON_VALUE)
- public ResponseEntity<String> classify(@RequestParam String query) {
- try {
- CustomerServiceCategoryClassifier customerServiceClassifier = AiServices.create(CustomerServiceCategoryClassifier.class, ollamaChatModel);
- CustomerServiceCategory classify = customerServiceClassifier.classify(query);
- return ResponseEntity.ok(classify.getDesc());
- } catch (Exception e) {
- log.error("classify", e);
- return ResponseEntity.ok("{"error":"classify error: " + e.getMessage() + ""}");
- }
- }
复制代码 效果:
观察日志的话,能看到与LLM的交互:- 2025-12-09T21:00:57.280+08:00 INFO 5948 --- [langchain4j-study] [io-8080-exec-10] d.l.http.client.log.LoggingHttpClient : HTTP request:
- - method: POST
- - url: http://localhost:11434/api/chat
- - headers: [Content-Type: application/json]
- - body: {
- "model" : "deepseek-v3.1:671b-cloud",
- "messages" : [ {
- "role" : "user",
- "content" : "将客人遇到的问题【我的退款为什么还没到账?】归类\nYou must answer strictly with one of these enums:\nPRODUCT\nORDER\nACCOUNT\nMEMBER\nPAYMENT\nOTHERS"
- } ],
- "options" : {
- "stop" : [ ]
- },
- "stream" : false,
- "tools" : [ ]
- }
复制代码 这种方法的准确性完全取决于模型能力的强弱,大多数情况下是OK的,但有些case可能会不太符合我们的预期,比如:
一些互联网平台,对于“积分”可能会归到【会员相关】(比如:积分累积到了一定程度,可以兑换成高等级会员),这时候就可以考虑第2种方法。
二、基于向量数据库的相似度计算
2.1 先梳理已知问题的归类- Map<CustomerServiceCategory, List<String>> getExamples() {
- Map<CustomerServiceCategory, List<String>> examples = new HashMap<>();
- examples.put(PRODUCT, asList(
- "怎么没有产品说明书?",
- "产品的保修期过了怎么办?",
- "我新买的东西用了一周就坏了?",
- "产品无法使用?"
- ));
- examples.put(ORDER, asList(
- "我的订单现在到哪里了?",
- "能给我一个快递单号吗?",
- "我怎么知道我的订单已经发货了?",
- "我可以更改配送方式吗?",
- "你们提供次日达服务吗?",
- "可以选择到店自提吗?",
- "我的订单什么时候能到?",
- "为什么我的配送延迟了?",
- "我可以指定配送日期吗?",
- "已经过了预计送达日期,我的订单在哪里?",
- "如果出现延迟,我会收到通知吗?",
- "天气原因会导致配送延迟多久?",
- "我收到了订单,但少了一件商品。",
- "包裹送达时是空的。",
- "我收到的商品错了,该怎么办?",
- "我所有的商品会同时送达吗?",
- "为什么我只收到部分订单商品?",
- "剩下的商品能更快送达吗?"
- ));
- examples.put(PAYMENT, asList(
- "能用支付宝吗?",
- "微信支付可以吗?",
- "支持信用卡吗?",
- "付款时我遇到一个错误",
- "可以通过银行转账付款吗?",
- "为什么我的付款被拒绝了",
- "可以给我发送上一笔订单的发票吗?",
- "发票会自动发送到我的电子邮箱吗?",
- "如何申请退款?"
- ));
- examples.put(MEMBER, asList(
- "我的会员等级变低了?",
- "我的积分过期了?",
- "我的优惠券不能用了?",
- "能给我发个支付95折优惠券吗?",
- "满减优惠券当次消费就能用吗?",
- "能送100点优惠积分吗?"
- ));
- examples.put(ACCOUNT, asList(
- "如何注销账号?",
- "我的密码过期了?",
- "为什么无法登录",
- "登录时手机收不到验证码",
- "如果更换账号绑定的手机号"
- ));
- examples.put(OTHERS, asList(
- "厂商的联系电话是多少?",
- "如何加盟?",
- "你们公司还招人吗?"
- ));
- return examples;
- }
复制代码 2.2 使用embedding模型分类- @GetMapping(value = "/classify/embed", produces = MediaType.APPLICATION_JSON_VALUE)
- public ResponseEntity<String> classifyEmbed(@RequestParam String query) {
- try {
- TextClassifier<CustomerServiceCategory> classifier = new EmbeddingModelTextClassifier<>(ollamaEmbeddingModel, getExamples());
- List<CustomerServiceCategory> categories = classifier.classify(query);
- String result = "";
- if (!CollectionUtils.isEmpty(categories)) {
- CustomerServiceCategory classify = categories.get(0);
- result += classify.getDesc() + ",";
- }
- return ResponseEntity.ok(StringUtils.trimTrailingCharacter(result, ','));
- } catch (Exception e) {
- log.error("classify", e);
- return ResponseEntity.ok("{"error":"classify error: " + e.getMessage() + ""}");
- }
- }
复制代码
刚才的case符合预期了,但该方法有缺陷也十分明显,如果梳理的已知问题分类不够全面,会出现误判,比如:
这个问题不在事先准备好的问题列表中,计算出来的结果就差强人意了。实际应用中,如何取舍看业务场景,或者二者结合使用(比如:2个方法都跑一遍,看是否一致,然后再根据一定策略做处理。或者先用方法1,先做一轮分类,将结果人工复检后,用于完善方法2中的分类列表)
文中示例代码:GitHub - yjmyzz/langchain4j-study at day07
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |