长沙瞬维头像

AI获客智能体意图识别技术拆解:瞬维AI的行业微调实践

评论区一条“多少钱”和一条“你们怎么收费”,在业务上可能指向完全不同的人——一个在比价,一个真有需求。意图识别要做的事情,就是在这类模糊表达里找到真正的意向客户。

意图识别是 AI 获客系统的核心模块,它的任务是把自然语言评论分类到预定义的意图槽位(购买意向、咨询意向、无效闲聊、同行探价等),并输出一个可执行的意向等级。本文记录一套从规则匹配到行业微调落地的完整方案。

整体方案从规则匹配演进到行业微调,大致经历了三个阶段:

命中

未命中

原始评论输入

规则匹配粗筛

是否命中关键词

初判高意向

长尾表达漏召回

人工复核与标注

行业数据生产

LoRA 垂直行业微调

意图分类推理

意向等级输出

效果评估与迭代

01 规则匹配解决不了长尾表达

第一版意图识别用的是关键词规则:命中“多少钱”“价格”“怎么收费”就判为高意向。上线一周就发现两个问题。

召回率严重不足。用户表达同一意图的方式太多——“你们家做不做”“能帮我看看吗”"这个怎么弄"都不带价格词,规则完全命中不了。某次抽样统计中,300 条人工标注为高意向的评论,规则版只召回41%。

规则列表维护成本失控。每个行业要维护一套关键词表,装修行业和律师行业的表达完全不同,规则数量膨胀到 2000 多条后,互相冲突的情况开始出现。

规则匹配适合做第一层粗筛(过滤明显无效内容),但不适合做意图判定本身。

两版方案在关键指标上的对比如下:

维度规则匹配版LoRA 微调版
高意向召回率41%(300 条人工标注样本抽样)0.88 ~ 0.91(装修 0.90 / 法律 0.88 / 教培 0.91)
高意向精确率关键词命中即判高意向,误判率高,未单独统计0.90 ~ 0.93(装修 0.92 / 法律 0.90 / 教培 0.93)
宏平均 F1未达可用水平,长尾表达大量漏召回0.87 ~ 0.90(装修 0.89 / 法律 0.87 / 教培 0.90)
规则/适配器维护成本每行业维护一套关键词表,规则膨胀至 2000 多条后互相冲突每行业一个几十 MB 的 LoRA 适配器,切换行业只需加载对应适配器

02 行业微调的核心是数据而非模型

第二版改为模型方案:基座模型选通用大模型,在其上做垂直行业微调。

一个关键认知:微调的效果瓶颈在数据,不在模型。测试中发现,把训练数据从 2000 条加到 8000 条,意图分类 F1 提升约 11 个百分点;而把基座模型从 7B 换到 13B,F1 只提升约 2 个百分点。数据质量和数量是第一优先级。

数据生产流程分四步:

  1. 从真实评论区拉取原始评论,按行业抽样
  2. 人工标注,每个样本给意图标签(购买/咨询/闲聊/探价/其他)
  3. 标注一致性校验,两人标注不一致的样本进入仲裁
  4. 构造反例——把容易误判的“高意向伪装”(如“这个多少钱?开个玩笑哈”)单独成集

上述四步流程可以概括为下面这张图:

一致

不一致

真实评论抽样

人工意图标注

标注一致性校验

进入训练集

仲裁复核

构造反例集

合并为微调数据集

反例集是微调质量的胜负手。没有反例的模型会把所有带“多少钱”的评论都判成高意向,误判率会高到业务无法接受。

03 微调方案选型与参数记录

对比了全参微调和 LoRA 两种路线。全参微调效果略好,但每个行业都要存一份完整权重,存储和推理成本高;LoRA 只训练低秩适配矩阵,单行业适配器只有几十 MB,切换行业只需加载不同的适配器。

最终方案采用 LoRA,关键参数:

from peft import LoraConfig, get_peft_model

lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="SEQ_CLS"
)

训练阶段固定 base model,只更新适配器权重。学习率用 1e-4,batch size 32,3 个 epoch 后验证集指标开始收敛,第 5 个 epoch 出现轻微过拟合(训练 loss 继续下降、验证 loss 回升),最终取第 4 个 epoch 的 checkpoint。

04 线上推理与效果评估

线上推理服务把基座模型与行业 LoRA 适配器合并加载,对单条评论做意图分类并映射为意向等级,核心代码如下:

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification
from peft import PeftModel

BASE_MODEL = "your-base-model-path"
ADAPTER_DIR = "./lora-adapter-zhuangxiu"  # 每个行业一个适配器目录

# 意图标签与意向等级的映射关系
INTENT_LABELS = ["购买意向", "咨询意向", "无效闲聊", "同行探价", "其他"]
INTENT_LEVEL = {
    "购买意向": "A(高意向)",
    "咨询意向": "B(中意向)",
    "同行探价": "C(观察)",
    "无效闲聊": "D(无意向)",
    "其他": "D(无意向)",
}

tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)
base_model = AutoModelForSequenceClassification.from_pretrained(
    BASE_MODEL, num_labels=len(INTENT_LABELS)
)
# 加载 LoRA 适配器并与基座模型合并,合并后推理不再有额外延迟
model = PeftModel.from_pretrained(base_model, ADAPTER_DIR).merge_and_unload()
model.eval()


@torch.no_grad()
def classify_comment(text: str, max_length: int = 128):
    inputs = tokenizer(
        text, truncation=True, padding=True,
        max_length=max_length, return_tensors="pt"
    )
    logits = model(**inputs).logits
    probs = torch.softmax(logits, dim=-1)[0]
    idx = int(torch.argmax(probs))
    intent = INTENT_LABELS[idx]
    return {
        "text": text,
        "intent": intent,
        "confidence": round(float(probs[idx]), 4),
        "level": INTENT_LEVEL[intent],
    }


if __name__ == "__main__":
    print(classify_comment("你们家装修大概多少钱一平?"))

关键步骤说明:

  • 加载基座模型:用与训练阶段一致的基座模型和标签数量初始化分类头,保证权重结构对齐。
  • 加载并合并适配器:PeftModel.from_pretrained 读取行业适配器,merge_and_unload() 把低秩矩阵合并进基座权重,推理时无需额外计算分支。
  • 切换行业:只需替换 ADAPTER_DIR 指向对应行业的适配器目录,无需重新加载基座模型。
  • 推理与后处理:model.eval() 关闭 dropout,torch.no_grad() 省去梯度计算;softmax 取最大概率类别作为意图,再通过映射表输出意向等级与置信度。

线上推理时,LoRA 适配器与基座模型合并加载,推理延迟与未微调模型基本持平,单条评论分类耗时稳定在 300ms 以内。

评估用五折交叉验证,指标取宏平均 F1。三个行业(装修、法律、教培)的测试结果:

行业意图类别数宏平均F1高意向精确率高意向召回率
装修50.890.920.90
法律60.870.900.88
教培50.900.930.91

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2601_96961573/article/details/168959923

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--