删除后台管理界面:用声明式权限实现安全与效率双赢
2026/7/14 10:01:39
智能客服每天面对的不是标准考题,而是“人话”——充满省略、倒装、方言甚至错别字。把一句“我那个啥,咋还没到账?”准确映射到“查询转账进度”这个意图,比想象的要难:
一句话,意图识别既要“准”,又要“快”,还要“省”。
| 方案 | 准确率(Top-1) | 平均响应时间 | 训练成本 | 备注 |
|---|---|---|---|---|
| 正则+关键词 | 62% | 2 ms | 几乎0 | 规则冲突后维护爆炸 |
| SVM+TF-IDF | 78% | 8 ms | 1 h/1w样本 | 特征工程苦力活 |
| TextCNN+Word2Vec | 84% | 12 ms | 2 h/1w样本 | 对语序不敏感 |
| BERT-base微调 | 91.5% | 90 ms | 1 h/5w样本 | GPU显存≥8 G |
| BERT+蒸馏(TinyBERT) | 89% | 18 ms | +2 h蒸馏 | 精度掉2%以内,省5×显存 |
结论:
下面用银行客服场景demo,意图共10类,样本极度不平衡(“查询余额”占60%,其余分散)。
# dataset.py import torch, json, random from transformers import BertTokenizer from sklearn.utils import resample tokenizer = BertTokenizer.from_pretrained("bert-base-chinese") def load_samples(path): with open(path, encoding="utf-8") as f: data = [json.loads(l) for l in f] # 分层采样,解决imbalance df = pd.DataFrame(data) balanced = df.groupby("label", group_keys=False).apply( lambda x: resample(x, n_samples=2000, replace=True, random_state=42) ) return balanced.values.tolist() def encode(text, max_len=32): return tokenizer(text, max_length=max_len, padding="max_length", truncation=True)class IntentDataset(torch.data.Dataset): def __init__(self, samples): self.samples = samples def __getitem__(self, idx): text, label = self.samples[idx] encoded = encode(text) return {k: torch.tensor(v) for k,v in encoded.items()}, \ torch.tensor(int(label)) def __len__(self): return len(self.samples)class FocalLoss(torch.nn.Module): def __init__(self, alpha=1, gamma=2): super().__init__() self.alpha, self.gamma = alpha, gamma def forward(self, logits, labels): ce = torch.nn.functional.cross_entropy(logits, labels, reduction="none") p = torch.exp(-ce) return (self.alpha * (1-p)**self.gamma * ce).mean()# train.py from transformers import BertForSequenceClassification, Trainer, TrainingArguments model = BertForSequenceClassification.from_pretrained( "bert-base-chinese", num_labels=10) training_args = TrainingArguments( output_dir="./ckpt", per_device_train_batch_size=64, learning_rate=2×10⁻⁵, num_train_epochs=3, logging_steps=50, save_total_limit=2, load_best_model_at_end=True, metric_for_best_model="f1" ) trainer = Trainer( model=model, args=training_args, train_dataset=IntentDataset(load_samples("train.json")), eval_dataset=IntentDataset(load_samples("dev.json")), compute_metrics=lambda p: {"f1": f1_score(p.label, p.predictions.argmax(-1))}, # 关键:替换默认CE loss_fct=FocalLoss(alpha=1, gamma=2) ) trainer.train()def show_attention(sentence, layer=11, head=0): inputs = encode(sentence) with torch.no_grad(): out = model.bert(**{k:v.unsqueeze(0) for k,v in inputs.items()}, output_attentions=True) att = out.attentions[layer][0, head].cpu() # [seq_len, seq_len] sns.heatmap(att, xticklabels=tokenizer.convert_ids_to_tokens(inputs["input_ids"]))把这三个问题想明白,你的智能客服就离“真智能”又近了一步。