📌 背景:14,000 条乘客反馈,怎么看?
最近我做了一个项目:分析南京地铁的乘客反馈。数据来源是微博,一共爬取了 14,088 条相关博文。
面对这么多文本,第一个问题就是:怎么把这些杂乱的口语化信息变成结构化的数据?
传统的做法是人工标注,但 14,000 条数据,一个人标注至少需要两周,而且一致性很难保证。
我选择的方法是——让大模型(LLM)来分类。具体来说,是把每条乘客反馈映射到一个地铁场景的马斯洛需求层次中。
这个需求层次是我结合地铁服务场景重新定义的:
| 层次 | 定义 | 典型场景 |
|---|---|---|
| 基础层 | 安全与时效 | 列车延误、设备故障、急刹车 |
| 保障层 | 设施与可达性 | 电梯缺失、换乘不便、支付故障 |
| 舒适层 | 环境体验 | 空调温度、车厢拥挤、噪音异味 |
| 尊重层 | 人性化服务 | 工作人员态度、毕业祝福广播 |
| 共鸣层 | 情感联结 | 归属感、怀念老线路、城市自豪 |
听起来很简单对吧?但真正做起来,我发现提示词的设计直接决定了分类准确率。
这篇文章就分享我的完整实战经验——从第一版的"惨不忍睹"到最终版 91% 的准确率,我经历了什么。
🤔 第一版提示词:理想很丰满,现实很骨感
我最初写的提示词非常简单,就是直接告诉模型分类标准:
请判断以下乘客反馈属于哪个需求层次:
1. 基础层:安全与时效
2. 保障层:设施与可达性
3. 舒适层:环境体验
4. 尊重层:人性化服务
5. 共鸣层:情感联结
6. 其他
反馈内容:{text}
测试结果让我大跌眼镜:
| 反馈原文 | 模型输出 | 正确分类 | 问题 |
|---|---|---|---|
| "早晚高峰太挤了,站都站不稳" | 其他 | 舒适层 | 模型不理解"拥挤"属于环境体验 |
| "工作人员帮我找回了钱包,太感谢了" | 舒适层 | 尊重层 | 模型把"感谢"误判为舒适感受 |
| "南京地铁 S6 号线什么时候通车啊" | 保障层 | 其他 | 这是信息询问,不是需求表达 |
问题分析:
- 定义太抽象:只说"安全与时效",模型不知道具体指什么
- 没有示例:模型缺少参考标准,全靠自己"猜"
- 没有排除规则:模型倾向于给所有内容一个分类,包括不相关的
🛠️ 第二版:补充严格定义 + 排除规则
我开始细化每个层次的定义,加上 "严格限定" 和 "必须包含" 的条件:
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,231 | 30.0% |
| 尊重层 | 3,012 | 21.4% |
| 保障层 | 2,456 | 17.4% |
| 基础层 | 1,998 | 14.2% |
| 共鸣层 | 1,550 | 11.0% |
| 其他 | 841 | 6.0% |
关键发现:
- 舒适层占比最高(30%),说明环境体验是乘客最常提及的话题
- 尊重层占比第二(21.4%),且正面评价居多,说明南京地铁的人性化服务做得不错
- 基础层虽然占比不高(14.2%),但负面率极高(89%),是乘客最不满意的领域
🔗 完整代码与项目
这个分类系统是我的开源项目的一部分,完整代码已发布在 GitHub:
项目包含三个版本的分类脚本:
classify_demand.py:DeepSeek 基础版classify_demand_deepseek.py:DeepSeek 版本(带评价功能)classify_demand_openai.py:OpenAI 版本(带评价功能)
欢迎 Star ⭐ 和交流讨论!
📮 写在最后
提示词工程听起来玄乎,但本质上就是不断试错、观察输出、调整约束的迭代过程。希望我的经验能帮你少走一些弯路。
如果你也在做类似的文本分类任务,或者对我的方案有任何建议,欢迎在评论区交流!
本文是"南京地铁乘客需求分析"系列的第一篇。下一篇将分享《LLM 结构化抽取实战:如何逼迫大模型严格输出"3-7字"核心要素》,敬请期待。