news 2026/7/4 2:32:18

意图识别是怎么做的:AI 客服为什么要先判断“用户想干什么”

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
意图识别是怎么做的:AI 客服为什么要先判断“用户想干什么”

如果你想把这篇文章和源码对着看,可以先留意文中出现的几个文件名。这个系列会继续按源码往后拆;如果这种拆解方式对你有帮助.

这一篇看:

TEXT

server/src/services/intentService.js

它解决的问题是:

TEXT

用户发来一句话,系统怎么判断他是要查订单、问商品、退款、投诉,还是普通问答?

在 AI 客服里,意图识别是后续所有动作的入口。

如果意图识别错了,后面可能就会:

  • 该查订单却去查知识库
  • 该退款却只生成安慰话术
  • 该追问订单号却直接说处理成功
  • 用户情绪激动却没有触发人工升级

所以这个项目没有把用户消息直接丢给大模型回复,而是先走intentService.process()

5.1 意图识别要解决什么问题

先看项目支持的意图:

JS

const VALID_INTENTS = new Set([ 'QUERY_ORDER', 'CANCEL_ORDER', 'REFUND', 'COMPLAINT', 'PRODUCT_INQUIRY', 'GENERAL_QA', 'UNKNOWN',]);

这些意图对应客服场景:

意图用户可能怎么说
QUERY_ORDER我的订单到哪了?
CANCEL_ORDER帮我取消订单
REFUND我要退款
COMPLAINT我要投诉,太差了
PRODUCT_INQUIRY这款耳机还有货吗?
GENERAL_QA你们几点上班?
UNKNOWN模型和规则都不确定

意图识别不只是给消息打标签。

它还要提取实体:

JSON

{ "order_id": "1001", "product_name": "南屿 AirBuds 2 主动降噪耳机", "reason": "不想要了", "content": "投诉内容"}

并判断:

  • 置信度高不高
  • 情绪是什么
  • 是否需要澄清
  • 是否引用上一轮
  • 检索知识库时用什么 query

5.2 process 的整体步骤

核心入口是:

JS

