📌 背景:13 个簇,每个叫什么名字?
在上一篇文章中,我用层次聚类 + 轮廓系数把 2000+ 个服务要素聚成了 13 个主题簇。
但现在面临一个新问题:这 13 个簇分别叫什么名字?
比如簇 6,里面有这些要素:
- 温度不适、空调过冷、闷热、冷气过强、车厢温度、制冷不足...
人工看完可以总结为"空调温度问题"。但 13 个簇一个一个看,太慢了。
我需要一种方法:输入一个簇的所有要素,自动输出一个标准化的名称。
这就是"语义对齐"——让 LLM 理解一个簇的语义核心,并用统一的格式表达出来。
🏷️ 语义对齐设计
我设计了一套标准化的输出格式:
text
乘客 + (类型) + 核心问题
类型有三种:
- (需求) :乘客主动提出的改进需求
- (问题) :乘客反映的现存问题
- (评价) :乘客表达的服务评价
示例:
乘客(问题)空调温度不适乘客(评价)赞赏暖心毕业祝福乘客(需求)增加高峰班次
这样设计的好处:
- 主语统一:都是"乘客",视角一致
- 类型明确:一看就知道是问题、需求还是评价
- 格式固定:方便后续统计和展示
- 可操作性强:运营方可以直接根据类型采取行动
🛠️ 提示词设计
我设计的提示词包含以下几个部分:
prompt = f"""
请将以下关于地铁服务的乘客反馈提炼为最核心的标准化表述,要求:
1. 输出仅一条标准化表述
2. 只保留最本质的需求/问题/感受
3. 使用"乘客"作为主语
4. 采用"乘客+核心诉求"的极简结构
5. 不要包含具体线路、时段等细节
【输出规范】
1. 格式:严格遵循"乘客+[诉求类型]+[核心问题]"结构
2. 长度:不超过20个汉字(含标点)
3. 诉求类型标注:
- (需求) 乘客主动提出的改进需求
- (问题) 乘客反映的现存问题
- (评价) 乘客表达的服务评价
4. 必须包含最高频核心词
5. 优先选择出现频率最高的诉求类型
【优化原则】
1. 聚焦可行动项(运营方可直接解决的问题)
2. 保留程度副词(如"过度拥挤"vs"轻微拥挤")
3. 区分问题类型(设施/服务/管理等)
4. 消除模糊表述(如"改善服务"→"增加安检速度")
【典型范例】
好的输出:
"乘客(需求)增加高峰班次"
"乘客(问题)闸机故障率高"
"乘客(评价)赞赏问询服务"
"乘客(评价)赞赏暖心毕业祝福"
差的输出:
"希望改进"(缺少主语和类型)
"3号线太挤"(含具体线路)
待分析文本:
{texts}
【最终输出】(只需返回标准表述,不要解释):
"""
📊 对齐结果展示
运行语义对齐后,13 个簇的标准表述如下:
| 簇 ID | 要素数 | 标准化表述 | 类型 |
|---|---|---|---|
| 1 | 152 | 乘客(评价)乘车环境舒适 | 评价 |
| 2 | 161 | 乘客(评价)赞赏工作人员贴心服务 | 评价 |
| 3 | 183 | 乘客(评价)出行高效便捷 | 评价 |
| 4 | 438 | 乘客(评价)赞赏文化创意活动 | 评价 |
| 5 | 546 | 乘客(评价)赞赏暖心毕业祝福 | 评价 |
| 6 | 584 | 乘客(问题)空调温度不适 | 问题 |
| 7 | 390 | 乘客(问题)车厢过度拥挤 | 问题 |
| 8 | 295 | 乘客(问题)电梯扶梯设施不足 | 问题 |
| 9 | 179 | 乘客(问题)列车故障与延误 | 问题 |
| 10 | 232 | 乘客(问题)票价与效率性价比低 | 问题 |
| 11 | 285 | 乘客(问题)管理服务混乱 | 问题 |
| 12 | 229 | 乘客(问题)乘坐体验不舒适 | 问题 |
| 13 | 182 | 乘客(问题)环境卫生与噪音 | 问题 |
一目了然!
- 正面评价集中在簇 1-5:舒适体验、贴心服务、高效出行、文化活动、暖心祝福
- 负面问题集中在簇 6-13:空调温度、拥挤、设施不足、故障延误...
💡 批量处理技巧
1. 控制输入长度
每个簇可能有几百个要素,全部输入会超 token。我取前 20 个代表性要素作为输入:
def align_semantics(texts, max_samples=20):
# 按频率排序,取前20个
sample_texts = texts[:max_samples]
prompt = f"""... 待分析文本:{sample_texts} ..."""
2. 低温度保证一致性
对齐任务需要稳定输出,temperature 设为 0.1:
data = {
"model": "deepseek-chat",
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.1,
"max_tokens": 100
}
3. 异常处理
API 调用可能失败,要有 fallback:
try:
response = requests.post(url, headers=headers, json=data, timeout=30)
result = response.json()['choices'][0]['message']['content'].strip()
return result
except Exception as e:
print(f"API调用失败: {e}")
return "【自动生成】" + texts[0][:50] + "..."
📐 完整代码
def align_semantics(texts):
"""使用DeepSeek API进行语义对齐"""
prompt = f"""
请将以下关于地铁服务的乘客反馈提炼为最核心的标准化表述,要求:
1. 输出仅一条标准化表述
2. 只保留最本质的需求/问题/感受
3. 使用"乘客"作为主语
4. 采用"乘客+核心诉求"的极简结构
【输出规范】
格式:严格遵循"乘客+[诉求类型]+[核心问题]"结构
诉求类型:(需求)/(问题)/(评价)
【典型范例】
"乘客(需求)增加高峰班次"
"乘客(问题)闸机故障率高"
"乘客(评价)赞赏暖心毕业祝福"
待分析文本:
{texts[:20]} # 取前20个代表样本
【最终输出】:
"""
headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
data = {
"model": "deepseek-chat",
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.1,
"max_tokens": 100
}
response = requests.post(DEEPSEEK_API_URL, headers=headers, json=data, timeout=30)
return response.json()['choices'][0]['message']['content'].strip()
💡 三条核心经验
1. 标准化格式是灵魂
"乘客(问题)空调温度不适" 比 "空调问题" 好在哪里?
- 明确了主体(乘客视角)
- 明确了性质(这是一个"问题",不是"评价"或"需求")
- 运营方看到"(问题)"就知道需要解决,看到"(评价)"就知道是表扬
2. 输入样本要精选
不要把所有要素都扔给 LLM。取频次最高的前 20 个,既能代表簇的核心语义,又不会超 token。
3. 范例要覆盖不同类型
我给的范例覆盖了三种类型(需求/问题/评价),让模型知道每种类型应该怎么表述。
🔗 完整代码与项目
完整实现已开源在 GitHub:
👉 nanjing-metro-analysis/notebooks/02_semantic_alignment.ipynb
📮 写在最后
语义对齐是连接"机器聚类"和"人类理解"的桥梁。聚类算法只能把相似的放一起,但给这个簇起什么名字、如何标准化表述,还是需要 LLM 的语言能力。
下一篇是系列的最后一篇——《马斯洛理论重构地铁服务:挖掘 14,088 条文本背后的真实诉求》,我会把所有分析结果汇总,给出完整的业务洞察和运营建议。
本文是"南京地铁乘客需求分析"系列的第四篇。