news 2026/6/24 4:19:29

94万条热线问题的分析之路——KMeans聚类、动态相似度与大模型分类

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
94万条热线问题的分析之路——KMeans聚类、动态相似度与大模型分类

94万条热线问题的分析之路——KMeans聚类、动态相似度与大模型分类

文章目录

  • 94万条热线问题的分析之路——KMeans聚类、动态相似度与大模型分类
    • 一、问题:94万条问题,人工看不完
    • 二、方法一:KMeans + TF-IDF粗分
      • 原理
      • 效果
    • 三、方法二:向量相似度动态聚类
      • 思路
      • 效果
    • 四、方法三:大模型语义分类
      • DeepSeek分类
      • 效果
    • 五、知识库覆盖率分析
    • 六、三种方法的对比

某政务热线有94万条历史问题,怎么搞清楚这些问题到底在问什么?哪些是高频的?哪些知识库还没覆盖?这篇记录我用三种方法分析这批数据的过程:KMeans聚类做粗分、向量相似度做精分、大模型做语义分类。


一、问题:94万条问题,人工看不完

94万条问题,格式是这样的:

退休了医保怎么办 社保卡丢了怎么补办 灵活就业人员怎么参保 ...

没有分类标签,没有结构化信息,就是一堆文本。要回答三个问题:

  1. 这些问题可以分成几大类?参保?缴费?社保卡?
  2. 哪些问题是重复的?94万里有多少是同一件事换了个问法
  3. 高频问题我们的知识库覆盖了多少?

二、方法一:KMeans + TF-IDF粗分

原理

TF-IDF把每条问题转成一个稀疏向量(关键词权重),KMeans把向量聚成N个簇,同一个簇里的问题被认为是一类。

importjiebafromsklearn.feature_extraction.textimportTfidfVectorizerfromsklearn.clusterimportKMeansimportcsv texts=[]withopen('problem.csv','r',encoding="utf-8")asfile:csv_reader=csv.reader(file)forrowincsv_reader:texts.append(row[0])defchinese_tokenizer(text):returnjieba.cut(text)vectorizer=TfidfVectorizer(tokenizer=chinese_tokenizer)X=vectorizer.fit_transform(texts)kmeans=KMeans(n_clusters=5000,random_state=42)kmeans.fit(X)labels=kmeans.labels_withopen("result.txt","w",encoding="utf-8")asfile:fori,textinenumerate(texts):file.write(f"{text}\t{labels[i]}\n")

jieba分词 → TF-IDF提取特征 → KMeans聚5000个簇。

效果

5000个簇意味着平均每个簇约188条问题(94万/5000)。同一个簇里的问题确实有关联性,比如簇#1234里可能全是"退休"相关的问题。

问题:TF-IDF是基于关键词的,不理解语义。"退休怎么办"和"到了法定年龄怎么办理退休手续"分词结果不同,可能被分到不同的簇。粗分可用,精细不够。


三、方法二:向量相似度动态聚类

上一篇文章里把问题都向量化存到了Milvus。现在用向量相似度做更精准的聚类。

思路

从第一条问题开始,在Milvus里搜所有和它余弦相似度>0.95的问题,归为一类。然后找下一条还没被归类的问题,重复这个过程。

search_params={"metric_type":"COSINE","params":{"radius":0.95}}getedlist=[]foriinrange(1,93936):qs=client.get(collection_name="p_hotline",ids=[i],output_fields=["uid","Question","embeddings_Q"])v=qs[0]["embeddings_Q"]uid=qs[0]["uid"]ifuidingetedlist:continueres=client.search(collection_name="p_hotline",data=[v],limit=10000,output_fields=["uid","Question"],search_params=search_params)forjinrange(0,res[0].__len__()):getedlist.append(res[0][j]["entity"]["uid"])file.write(str(uid)+"\t"+str(res[0][j]["entity"]["uid"])+"\t"+str(res[0][j]["distance"])+"\t"+res[0][j]["entity"]["Question"]+"\n")

关键设计

  1. 相似度阈值0.95起步——非常严格,只有几乎一样的问题才会归到一起
  2. 已归类的问题跳过——getedlist记录所有已归类的问题ID,避免重复处理
  3. 逐条遍历93936条——对每条未归类的问题,搜索所有和它相似的问题

效果

比KMeans精准得多。"退休怎么办"和"到了退休年龄怎么办理"相似度>0.95,会被归到一类。因为用的是语义向量,不是关键词。

问题:慢。93936条,每条都要搜一次Milvus,跑了几个小时。


四、方法三:大模型语义分类

KMeans粗分、向量聚类精分,都还需要人去看每个簇/类的代表问题来确定分类名称。能不能让大模型直接分类?

