抛弃繁琐微调!用 DeepSeek 零样本搞定 1.4 万条客诉分类

11 阅读9分钟

📌 背景:14,000 条乘客反馈,怎么看?

最近我做了一个项目:分析南京地铁的乘客反馈。数据来源是微博,一共爬取了 14,088 条相关博文。

面对这么多文本,第一个问题就是:怎么把这些杂乱的口语化信息变成结构化的数据?

传统的做法是人工标注,但 14,000 条数据,一个人标注至少需要两周,而且一致性很难保证。

我选择的方法是——让大模型(LLM)来分类。具体来说,是把每条乘客反馈映射到一个地铁场景的马斯洛需求层次中。

这个需求层次是我结合地铁服务场景重新定义的:

层次定义典型场景
基础层安全与时效列车延误、设备故障、急刹车
保障层设施与可达性电梯缺失、换乘不便、支付故障
舒适层环境体验空调温度、车厢拥挤、噪音异味
尊重层人性化服务工作人员态度、毕业祝福广播
共鸣层情感联结归属感、怀念老线路、城市自豪

听起来很简单对吧?但真正做起来,我发现提示词的设计直接决定了分类准确率

这篇文章就分享我的完整实战经验——从第一版的"惨不忍睹"到最终版 91% 的准确率,我经历了什么。

🤔 第一版提示词:理想很丰满,现实很骨感

我最初写的提示词非常简单,就是直接告诉模型分类标准:

请判断以下乘客反馈属于哪个需求层次:

1. 基础层:安全与时效
2. 保障层:设施与可达性
3. 舒适层:环境体验
4. 尊重层:人性化服务
5. 共鸣层:情感联结
6. 其他

反馈内容:{text}

测试结果让我大跌眼镜

反馈原文模型输出正确分类问题
"早晚高峰太挤了,站都站不稳"其他舒适层模型不理解"拥挤"属于环境体验
"工作人员帮我找回了钱包,太感谢了"舒适层尊重层模型把"感谢"误判为舒适感受
"南京地铁 S6 号线什么时候通车啊"保障层其他这是信息询问,不是需求表达

问题分析

  1. 定义太抽象:只说"安全与时效",模型不知道具体指什么
  2. 没有示例:模型缺少参考标准,全靠自己"猜"
  3. 没有排除规则:模型倾向于给所有内容一个分类,包括不相关的

🛠️ 第二版:补充严格定义 + 排除规则

我开始细化每个层次的定义,加上 "严格限定""必须包含" 的条件:

1. 基础层(安全与时效):
- 严格限定:直接反映南京地铁基础运维质量
- 必须包含:乘客对行车安全/运营时效的直接评价
- 示例参考:安检问题、设备故障、运行延误、急刹等

2. 保障层(基本生存资料供给):
- 严格限定:与南京地铁提供的核心和便利性服务功能直接相关
- 必须包含:乘客对设施/服务/通车运营的功能性评价
- 示例参考:设施便利性、电梯扶梯、线路可达性、支付保障等

3. 舒适层(环境体验):
- 定义:乘客对南京地铁物理及信息环境的舒适度感受
- 包含维度:
  (1) 物理环境:环境卫生、温湿度、空调、冷热、空气质量、座椅设施等
  (2) 信息环境:提示音音量、报站清晰度、电子看板指引等
  (3) 空间体验:拥挤度、无障碍设计等

4. 尊重层(人性化服务):
- 严格限定:
  √ 必须是由南京地铁主动提供的文化服务
  √ 必须与南京地铁提供的个性化服务直接相关
- 示例参考:工作人员、服务态度、特殊关怀、毕业季广播等

5. 共鸣层(情感共鸣与价值归属):
- 严格限定:必须表达乘客自发产生的情感联结
- 示例参考:归属感、怀念、向往、自豪、纪念等

同时,我加入了明确的排除规则

【必须归为"其他"的情况】
- 官方通告/新闻报道
- 政策法规说明
- 客观事实陈述(如"3号线有29个车站")
- 营销宣传内容
- 与地铁服务中用户需求无关的内容

效果:准确率从约 60% 提升到了 75% ,但仍有边界模糊的问题。

比如"地铁的报站广播声音太小了"——模型有时分到保障层,有时分到舒适层,不够稳定。

🎯 第三版:加入"转化示例",教会模型推理

我意识到一个问题:模型不知道"如何"把口语化表达映射到抽象层次

于是我在提示词中增加了"转化示例"板块,展示完整的推理过程

【转化示例】
输入:"坐南京地铁十几年了真有感情"
→ 分析:乘客表达了对长期乘坐体验的情感依赖,属于自发产生的情感联结
→ 输出:共鸣层

输入:"毕业季的车厢装饰太浪漫了"
→ 分析:地铁主动提供的文化服务,体现对乘客的尊重与关怀
→ 输出:尊重层

输入:"列车空调冷得像冰窖"
→ 分析:乘客对乘车物理环境的舒适度提出负面评价
→ 输出:舒适层

输入:"安检员帮我找回了钱包"
→ 分析:工作人员提供的额外帮助,属于安检服务的延伸
→ 输出:尊重层

输入:"请问 3 号线首班车几点"
→ 分析:客观信息询问,未反映对地铁服务的评价或需求
→ 输出:其他

