ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从零搭建AI市场调研系统:大模型驱动的消费者洞察与情感分析实战

从零搭建AI市场调研系统:大模型驱动的消费者洞察与情感分析实战 1. 从零搭建AI市场调研系统的整体设计思路做过市场调研的人都知道传统方式无非是问卷、访谈、焦点小组这几板斧。一套流程走下来从设计问卷到回收数据再到出报告少说三四周多则两三个月。等报告出来市场风向可能已经变了。我去年接手一个消费品类的调研项目客户要求两周内给出消费者对某新品类的认知度和购买意愿分析按老办法根本不可能完成。也就是从那时候起我开始认真琢磨用AI把这条链路重新做一遍。这套系统的核心思路其实不复杂用大模型替代人工完成信息采集、清洗、编码、分析、报告生成这五个环节中的重复劳动人只负责定义问题和校验结果。听起来简单但每个环节都有坑。比如信息采集环节你不能直接拿大模型去编消费者数据那是自欺欺人。正确的做法是让AI去处理真实存在的文本数据——电商评论、社交媒体讨论、论坛帖子、客服对话记录这些才是消费者行为的真实映射。为什么选这个路线而不是直接让AI生成调研结论因为市场调研的底线是数据可追溯。你告诉客户67%的消费者表示会复购客户第一反应是问这个数据哪来的。如果答案是AI说的这个项目就废了。所以整套系统的设计原则是AI负责处理和理解数据人负责判断和决策。技术选型上我最终确定的架构是四层数据采集层用Python写爬虫和API对接模块从公开渠道获取评论文本、讨论帖、行业报告摘要数据处理层NLP模型做情感分析、意图识别、实体抽取把非结构化文本转成结构化标签分析建模层机器学习模型做聚类和预测比如消费者分群、购买意愿打分交互输出层大模型做报告生成和自然语言问答让非技术背景的同事也能直接查数据这个架构的好处是每一层都可以独立替换和升级。比如你后面想换一个更强的情感分析模型只需要改数据处理层不影响其他部分。我试过把情感分析从BERT换成某个国产大模型API整个切换过程不到半天。注意整套系统的前提是数据来源合法合规。公开渠道的数据采集要遵守目标平台的使用条款涉及个人信息的要脱敏处理。这一点在项目启动前就要和法务确认清楚不要等做完了再补。2. 核心模块拆解与关键技术点解析2.1 数据采集怎么拿到真话而不是套话市场调研最怕的就是拿到一堆正确的废话。你问用户您对价格敏感吗十个人有八个说比较敏感这种数据没有分析价值。真正有价值的是用户在自然状态下说的话——电商评论区里那句用了三天就坏了客服还不给退比问卷里任何选项都真实。所以数据采集模块的设计重点是抓取自然语境下的文本。我常用的数据源有三类第一类是电商平台评论。某主流电商平台的商品评论API可以按关键词、时间范围、评分等级筛选返回JSON格式的评论内容、评分、时间戳。这里有个技巧不要只抓差评好评里的具体描述同样有价值。比如包装很用心送人很合适这句话透露的是礼品场景需求这是问卷很难问出来的。第二类是社交媒体讨论。某内容平台的搜索接口可以按话题标签抓取帖子标题和正文。这里要注意的是社交媒体数据噪声很大需要做初步过滤。我的做法是设置一个最小文本长度阈值比如20个字过滤掉哈哈哈太棒了这类无信息量的短文本。第三类是客服对话记录。如果客户愿意提供脱敏后的客服对话数据这是金矿。因为用户在客服面前说的话往往最直接——我要退货这个功能怎么用不了能不能便宜点。这些对话里藏着产品缺陷、使用障碍、价格敏感度等关键信息。采集频率上我一般设置增量采集而不是全量重抓。每天定时跑一次只抓上次采集时间之后的新数据。这样既节省资源又能保证数据的时效性。增量采集的关键是维护一个最后采集时间戳的状态文件每次采集前读取采集后更新。# 增量采集状态管理示例 import json from datetime import datetime def load_last_crawl_time(state_filecrawl_state.json): try: with open(state_file, r) as f: state json.load(f) return state.get(last_crawl_time) except FileNotFoundError: return None def save_last_crawl_time(state_filecrawl_state.json): state {last_crawl_time: datetime.now().isoformat()} with open(state_file, w) as f: json.dump(state, f)这段代码看起来简单但实际跑起来有个坑如果某次采集失败了时间戳不能更新否则会漏数据。我的做法是采集成功后再更新时间戳并且记录每次采集的数据量如果某次数据量突然降为零要触发告警。2.2 文本预处理把脏数据变成干净燃料原始文本直接丢给模型效果一定差。我见过太多人跳过预处理这一步然后抱怨模型不准。实际上预处理的质量决定了整个系统效果的上限。预处理的核心任务有四个去噪、分词、去停用词、标准化。去噪主要是去掉HTML标签、特殊符号、重复字符。比如好好好好好要压缩成好要统一成。分词用jieba或者HanLP都行但我更推荐用大模型做分词因为大模型对网络新词和领域术语的识别更准。比如绝绝子这种词传统分词工具可能切成绝绝/子但大模型能正确识别为一个整体。去停用词要注意领域适配。通用的停用词表的了是可以直接用但领域停用词需要自己维护。比如做美妆调研时皮肤使用感觉这些词出现频率极高但区分度低应该加入停用词表。我的做法是先跑一遍词频统计把Top 50的高频词人工过一遍判断哪些是噪声词。标准化包括统一大小写、统一数字格式、统一时间格式。比如100元100块一百元要统一成100元。这一步看起来琐碎但对后续的实体抽取和统计分析影响很大。实操心得预处理阶段一定要保留原始文本的备份。我踩过一次坑预处理脚本有个bug把否定词不给去掉了导致情感分析结果完全反了。幸好有原始备份重新跑一遍就恢复了。如果没有备份整个项目要重来。2.3 情感分析与意图识别读懂话外之音情感分析是市场调研的核心需求之一。但传统的情感分析模型只能判断正面/负面/中性这远远不够。实际业务中我们需要知道的是用户对哪个方面满意/不满意程度如何是否会影响购买决策。举个例子价格有点贵但质量确实好还是会买。传统模型可能判为中性或正面但实际上这句话包含两个维度的信息价格负面、质量正面、购买意愿正面。如果只给一个笼统的情感标签这个信息就丢失了。我的做法是用方面级情感分析Aspect-Based Sentiment Analysis。具体实现上可以用大模型做Few-shot学习给几个示例让它输出结构化的结果{ aspects: [ {aspect: 价格, sentiment: negative, intensity: 0.6}, {aspect: 质量, sentiment: positive, intensity: 0.9}, {aspect: 购买意愿, sentiment: positive, intensity: 0.8} ] }这种结构化输出可以直接入库后续做聚合分析非常方便。比如你可以快速算出价格负面提及率和质量正面提及率的对比判断产品的核心优劣势。意图识别是另一个关键模块。用户说一句话背后可能有多种意图咨询、投诉、比价、推荐、复购。识别出意图后可以针对性地做后续处理。比如识别出比价意图的用户可以重点分析他对价格的敏感度识别出投诉意图的要重点关注产品缺陷。意图识别的实现可以用文本分类模型也可以用大模型做Zero-shot分类。我实测下来对于意图类别少于10个的场景大模型Zero-shot的效果已经足够好不需要专门训练分类器。但如果意图类别很多比如20个以上还是需要标注数据微调模型。2.4 消费者分群从一群人到几类人市场调研的最终目的是指导决策。而决策需要的是分群不是平均值。知道平均满意度7.2分没有意义知道价格敏感型用户满意度5.1分品质优先型用户满意度8.9分才有意义。消费者分群我用的是聚类画像的组合方案。先用K-Means或DBSCAN对用户行为特征做聚类然后用大模型给每个簇生成自然语言画像。特征工程是分群效果的关键。我常用的特征包括评论长度反映参与度情感极性分布正面/负面/中性比例方面提及频率价格、质量、服务、物流等购买频次如果有交易数据互动行为点赞、收藏、转发聚类数目的选择上不要迷信肘部法则。我的经验是先跑一遍层次聚类看树状图确定大致的簇数量范围再用K-Means细化。实际项目中消费者分群通常3-6类比较合适太少区分度不够太多不好解读。画像生成用大模型来做给每个簇的统计特征和代表性评论让模型输出一段200字左右的画像描述。比如这类用户以25-35岁女性为主对价格高度敏感评论中频繁提及性价比划算贵等词汇。她们通常会在购买前对比多个品牌决策周期较长。对促销活动反应积极但对产品质量的容忍度较低一旦出现质量问题很容易给出差评并流失。这种画像可以直接给业务方看比一堆数字直观得多。3. 完整实操流程与关键环节实现3.1 环境准备与依赖安装整套系统我是在Linux环境下开发的Python 3.10版本。为什么强调版本因为有些NLP库对Python版本有要求比如某些版本的transformers库在3.8以下跑不起来。我建议直接用3.10或3.11兼容性最好。核心依赖清单pip install requests pandas numpy scikit-learn jieba pip install transformers torch pip install openai # 如果用大模型API pip install fastapi uvicorn # 如果要做成服务 pip install schedule # 定时任务这里有个坑torch的安装要根据CUDA版本选择对应的命令。如果你有GPU去PyTorch官网查一下对应CUDA版本的安装命令不要直接pip install torch否则可能装成CPU版本跑模型慢得你想砸电脑。数据库我用的是PostgreSQL因为要存JSON格式的分析结果PostgreSQL的JSONB类型很好用。如果数据量不大SQLite也够用。缓存用Redis主要是存一些频繁查询的中间结果比如词频统计。3.2 数据采集模块的完整实现采集模块我封装成了一个类核心方法有三个fetch_comments、fetch_posts、fetch_customer_service_logs。每个方法都支持增量采集和分页。以电商评论采集为例核心逻辑是import requests import time import json from datetime import datetime class DataCollector: def __init__(self, api_key, state_filecrawl_state.json): self.api_key api_key self.state_file state_file self.session requests.Session() self.session.headers.update({Authorization: fBearer {api_key}}) def fetch_comments(self, product_id, max_pages50): last_time self._load_last_time() all_comments [] for page in range(1, max_pages 1): params { product_id: product_id, page: page, page_size: 50, start_time: last_time } resp self.session.get(https://api.example.com/comments, paramsparams) if resp.status_code ! 200: print(f采集失败状态码{resp.status_code}) break data resp.json() comments data.get(comments, []) if not comments: break all_comments.extend(comments) time.sleep(1.5) # 控制请求频率 if all_comments: self._save_last_time() return all_comments这里有几个实操要点。第一time.sleep(1.5)是必须的不要贪快。我见过有人把间隔设成0.1秒结果IP被限流整个采集任务中断。第二分页终止条件要判断返回空列表而不是达到max_pages因为实际数据量可能远小于你的预期。第三每次请求都要检查状态码非200就记录日志并中断不要继续跑。采集到的原始数据我建议先存成JSON文件不要直接入库。因为后续预处理可能会调整逻辑如果直接入库重新处理要清库重来。存文件的话改个脚本重新跑一遍就行。3.3 预处理流水线的搭建预处理我设计成了一条流水线每个步骤是一个独立的函数方便单独调试和替换。import re import jieba def clean_text(text): 基础清洗去HTML、去特殊符号、压缩重复字符 text re.sub(r[^], , text) # 去HTML标签 text re.sub(r[^\w\s\u4e00-\u9fff。、], , text) # 保留中文和常用标点 text re.sub(r(.)\1{3,}, r\1\1, text) # 压缩重复字符 return text.strip() def segment(text): 分词 return list(jieba.cut(text)) def remove_stopwords(words, stopword_filestopwords.txt): 去停用词 with open(stopword_file, r, encodingutf-8) as f: stopwords set([line.strip() for line in f]) return [w for w in words if w not in stopwords and len(w) 1] def preprocess_pipeline(raw_text): 完整预处理流水线 text clean_text(raw_text) words segment(text) words remove_stopwords(words) return { cleaned_text: text, words: words, word_count: len(words) }停用词表我建议用通用停用词表领域停用词表的组合。通用停用词表网上有很多哈工大、百度、四川大学都有公开版本。领域停用词表需要自己积累我的做法是每做一个新项目就把新发现的领域停用词追加到项目专属的停用词文件里。注意停用词表不要用一份走天下。做美妆调研和做数码调研停用词表应该不一样。我一般会在项目目录下放一个stopwords_project.txt和通用停用词表合并使用。3.4 情感分析与意图识别的落地实现情感分析我用的是大模型API本地缓存的方案。为什么不全用本地模型因为本地部署一个效果好的情感分析模型至少需要一张显存16G以上的显卡成本不低。而大模型API按量付费初期成本更低效果也更好。核心代码逻辑import hashlib import json import redis class SentimentAnalyzer: def __init__(self, llm_client, redis_client): self.llm llm_client self.redis redis_client def analyze(self, text): # 先查缓存 cache_key fsentiment:{hashlib.md5(text.encode()).hexdigest()} cached self.redis.get(cache_key) if cached: return json.loads(cached) # 调用大模型 prompt f分析以下文本的方面级情感输出JSON格式 文本{text} 输出格式{{aspects: [{{aspect: 方面, sentiment: positive/negative/neutral, intensity: 0.0-1.0}}]}} 只输出JSON不要其他内容。 response self.llm.chat(prompt) result json.loads(response) # 写缓存有效期7天 self.redis.setex(cache_key, 604800, json.dumps(result)) return result缓存这一步很关键。同一个文本可能被多次分析比如调试时反复跑没有缓存的话API费用会飙升。我实测下来加上缓存后API调用量能降低60%以上。意图识别类似也是用大模型做Zero-shot分类。Prompt设计上我会把意图类别和判断标准都写清楚INTENT_PROMPT 判断以下用户文本的意图从以下类别中选择最匹配的一个 - 咨询询问产品信息、使用方法、售后政策 - 投诉表达不满、要求退换货、抱怨服务 - 比价对比不同品牌或渠道的价格 - 推荐向他人推荐或表达复购意愿 - 其他不属于以上任何类别 文本{text} 只输出意图类别名称。实测下来意图识别的准确率在85%左右对于市场调研的场景已经够用。如果对准确率要求更高可以加Few-shot示例或者用标注数据微调一个小模型。3.5 消费者分群与画像生成分群模块的输入是每个用户的特征向量。特征向量的构建逻辑import numpy as np from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler def build_user_features(user_data): 构建用户特征向量 features [] for user in user_data: # 情感分布特征 pos_ratio user[positive_count] / max(user[total_count], 1) neg_ratio user[negative_count] / max(user[total_count], 1) # 方面提及特征 price_mention user[aspect_counts].get(价格, 0) / max(user[total_count], 1) quality_mention user[aspect_counts].get(质量, 0) / max(user[total_count], 1) service_mention user[aspect_counts].get(服务, 0) / max(user[total_count], 1) # 行为特征 avg_length user[total_word_count] / max(user[total_count], 1) features.append([ pos_ratio, neg_ratio, price_mention, quality_mention, service_mention, avg_length ]) return np.array(features) def cluster_users(features, n_clusters4): 聚类 scaler StandardScaler() features_scaled scaler.fit_transform(features) kmeans KMeans(n_clustersn_clusters, random_state42, n_init10) labels kmeans.fit_predict(features_scaled) return labels, scaler, kmeans聚类数目怎么定我的经验是先跑3到8类看每个簇的样本量和特征差异选区分度最好的那个。如果某个簇只有几个人说明这个簇没有代表性应该减少聚类数。如果两个簇的特征向量几乎一样说明聚类数太多了。画像生成用大模型来做把每个簇的统计特征和Top 10代表性评论喂给模型def generate_persona(cluster_stats, sample_comments, llm_client): prompt f根据以下用户群体的统计特征和代表性评论生成一段200字左右的用户画像描述。 统计特征 - 正面评论占比{cluster_stats[pos_ratio]:.1%} - 负面评论占比{cluster_stats[neg_ratio]:.1%} - 价格提及率{cluster_stats[price_mention]:.1%} - 质量提及率{cluster_stats[quality_mention]:.1%} - 平均评论长度{cluster_stats[avg_length]:.0f}字 代表性评论 {chr(10).join(sample_comments[:10])} 请用一段话描述这类用户的特征、偏好和潜在需求。 return llm_client.chat(prompt)生成的画像我会人工过一遍确保没有明显的偏差或幻觉。如果画像里出现了数据中不存在的特征要检查是不是模型在编造。4. 常见问题排查与避坑经验实录4.1 数据采集被限流怎么办这是最常见的问题。表现是采集到一半突然返回403或429状态码或者返回空数据。原因通常是请求频率太高触发了目标平台的反爬机制。解决方案分三个层次第一层是降低请求频率。把time.sleep的时间调大我一般设1.5到3秒。如果还不行就设5秒。宁可慢一点也不要被封。第二层是轮换请求头。准备多个User-Agent每次请求随机选一个。但注意不要用那些明显是爬虫的UA要用真实浏览器的UA。第三层是使用代理池。如果数据量很大单IP确实扛不住就需要代理池。但代理池的维护成本不低而且质量参差不齐。我的建议是优先考虑官方API很多平台都有开放的数据接口虽然可能有调用次数限制但稳定性和合规性都好得多。实操心得采集任务一定要加异常捕获和重试机制。我一般设置最多重试3次每次重试间隔递增5秒、15秒、30秒。如果3次都失败就记录失败页码跳过继续。不要因为一页失败就整个任务中断。4.2 情感分析结果不准怎么调情感分析不准通常有三种表现把正面判成负面、把负面判成正面、把有倾向的判成中性。排查思路首先检查预处理是否把关键信息洗掉了。比如否定词不没别如果被当成停用词去掉了不好就变成了好情感完全反了。检查方法是随机抽100条原始文本和预处理后的文本人工对比看有没有信息丢失。其次检查Prompt设计是否合理。如果Prompt太简单模型可能理解偏差。比如你只说分析情感模型可能只给一个笼统的标签。要明确告诉模型输出格式和判断标准。最后检查领域适配。通用情感分析模型在特定领域可能表现不佳。比如在数码领域发热通常是负面词但在某些场景下比如冬天用的暖手宝发热是正面词。这种领域特定的情感倾向需要在Prompt里说明或者用领域数据微调模型。我的做法是先跑100条人工标注的测试集算准确率。如果低于80%就调Prompt如果调完还不行就考虑微调模型。测试集一定要人工标注不要用模型标注的结果当测试集那是自欺欺人。4.3 聚类结果不好解读怎么办聚类结果不好解读通常表现为簇的特征差异不明显或者画像描述很模糊。原因可能有三个一是特征选择不当。如果选的特征本身区分度低聚类效果肯定不好。比如你选了评论是否包含标点符号这种特征大部分用户都是一样的对聚类没有帮助。特征选择的原则是选那些在不同用户之间有显著差异的特征。可以先做单特征分布分析看哪些特征的方差大。二是数据标准化没做好。不同特征的量纲不一样比如评论长度是几十到几百情感比例是0到1。如果不做标准化聚类会被量纲大的特征主导。StandardScaler是必须的。三是聚类数选择不当。前面说过3到6类比较合适。如果选了10类每个簇的样本量太少统计特征不稳定画像自然模糊。我的排查流程是先看特征分布再看聚类结果的轮廓系数最后看每个簇的样本量和特征均值。如果轮廓系数低于0.3说明聚类效果不好需要调整特征或聚类数。4.4 大模型API调用成本怎么控制大模型API按Token计费如果数据量大成本会很高。我做过一个项目原始数据有50万条评论如果全部调API做情感分析费用要好几千块。控制成本的几个方法第一缓存。前面已经说过相同文本只调一次API。实际项目中重复文本的比例可能高达30%到50%比如好评不错这种短评论。第二采样。如果数据量太大不需要全量分析可以分层采样。比如按评分等级分层每个等级抽10%的样本。这样既能保证代表性又能大幅降低成本。第三本地模型兜底。对于简单的任务比如判断情感极性可以用本地的小模型先跑一遍只把置信度低的样本送给大模型。这样能减少70%以上的API调用。第四批量请求。有些API支持一次传多条文本比逐条调用便宜。如果API支持尽量批量传。注意不要为了省钱用效果很差的模型。市场调研的结论是要指导决策的如果分析结果不准省下的API费用远抵不上决策失误的损失。我的原则是核心分析用最好的模型辅助性分析可以用便宜模型。4.5 常见问题速查表问题现象可能原因排查方法解决方案采集返回空数据被限流或参数错误检查状态码和返回体降低频率、检查参数、换IP情感分析结果反了否定词被过滤对比预处理前后文本检查停用词表保留否定词聚类轮廓系数低特征区分度不够看单特征方差重新选特征做标准化API费用超预期重复调用或全量分析统计调用量和重复率加缓存、采样、本地模型兜底画像描述模糊聚类数太多或特征太少看每簇样本量和特征均值减少聚类数增加特征报告生成有幻觉Prompt约束不够人工校验生成内容加数据引用要求人工审核5. 系统扩展与个人实操体会这套系统跑通之后我陆续做了几个扩展效果都不错。第一个扩展是实时监控看板。用FastAPI搭一个简单的Web服务前端用ECharts做可视化把情感趋势、方面提及率、消费者分群变化实时展示出来。业务方可以自己上去看不用等我出报告。这个看板的开发量不大但实用性很强尤其是做新品上市监控的时候每天都能看到消费者反馈的变化。第二个扩展是竞品对比分析。把自家产品和竞品的评论数据放在一起分析看消费者在提到两个品牌时关注的方面有什么差异。比如自家产品被提及最多的是价格竞品被提及最多的是设计那说明竞品的差异化优势在设计上自家需要在设计上发力。这个分析用同一套NLP流水线就能做只需要把数据源换成竞品的评论。第三个扩展是预测模型。用历史评论数据训练一个购买意愿预测模型输入是用户的历史评论特征输出是未来30天的购买概率。这个模型的效果取决于数据量和特征质量我实测下来AUC能到0.75左右对于辅助决策已经够用。但要注意预测模型不能替代人工判断只能作为参考。我个人在实际操作中的体会是AI市场调研系统的价值不在于替代人而在于让人从重复劳动中解放出来把精力放在真正需要判断力的地方。以前做调研80%的时间花在数据清洗和编码上只有20%的时间在思考。现在反过来了80%的时间在思考业务问题20%的时间在调系统和验结果。这个转变带来的价值提升远比省下的那点人力成本大得多。最后分享一个小技巧每次项目结束后把Prompt、停用词表、特征工程代码整理成模板。下一个项目直接复用只需要调整领域相关的部分。我现在的模板库已经覆盖了美妆、数码、食品、服装四个大类新项目启动时间从一周缩短到一天。这个积累过程很值得越早开始越好。
返回列表