DeepSeek分类

fromopenaiimportOpenAI ctext=("分类为参保、缴费、社保卡、养老保险、失业保险、医疗保险、""工伤保险、生育保险、人事、就业培训、就业、社保档案、其他档案、其他""之间那一类问题,只需返回的那分类的那几个字")deff_classifiy(txt):client=OpenAI(api_key="sk-xxx",base_url="https://api.deepseek.com")response=client.chat.completions.create(model="deepseek-chat",messages=[{"role":"user","content":txt}],stream=False)returnresponse.choices[0].message.contentforstr1intexts:str2=f_classifiy(str1+" "+ctext)file.write(str1+"\t"+str2+"\n")

把问题文本 + 分类要求一起发给DeepSeek,让它返回类别名称。14个预设类别覆盖了社保的主要领域。

效果

分类准确率很高。DeepSeek对中文社保领域的语义理解比TF-IDF强太多了。“退休后医保还能报销吗"被正确分类为"医疗保险”,不是"养老保险"。

问题:成本。每条问题调用一次API,94万条费用不低。实际上先用向量聚类把重复问题去掉,剩下几万条不重复的再用大模型分类,成本可控。


五、知识库覆盖率分析

分类完了,还要回答一个问题:高频问题我们的知识库覆盖了没有?

# 从p2集合取出所有问题向量,在SI_knowledge知识库中检索forjinrange(0,qs[0].__len__()):res=client.search(collection_name="SI_knowledge",data=[qs[0][j]["entity"]["v"]],limit=10,output_fields=["uid","Question"],search_params={"metric_type":"COSINE","params":{"radius":0.0}})ifres[0].__len__()>0:file.write(qs[0][j]["entity"]["Question"]+"\t"+str(res[0][0]["distance"])+"\t"+res[0][0]["entity"]["Question"]+"\n")

把热线问题拿到知识库里搜,看匹配的最高相似度是多少。相似度>0.8说明知识库有覆盖,<0.5说明是知识盲区。

这个分析直接告诉我们:该往知识库补什么内容。


六、三种方法的对比

方法原理优点缺点
KMeans+TF-IDF关键词特征聚类快、不需要额外服务不理解语义、簇需要人工解读
向量相似度聚类语义向量+余弦相似度精准、理解语义慢、需要先建向量库
大模型分类LLM语义理解最精准、直接出类别名有API成本、有速率限制

实际工作流

  1. 先用向量相似度去重(94万→几万条不重复)
  2. 再用大模型分类(几万条→14个类别)
  3. 最后用覆盖率分析找出知识盲区

三种方法不是替代关系,是流水线关系。每一步为下一步准备更干净的数据。


相关阅读:

  • 《向量数据库实战——用Milvus+Ollama搭建社保知识检索系统》
  • 《约94万条热线问题怎么去重?动态相似度阈值+Milvus》
  • 《知识库建好了但够不够用?向量检索量化覆盖率》
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/24 4:15:47

干细胞研究领域最新发展动态观察

干细胞研究领域最新发展动态观察干细胞是一类具有自我更新与多向分化潜能的特殊细胞&#xff0c;一直是生命科学基础研究领域的热点方向。近年来&#xff0c;随着分子生物学与细胞生物学技术的发展&#xff0c;科研人员对干细胞的生物学特性、分化调控机制等方面的认知正在不断…

作者头像 李华
网站建设 2026/6/24 4:00:36

SMUDebugTool终极指南:免费开源AMD Ryzen处理器调试工具完全教程

SMUDebugTool终极指南&#xff1a;免费开源AMD Ryzen处理器调试工具完全教程 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: …

作者头像 李华
网站建设 2026/6/24 3:50:35

原神抽卡记录导出工具:3步轻松保存你的每一次祈愿

原神抽卡记录导出工具&#xff1a;3步轻松保存你的每一次祈愿 【免费下载链接】genshin-wish-export Easily export the Genshin Impact wish record. 项目地址: https://gitcode.com/GitHub_Trending/ge/genshin-wish-export 你是否曾为原神抽卡记录无法永久保存而烦恼…

作者头像 李华
网站建设 2026/6/24 3:47:38

车载三电PCB可靠性难落地?车规级板材场景适配与验证要点

新能源汽车 BMS 电池管理板、电机控制器、车载充电机属于车规严苛级 PCB 应用&#xff0c;必须满足宽温交变、振动冲击、湿热盐雾、长期高压绝缘多重考核&#xff0c;普通工业级板材无法通过车企准入验证&#xff0c;不少研发人员因基材选型不合规&#xff0c;导致样品在 AEC-Q…

作者头像 李华