async function process(message, session) { // ...}

整个流程可以画成:

Mermaid 流程图静态示意

用户消息 + session

并发读取历史、设置、意图上下文

B

deepseekService.recognize() / 大模型初步识别

C

规则修正 / 商品名、关键词、指代

D

实体合并和规范化

E

情绪历史更新 / 判断是否安抚/升级

F

是否需要澄清

G

是| H[“返回 clarification”]

G

否| I[“更新 intent_context”]

I

返回完整 intentResult

这个流程体现了项目的一个设计:

TEXT

大模型先判断,代码再兜底修正。

5.3 为什么第一步要并发读取三类数据

process()一开始并发读取:

JS

const [history, settings, intentContext] = await Promise.all([ contextService.getPlainContext(session.id), actionService.getSettings(), contextService.getIntentContext(session.id),]);

这三类数据分别是:

数据用途
history最近聊天记录,帮助理解上下文
settings店铺名、营业时间、系统提示词等
intentContext多轮意图状态和已收集实体

为什么要并发?

因为这三件事互不依赖。

顺序读取会浪费时间:

TEXT

读历史 -> 读设置 -> 读上下文

并发读取更快:

TEXT

同时读历史、设置、上下文

聊天接口对响应速度很敏感,所以这里用Promise.all()

5.4 DeepSeek 初步识别

读完上下文后,项目调用:

JS

const recognized = await deepseekService.recognize(message, history, settings);

deepseekService.recognize()会走 LangChain 的意图识别链。

大模型返回类似:

JSON

{ "intent": "PRODUCT_INQUIRY", "entities": { "product_name": "南屿 AirBuds 2", "order_id": null, "reason": null, "content": null }, "confidence": 0.82, "emotion": "neutral", "emotion_score": 0.1, "needs_clarification": false, "reference_to_previous": false}

这一步很重要,但项目没有完全相信它。

5.5 为什么还要自己写规则,不完全相信大模型

项目里写了很多正则规则:

JS

const PRODUCT_QUESTION_RE = /(商品|产品|多少钱|价格|库存|有货|还有|介绍|怎么样|参数|规格|续航|颜色|尺寸|卖点)/;const ORDER_RE = /(订单|物流|发货|快递|购买记录|买的|我的订单)/;const REFUND_RE = /(退款|退货|退钱|售后)/;const CANCEL_RE = /(取消订单|取消|不想要)/;const COMPLAINT_RE = /(投诉|生气|差评|不满意|人工|客服|解决不了)/;

这些规则用于修正模型结果:

JS

function inferIntent(message, entities, recognizedIntent) { if (entities.product_name || PRODUCT_QUESTION_RE.test(message)) return 'PRODUCT_INQUIRY'; if (REFUND_RE.test(message)) return 'REFUND'; if (CANCEL_RE.test(message)) return 'CANCEL_ORDER'; if (ORDER_RE.test(message)) return 'QUERY_ORDER'; if (COMPLAINT_RE.test(message)) return 'COMPLAINT'; return VALID_INTENTS.has(recognizedIntent) ? recognizedIntent : 'UNKNOWN';}

为什么要这样?

因为客服系统不能完全靠模型“感觉”。

比如用户说:

TEXT

我要退款

无论模型怎么犹豫,规则都能明确把它识别为:

TEXT

REFUND

再比如用户说:

TEXT

订单什么时候发货?

关键词“订单、发货”强烈指向:

TEXT

QUERY_ORDER

规则不是为了替代大模型,而是为了给关键业务场景加保险。

5.6 实体规范化

项目会把模型返回的实体做规范化:

JS

function normalizeEntities(raw = {}) { const entities = { order_id: raw.order_id || null, product_name: raw.product_name || null, reason: raw.reason || null, content: raw.content || null, }; if (entities.product_name) { entities.product_name = String(entities.product_name).trim() || null; } if (entities.order_id) { const match = String(entities.order_id).match(/\d+/); entities.order_id = match ? match[0] : null; } return entities;}

这一步的作用是:

  • 去掉空字符串
  • 商品名 trim
  • 订单号只保留数字部分
  • 确保字段结构稳定

例如模型返回:

JSON

{ "order_id": "订单号:1001"}

规范化后变成:

JSON

{ "order_id": "1001"}

这样后面actionService.cancelOrder()才能直接查数据库。

商品名还会用数据库做确定性匹配

项目里还有一个inferProductName()

JS

async function inferProductName(message) { const [rows] = await pool.execute( "SELECT name FROM products WHERE status = 'active' ORDER BY CHAR_LENGTH(name) DESC LIMIT 200" ); let best = null; let bestScore = 0; for (const row of rows) { const score = scoreProductName(message, row.name); if (score > bestScore) { best = row.name; bestScore = score; } } return bestScore >= 2 ? best : null;}

也就是说,项目会从 MySQL 商品表里拿商品名,和用户消息做匹配。

比如种子数据里有:

TEXT

南屿 AirBuds 2 主动降噪耳机南屿 Watch S3 运动健康手表南屿 PowerCell 20000mAh 快充电源

用户问:

TEXT

AirBuds 2 还有货吗?

即使模型没有准确抽取商品名,规则也可能从数据库商品名里补回来。

5.7 多轮上下文怎么处理

用户经常不会每轮都说完整。

例如:

TEXT

用户:南屿 AirBuds 2 多少钱?客服:价格是 399 元。用户:那它还有货吗?

第二句里的“它”,需要继承上一轮商品名。

项目用正则识别这种指代:

JS

const PREVIOUS_REFERENCE_RE = /(它|这个|那个|这款|那款|刚才|上面|前面|刚刚|还有吗|多少钱|价格|库存|有货)/;

如果判断是引用上一轮:

JS

if (referenceToPrevious) { collectedEntities = mergeEntities( intentContext.collected_entities || {}, collectedEntities );}

intentContext保存在sessions.intent_context字段里。

更新时:

JS

const updatedIntentContext = { active_intent: activeIntent, collected_entities: collectedEntities, turn_count: turnCount, pending_slots: intentContext.pending_slots || [], last_user_message: message, updated_at: new Date().toISOString(),};await contextService.updateIntentContext(session.id, updatedIntentContext);

这就是项目实现多轮意图跟踪的方式。

5.8 澄清逻辑

有些意图必须要关键信息。

比如退款和取消订单,需要订单号:

JS

function missingRequiredSlot(intent, entities, message) { if (['CANCEL_ORDER', 'REFUND'].includes(intent)) { return !entities.order_id; } if (intent === 'PRODUCT_INQUIRY' && PRODUCT_QUESTION_RE.test(message)) { if (PRODUCT_LIST_RE.test(message)) return false; return !entities.product_name; } return false;}

如果缺少必要信息,就返回澄清:

JS

if (shouldClarify) { return { type: 'clarification', intent: activeIntent, entities: collectedEntities, confidence, lowConfidence, message: recognized.clarification_question || clarificationMessage(activeIntent), };}

例如用户说:

TEXT

我要退款

系统会问:

TEXT

请告诉我需要处理的订单号,我来继续帮您查询。

而不是直接申请退款。

5.9 情绪升级逻辑

意图识别还会识别情绪:

TEXT

emotionemotion_score

项目会记录情绪历史:

JS

const { shouldEscalate } = await contextService.updateEmotionHistory( session.id, emotion_score);

如果用户连续两轮情绪分数都大于0.9,就触发人工升级。

同时,如果情绪分数大于0.75

JS

const sootheMode = emotion_score > 0.75;

后面生成回复时,会加入安抚语气。

这说明意图识别不只是“分类”,还会影响客服的语气和人工介入。

用一个完整例子串起来

用户说:

TEXT

这个耳机还有货吗?

假设上一轮聊的是:

TEXT

南屿 AirBuds 2 主动降噪耳机

流程是:

TEXT

读取历史、设置、intent_context-> DeepSeek 初步识别 PRODUCT_INQUIRY-> 规则识别“这个/还有货”是上一轮指代-> 从 intent_context 继承 product_name-> 判断不需要澄清-> 更新 intent_context-> 返回 retrievalQuery

最终intentResult可能是:

JSON

{ "intent": "PRODUCT_INQUIRY", "entities": { "product_name": "南屿 AirBuds 2 主动降噪耳机" }, "emotion": "neutral", "sootheMode": false, "retrievalQuery": "南屿 AirBuds 2 主动降噪耳机\n这个耳机还有货吗?"}

后面的 Agent 才能继续:

TEXT

查商品库存-> 检索商品知识-> 生成客服回复

最后用一句话记住

在这个项目里,意图识别不是简单调用一次大模型。

它是一个组合流程:

TEXT

历史上下文 + 店铺设置 + 大模型识别 + 规则修正 + 实体规范化 + 多轮状态 + 情绪记录 + 澄清判断。

看懂intentService.process(),就看懂了 AI 客服为什么能从一句自然语言里决定下一步业务动作。

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 20:24:47

AT8563T实时时钟(RTC)故障排查报告

故障描述1.在使用这款RTC芯片时,每过一段时间时间会被重置。设备发生的环境1.设备做了温度测试,拿出来跑压力测试会出现时间重置的现象;排查思路1.时间被重置后,上图是规格书,该芯片内置一个低电压检测器,我…

作者头像 李华
网站建设 2026/7/3 5:40:19

注解的基本语法

定义注解 使用interface关键字来定义注解: public interface AutoFill { } 元注解 元注解是用来注解其他注解的注解,Java提供了以下几种元注解: Target - 指定注解可以应用的目标元素类型 Retention - 指定注解的保留策略 Documented - …

作者头像 李华
网站建设 2026/7/3 11:13:36

告别泰拉瑞亚原版限制:tModLoader模组开发实战手册

告别泰拉瑞亚原版限制:tModLoader模组开发实战手册 【免费下载链接】tModLoader A mod to make and play Terraria mods. Supports Terraria 1.4 (and earlier) installations 项目地址: https://gitcode.com/gh_mirrors/tm/tModLoader 还在为泰拉瑞亚原版内…

作者头像 李华
网站建设 2026/7/2 7:07:59

define和typedef的区别详解

前言在C/C编程中,#define和typedef都常用于为类型或值起一个别名,但它们的工作原理、适用场景和行为差异却天差地别。很多初学者甚至有一定经验的开发者都容易混淆二者,写出“看似正确却暗藏隐患”的代码。本文将深入剖析#define与typedef的本…

作者头像 李华