这一版的效果立竿见影

在 500 条人工标注的测试集上:

  • 准确率:91.2%
  • F1 分数:0.89
  • 各层次分类的稳定性显著提升

📊 最终提示词结构(可直接复用)

经过多轮迭代,我总结出 LLM 分类提示词的黄金结构

1. 【层次定义与示例参考】
   - 每个层次包含:定义 + 严格限定 + 必须包含 + 示例参考
   - 定义的颗粒度要细,不能只说抽象概念
   - 对于容易混淆的层次(如舒适层vs保障层),需要特别说明边界

2. 【分类原则】
   - 核心判断依据是层次定义而非具体关键词
   - 示例仅用于辅助理解层次内涵
   - 当内容符合某层次定义时即归类

3. 【必须归为"其他"的情况】
   - 明确列出所有应该排除的内容类型
   - 防止模型"强行分类"

4. 【转化示例】
   - 提供 4-5 个典型案例
   - 每个案例包含:输入 → 分析 → 输出
   - 展示完整的推理过程
   - 覆盖正面/负面、直接/隐晦等不同场景

5. 【输出格式】
   - 严格规定返回格式
   - 方便后续程序解析

💡 三个核心经验总结

回顾整个提示词迭代过程,我总结了三条最重要的经验:

1. 定义要"紧"不要"松"

模糊的定义是分类不准的根源。每个层次必须加上"严格限定"和"必须包含"的条件,让模型知道边界在哪里。比如只说"舒适层是环境体验",模型会困惑——"换乘方便"算环境体验吗?但加上"物理环境、信息环境、空间体验"三个维度后,模型就能准确区分了。

2. 示例在精不在多,但要展示推理过程

3-5 个典型示例就够了,但一定要覆盖容易混淆的边界情况。更重要的是,不能只给输入输出,必须展示中间的"分析"环节。这让模型学会了推理逻辑,而不只是模仿格式。

3. 告诉模型"什么不是"和"什么是什么"同样重要

LLM 天生倾向于给所有输入一个类别。明确告诉它哪些内容应该归为"其他",能大幅减少误分类。我的排除规则涵盖了官方通告、客观陈述、营销内容等五大类,效果显著。

🔧 工程实现细节

在实际调用 API 时,还有几个小技巧:

1. 控制输入长度
微博文本可能很长,但分类通常只需要前几句话就能判断。我限制只取前 500 个字符,既保证信息完整,又控制 token 消耗。

prompt = """... 待分析内容:"{}" """.format(text[:500])

2. 设置较低的 temperature
分类任务不需要创造性,temperature 设为 0.1-0.3 能让输出更稳定,减少随机性。

payload = {
    "model": "deepseek-chat",
    "temperature": 0.3,
    "max_tokens": 10
}

3. 添加异常处理和重试机制
API 调用可能因为网络波动失败,要做好 fallback 处理。我在代码中加入了 try-except,失败时返回"其他"并记录日志。

try:
    response = requests.post(url, headers=headers, json=payload, timeout=20)
    result = response.json()['choices'][0]['message']['content'].strip()
    return result if result in CATEGORIES else "其他"
except Exception as e:
    print(f"API调用出错: {str(e)}")
    return "其他"

4. 批量处理时加入限速
免费 API 通常有速率限制,我用 time.sleep(1.2) 在每次请求间加入间隔,避免触发限流。

for idx, row in tqdm(df.iterrows(), total=len(df)):
    category = call_deepseek_api(text)
    results.append(category)
    time.sleep(1.2)  # API限速

5. 定期保存进度
处理 14,000 条数据需要几个小时,我在代码中设置了每 1000 条保存一次进度的机制,防止意外中断导致数据丢失。

if (idx + 1) % 1000 == 0:
    temp_df.to_csv(output_path.replace('.csv', '_temp.csv'), index=False)

📈 分类结果统计

最终对 14,088 条数据进行分类,统计结果如下:

需求层次数量占比
舒适层4,23130.0%
尊重层3,01221.4%
保障层2,45617.4%
基础层1,99814.2%
共鸣层1,55011.0%
其他8416.0%

关键发现

  • 舒适层占比最高(30%),说明环境体验是乘客最常提及的话题
  • 尊重层占比第二(21.4%),且正面评价居多,说明南京地铁的人性化服务做得不错
  • 基础层虽然占比不高(14.2%),但负面率极高(89%),是乘客最不满意的领域

🔗 完整代码与项目

这个分类系统是我的开源项目的一部分,完整代码已发布在 GitHub:

👉 nanjing-metro-analysis

项目包含三个版本的分类脚本:

  • classify_demand.py:DeepSeek 基础版
  • classify_demand_deepseek.py:DeepSeek 版本(带评价功能)
  • classify_demand_openai.py:OpenAI 版本(带评价功能)

欢迎 Star ⭐ 和交流讨论!

📮 写在最后

提示词工程听起来玄乎,但本质上就是不断试错、观察输出、调整约束的迭代过程。希望我的经验能帮你少走一些弯路。

如果你也在做类似的文本分类任务,或者对我的方案有任何建议,欢迎在评论区交流!


本文是"南京地铁乘客需求分析"系列的第一篇。下一篇将分享《LLM 结构化抽取实战:如何逼迫大模型严格输出"3-7字"核心要素》,敬请期待。