从做过的几个文本分析项目里,中文情感分析是我觉得最能直接体现“从数据到价值”的活儿。标题里这套“基于Python + Vue的深度学习中文情感分析系统”不是某个培训机构挂出来的演示Demo,而是我实际落地过的一条完整链路:数据清洗、模型训练、后端服务、前端展示、数据库存储,一环扣一环。这篇博文就按我当时的开发顺序来拆,从需求分解到架构选型,再到模型细节和前后端联调,最后附上我踩过的坑和排查记录。不管你是在做毕业设计、公司内部舆论监测工具,还是单纯想体验一把“从零跑通一个NLP项目”的完整流程,这套思路都能直接复用。
1. 项目整体设计与架构思路
1.1 需求拆解:一个情感分析系统到底要解决什么问题
别看标题叫“深度学习中文情感分析系统”,真正动手之前要先想清楚:这个系统要服务谁、分析什么文本、输出什么结果、结果给谁看。我接到这个需求原型时,最初的需求描述其实就一句话——“对一批中文评论文本做正面/负面判断”。但这句话背后牵扯的问题不少:
- 输入形式是什么?是用户粘贴一段文本,还是上传Excel文件,还是对接API批量传入?
- 分析粒度是句子级、段落级还是整篇文档级?
- 情感类别是二分类(正/负),还是需要三分类(正/负/中性),或者更细的七分类(愤怒、喜悦、悲伤、恐惧、厌恶、惊讶、无情绪)?
- 结果需要怎样的解释?只给一个标签和置信度,还是需要给出模型判定依据(比如关键词高亮)?
- 数据从哪来?标注的训练语料怎么准备?如果客户没有现成标注数据,需不需要先用规则方法搭一个基线?
这个项目最终我采用了比较稳妥的方案:先做正/负/中三分类,原因是中文评论场景里“中性”占比实际很高,强行二分类会把很多客观描述判成负面,准确率反而难看。系统同时支持单条文本实时分析和批量文件导入分析,前端除了展示标签和概率,还会展示高频关键词分布和逐条明细,方便用户复核。
1.2 技术选型:为什么是Python后端 + Vue前端
这个组合在当下不算新奇,但它确实是“快速落地 + 易于扩展”的综合最优解。Python端的优势在于深度学习生态的完整度,尤其是PyTorch和Hugging Face Transformers这套组合,加载预训练中文模型、微调、推理都极其顺手。中文领域有现成的预训练模型可以用,甚至早期原型阶段直接加载零样本分类模型就能看到效果,这对项目初期的需求验证非常有价值。
Vue前端则负责把模型的能力转译成用户看得懂的东西。很多人会觉得情感分析的重点全在模型精度上,前端只是套个壳。实际上用户感知到的“系统好不好用”,很大程度取决于页面的交互逻辑。Vue的优势是组件化开发快、生态资料多,配合ECharts做结果可视化非常高效,散点图、柱状图、词云都不需要从零写。
数据库这个环节很多人会忽略,但一个完整的分析系统必须有存储能力。我的设计是MySQL存储用户上传的原始文本、分析结果、批量任务状态,以及模型的版本记录和分析日志。原因很实际:一方面用户需要查看历史分析记录,另一方面批量任务需要断点续跑的中间状态。纯内存方案看着简单,一旦进程重启数据全丢,这在真实业务里是不可接受的。
架构上我分了四层:
- 数据接入层:接收单条文本或批量文件(Excel/CSV),做编码校验和基础清洗
- 模型推理层:封装Tokenizer和模型,输出情感标签、置信度、注意力权重
- 业务服务层:处理用户权限、调用记录、批量任务调度
- 展示层:Vue单页应用,提供文本输入、结果可视化、历史查询、批量任务跟踪
1.3 数据流设计:从原始文本到情感标签的全路径
有一次我在给朋友演示系统时,他问了个很本质的问题:“我把这段评价贴进去,点一下按钮,背后到底发生了哪些事?”我把这份数据流画成了下面这样:
- 用户在前端输入文本,点击“分析”按钮
- Vue发请求到后端接口(比如 /api/analyze),参数里带上文本内容
- 后端先做文本规范化:去HTML标签、去不可见字符、统一全角半角、校正乱码(尤其是从Excel复制过来的文本经常有弯引号和不可见空格)
- 文本进入Tokenizer,转换成长度固定(比如128)的token序列,加上attention mask
- 模型前向传播,得到logits向量,经softmax转成三个概率值
- 后端根据概率值判定标签,同时提取模型attention分数较高的关键词
- 结果写入MySQL,同时返回JSON给前端
- 前端渲染标签、置信度、关键词,并更新图表组件
这个流程看起来简单,但每一步都有细节。比如第3步的文本清洗,直接决定模型效果;比如第6步的关键词提取,如果做得太粗糙,会展示一堆“的”“了”“是”这类无意义字词。这些细节我会在后面几节里逐个展开。
2. 核心算法与模型方案选择
2.1 中文情感分析的算法演进简述
在聊模型方案之前,有必要把中文情感分析常见的实现路线捋一遍,这样才能理解为什么最终选择了深度学习方案,也知道在什么情况下可以降级使用其他方案。
- 基于情感词典的方法:维护一个带权重的褒贬词典,比如“优秀”+2、“垃圾”-2,再把文本命中词条的分值累加。优点是无需训练、可解释性强、启动最快,缺点是词典覆盖有限、无法处理否定句式(“不是不好”这种双重否定直接算错)、“新词”和网络流行语无能为力。
- 传统机器学习方法:分词后提取TF-IDF或N-gram特征,喂给朴素贝叶斯、逻辑回归、SVM。优点是可解释性和数据效率尚可,但特征工程手工痕迹重,对上下文语义几乎无感知。
- 深度学习方法:从Word2Vec时代的CNN/RNN,到后来的BERT、RoBERTa、大模型,核心优势是能建模上下文,一句话里的“这个产品我很满意,但物流太慢”能同时捕捉到正负情绪,而不是简单按词频叠加。
- 在大模型时代,甚至可以不做微调,直接靠提示词让大模型输出评价,效果不错但推理成本高、延迟大,对系统的硬件要求也高。
我最终选择的是预训练模型微调路线,具体是用一个中文BERT结构的模型,在标注数据上做三分类微调。选择这个方案有几个具体原因。一是这套系统要部署在内网环境,推理延迟和硬件限制都要考虑,大模型的性价比不高。二是预训练模型的迁移能力很强,即便标注数据只有几千条,也能达到可用的精度。三是Hugging Face生态让整个训练和推理流程高度标准化,几乎不需要从零写训练逻辑。
2.2 数据标注与预处理:决定模型上限的隐形工作
很多人讲到情感分析都聚焦在模型结构上,但实际项目中决定效果的往往是数据。我在这套系统里准备了两类数据:
第一类是公开的中文评论语料,涵盖电商、餐饮、酒店、影视几个场景,加起来约2万条带标签数据。第二类是客户提供的真实业务数据,约3000条,但这部分数据质量参差不齐,需要人工清洗和标注。
数据预处理流程我讲得细一点,因为这些步骤直接影响模型效果:
- 去重:业务数据里存在大量同一句话被不同用户复制粘贴的情况,不去重会导致训练集和测试集重叠,指标虚高
- 标签修正:公开语料的标签粒度不统一,有的标“好评/差评”,有的标“1-5星”,需要映射成负/正/三分类标签
- 文本清洗:去除URL、@用户、#话题#、数字编号,保留中文、常用标点、表情符号(表情对情感判断有实际辅助作用)
- 长度截断:BERT类模型的输入长度有限(我设定为128),需要合理截断。这里有个技巧:优先保留文本开头和结尾,因为中文评论往往开头点题、结尾总结,中间多是细节描述
- 类别平衡:我检查了原始数据分布,负面样本明显偏少,典型的长尾分布。最简单的处理是过采样和损失函数加权,我用的是损失函数加权,也就是给少数类别更高的权重,避免模型“学成一个大胖子”全往多数类偏
2.3 模型结构与微调配置
模型结构我直接沿用了BERT的默认配置:12层Transformer、768维隐藏层、12个注意力头。这些参数不是最优的,但足够稳健。在中文情感分析这个任务上,微调一个BERT-base模型在几千条到几万条数据上完全够用,没必要上更大的模型——推理速度和显存占用会成倍增加,收益却不明显。
微调时我做了几个关键配置:
- 优化器:AdamW,学习率2e-5。这是预训练模型微调的常见经验值,太大会破坏预训练权重,太小收敛过慢
- Batch Size:16。显存8G的卡上跑BERT-base比较合适
- Epoch:3到5之间。需要配合验证集早停,我曾经过拟合过一个版本,训练集准确率98%,验证集准确率只剩78%,差得离谱
- Max Length:128。这是输入截断长度,兼顾了效率和上下文保留
- 损失函数:CrossEntropyLoss,类别权重设为1比1.5比1.2(正/中/负)
训练完成后我导出了两个东西:PyTorch模型权重文件和对应的Tokenizer配置文件。这两个文件是整个系统最核心的资产。我在代码里做了一个保护性设计:如果模型文件缺失,系统会自动降级到词典打分模式并返回提示信息,避免服务直接崩溃。
3. 后端服务搭建与模型封装
3.1 Python框架选择:FastAPI的优势
后端框架我选了FastAPI,主要原因是它的异步特性和自动API文档。做深度学习推理服务时,CPU推理是阻塞操作,如果框架不支持异步,一个耗时2到3秒的推理请求就会阻塞住整个进程。FastAPI配合后台任务队列,可以做到批处理任务异步执行、单条分析实时返回,体验好很多。
另一个实际好处是FastAPI自动生成Swagger文档,联调阶段省了大量沟通成本。前端同事不需要单独维护接口文档,直接打开 /docs 页面就能看到每个接口的请求参数和返回结构。
用FastAPI搭一个情感分析服务的骨架,核心代码大概长这样:
from fastapi import FastAPI from pydantic import BaseModel app = FastAPI(title="中文情感分析服务") class AnalyzeRequest(BaseModel): text: str class AnalyzeResponse(BaseModel): label: str confidence: float keywords: list[str] @app.post("/api/analyze", response_model=AnalyzeResponse) async def analyze(request: AnalyzeRequest): result = predict_sentiment(request.text) return result注意这里的 /api/analyze 接口是同步执行推理的。因为模型推理是一个计算密集型操作,在FastAPI里直接同步执行反而比用async def更合适——如果模型推理过程中触发了await,反而会因为事件循环调度产生额外开销。
3.2 推理逻辑封装:不要裸用模型
我习惯把模型推理封装成一个独立的预测类或模块,对外暴露一个predict(text: str) -> dict接口。内部依次完成:文本标准化、分词、模型前向、概率解析、关键词提取、结果结构化。这样设计的核心好处:接口的输入输出稳定,后续换模型版本,或者从CPU切到GPU,调用方代码完全不用改。
预测模块的大致结构:
class SentimentPredictor: def __init__(self, model_path: str, tokenizer_path: str, device: str = "cpu"): self.tokenizer = BertTokenizer.from_pretrained(tokenizer_path) self.model = BertForSequenceClassification.from_pretrained(model_path) self.model.eval() self.device = torch.device(device) self.model.to(self.device) def predict(self, text: str): cleaned_text = clean_text(text) inputs = self.tokenizer( cleaned_text, max_length=128, truncation=True, padding="max_length", return_tensors="pt" ) inputs = {k: v.to(self.device) for k, v in inputs.items()} with torch.no_grad(): outputs = self.model(**inputs) probs = torch.softmax(outputs.logits, dim=1).squeeze().tolist() return { "label": self._idx_to_label(int(torch.argmax(outputs.logits))), "confidence": max(probs), "keywords": extract_keywords(cleaned_text) }有几个细节我想单独强调。truncation=True和padding="max_length"都要一起设,漏掉任何一个都可能出问题。漏掉truncation会导致长文本在tokenize时报错;漏掉padding会导致batch中序列长度不一致,推理时矩阵运算直接挂掉。torch.no_grad()在推理时必须加,否则显存被计算图占满,跑几轮就OOM了。
3.3 模型服务化与缓存策略
模型加载比较花时间,尤其在大模型场景下,一次加载可能要几十秒。所以这个预测模块在进程启动时只初始化一次,之后所有请求都复用同一个模型实例。我在FastAPI里用了lifespan模式加载模型,代码大致这样:
from contextlib import asynccontextmanager from fastapi import FastAPI @asynccontextmanager async def lifespan(app: FastAPI): app.state.predictor = SentimentPredictor("models/checkpoint", "models/tokenizer") yield app = FastAPI(lifespan=lifespan)在单条分析接口里通常不需要额外的缓存,因为每条文本都不一样,缓存命中率低。但高频热词、固定分类统计结果可以放到Redis里做短时缓存。我在实现批量分析接口时就是先把批量文件切分成若干小批次,分批推理,每批结果更新一次任务进度,前端能实时看到进度条。
3.4 关键词提取的实操方案
关键词提取这里多说几句。最初版本我直接拿了模型attention层的分数选Top-N词汇,结果发现选出来的词经常是“[CLS]”“[SEP]”“的”“了”。后来改成两阶段方案:
- 用jieba分词,去掉停用词和长度小于2的词
- 在每个非特殊token的attention分数上叠加一个TF-IDF权重,最后按综合得分排序选取Top-N
这样选出来的关键词基本能落到“物流”“客服”“质量”“包装”这类实际业务词上。还有一个更简单的替代方案:如果不需要精确到token级,直接统计当前文本中命中情感词典里的候选词,也可以作为关键词展示。两者结合效果最好。
4. Vue前端设计与核心功能实现
4.1 页面结构与交互逻辑
前端我用Vue 3 + Vite + Element Plus搭建。整个界面一共5个核心区域:
- 顶部导航栏:系统名称 + 功能菜单(文本分析 / 批量分析 / 历史记录 / 系统设置)
- 文本分析面板:多行文本输入框 + “开始分析”按钮
- 结果展示面板:情感标签徽章、置信度进度条、关键词标签列表
- 统计图表区域:情感分布饼图、时间趋势折线图(针对历史数据)
- 批量任务区域:文件上传、任务进度、结果下载
用户交互的核心逻辑是:输入文本或上传文件,点击分析,等待结果,查看可视化。整个流程我做了不少细节优化,比如文本输入框限制在5000字以内并显示字数统计,避免后端被超长文本打挂;比如批量任务显示进度条,任务完成后自动轮询结果并展示下载链接。
4.2 调用后端接口与异常处理
前端调后端接口最需要注意的就是CORS跨域和错误提示。开发调试阶段我使用Vite的proxy配置解决跨域,这样浏览器看到的请求是同源的:
// vite.config.js export default { server: { proxy: { '/api': { target: 'http://localhost:8000', changeOrigin: true } } } }生产环境部署时我采用的是Nginx反向代理方案,把同一域名下的/api路径转发到FastAPI服务,前端就不存在跨域问题了。CORS问题要区分开:如果是前后端分开部署在不同域名,就需要在后端配置CORSMiddleware。
接口调用层我单独封装了一个api.js模块,统一管理请求、超时、错误码和Toast提示:
import axios from 'axios' import { ElMessage } from 'element-plus' const service = axios.create({ baseURL: '/api', timeout: 30000 }) service.interceptors.response.use( response => response.data, error => { if (error.code === 'ECONNABORTED') { ElMessage.error('请求超时,请检查后端服务状态') } else if (error.response) { ElMessage.error(error.response.data.detail || '服务异常') } else { ElMessage.error('网络异常,无法连接到服务器') } return Promise.reject(error) } )这里的timeout: 30000值得说明一下。如果用户粘贴了一段超长文本,模型单次推理可能超过10秒,加上排队时间,30秒是一个比较合适的阈值。设太短会频繁误报,设太长用户会以为系统卡死了。同时前端在等待结果时应该显示加载动画,并禁用提交按钮防止重复请求。
4.3 结果可视化:如何让情感分析结果“看得懂”
纯粹输出“正面 0.87”这种结果,对业务用户的价值其实有限。我做结果可视化时主要想了三个问题:
- 用户怎么快速理解置信度?我用的是进度条+颜色渐变,置信度越高,进度条越满,颜色越偏向对应的情感色(正面绿色、负面红色、中性蓝色)
- 用户怎么看出文本里哪些词影响了判断?我用关键词标签的形式,点开单个标签能显示包含该词的上下文句子,再联动后端调用定位到原文
- 用户怎么从整体上理解大量数据?我用ECharts实现了情感分布饼图和每日情感趋势堆叠折线图。比如运营人员导入一万条评论,立即就能看到正面占比、负面占比、以及哪几天负面舆情明显上升
这里还有一个我自己总结的经验:给每个搜索结果(历史分析记录)增加一个“置信度排序”和“情感标签筛选”功能。因为人工复核时,大家最关心的是“被模型判成低置信度的那些样本”,这些样本往往是模型可能出错的地方,优先审核它们,可以更快发现模型的问题。
5. 批量任务处理与数据库表设计
5.1 MySQL表结构与字段设计
数据库设计这部分需要细说,因为标题里特别强调了“数据库”。我设计了四张核心表:
- analysis_record:记录每一次单条分析请求,字段包括id、text、label、confidence、keywords_json、created_at
- batch_task:记录批量任务,字段包括id、task_name、file_path、status、total_count、success_count、fail_count、created_at
- batch_result:记录批量任务的逐条结果,字段包括id、task_id、text、label、confidence、keywords_json、row_index
- model_version:记录模型版本,字段包括id、model_name、version、params_path、tokenizer_path、accuracy、note
keywords_json字段我特意设计成JSON类型,这样不用单独拆一张关键词表,查明细时一次联查就能拿到全部数据,查询效率高得多。
批量任务的状态机是:pending -> running -> success / failed。如果任务跑到一半服务重启,下次启动时扫描task表,发现status还是running且更新时间特别久的,就把它标记为failed,并写入错误信息。这里有一个重要的设计选择——不要在task表里存所有的中间分析文本,只存原始文件路径和处理进度,真正的结果落地在batch_result表。这样即使中途崩溃,重跑任务时也不必重新分析前N行,只需要从断点继续。
5.2 异步任务队列:用FastAPI后台任务实现
批量分析如果同步做,一个1000条评论的文件可能要跑十几分钟,HTTP连接早就断开了。我用的方案是FastAPI的BackgroundTasks + 线程池,接收文件后立刻返回“任务已创建”,前端拿到task_id后轮询查询进度:
from fastapi import BackgroundTasks from fastapi.concurrency import run_in_threadpool def process_batch(task_id: int, file_path: str): update_task_status(task_id, "running") df = pd.read_excel(file_path) total = len(df) for idx, row in df.iterrows(): try: result = predictor.predict(row["content"]) save_batch_result(task_id, idx, row["content"], result) update_progress(task_id, idx + 1, total) except Exception as e: save_error_log(task_id, idx, str(e)) update_task_status(task_id, "success") @app.post("/api/batch/upload") async def upload_batch(file: UploadFile, background_tasks: BackgroundTasks): task_id = create_task(file.filename) file_path = save_upload_file(file) background_tasks.add_task(process_batch, task_id, file_path) return {"task_id": task_id}有两点特别提醒。一是线程池的并发数不能太大。模型推理是CPU密集或GPU密集任务,并发数超过设备核心数反而会相互拖慢。我实测4核CPU下并发数为2或3最合适,参数设置在配置文件中,方便按机器性能调节。二是Excel文件读取要注意单元格类型。有的单元格存储的是日期或数字,pandas读取后内容会变成时间戳或浮点数,这会导致文本清洗阶段直接出问题,我后面专门写了单元格类型强转逻辑,这里就不展开了。
6. 常见问题与排查技巧实录
6.1 中文乱码问题
这是我在实际开发中遇到最多的坑,出现在好几个环节:
- 问题现象一:前端提交中文文本,后端收到的全是
???。原因几乎总是编码问题——请求体的字符集设置不对。解决方案:前后端统一使用UTF-8编码,Axios请求头显式加上Content-Type: application/json; charset=utf-8 - 问题现象二:后端返回中文JSON,前端显示乱码。解决方案:FastAPI的JSONResponse默认使用UTF-8,但需要确认MySQL连接字符串也使用了
charset=utf8mb4。MySQL的utf8字符集其实不是真正的全量中文支持,utf8mb4才是 - 问题现象三:Excel文件中的中文读取乱码。解决方案:pandas读取Excel时指定引擎为openpyxl,读取CSV时指定
encoding='utf-8-sig'。注意不能用utf-8,因为很多CSV文件是从Windows Excel导出的,头部会带BOM标记,utf-8读出来的第一个字段名会多出“\ufeff”
6.2 模型加载慢与首次推理延迟过高
我的模型文件大约400MB,在只有CPU的测试服务器上,加载一次最慢要20秒。首次请求必须在模型加载完成后才能处理,否则直接报错。我的解决方案是:使用lifespan机制在应用启动时加载模型,并写了一版服务健康检查接口,前端页面加载时先调用 /api/health 确认模型已就绪,再允许用户点击分析按钮。
如果连启动时20秒都嫌慢,还有一个进阶方案:使用ONNX Runtime对模型做加速和优化。把PyTorch模型导出为ONNX格式后,CPU推理速度约提升1.5至2倍,模型体积还能压掉一部分。不过ONNX导出后注意力权重提取和关键词展示的逻辑要相应改,我建议先把完整流程跑通后再考虑这层优化。
6.3 类别不均衡导致的“全正面”陷阱
我踩过最严重的一个坑。第一版模型在测试集上准确率86%,看着还行,但实际跑客户数据时发现几乎所有文本都被判成正面。原因就是训练语料里正面样本占了80%,模型学会了“无脑选正面”。当时我一度怀疑是不是预处理代码有bug,后来打印了每条样本的标签分布才反应过来。
解决办法三个组合用:
- 损失函数加权,给样本少的类别更高的权重
- 对负面和中性样本做SMOTE过采样(这里要注意,NLP文本过采样和表格数据不一样,普通SMOTE不能直接用,我实际用的是对同一句话做同义词替换和回译增强,稍麻烦但有效)
- 评估指标从准确率改成宏平均F1,宏平均F1对类别不均衡更敏感,能更真实地反映模型对每个类的预测能力
用这几个方案后,模型在真实业务数据上的F1从0.8提高到0.86,最关键的是负面样本的召回率从不到0.3提升到了0.78,这个提升才真正有意义。
6.4 前后端联调时的几个经典错误
- 404错误:检查Vite代理配置的路径是否和后端路由前缀一致。最常见的是前端请求
/api/analyze,后端路由却是/analyze,忘了统一前缀 - 400错误:检查请求体格式。FastAPI要求字段名严格匹配,前端传的字段是
content,后端模型却是text,两边对不上就会报422 - 502错误:后端服务崩了。用
journalctl -u或docker logs查看日志,对比最后一条日志是模型加载失败还是端口被占用 - 跨域错误:确认后端有没有配置
allow_origins。不能图省事设成*,因为某些浏览器场景下带credentials的请求不允许通配符来源,建议写成白名单数组
6.5 深度模型在CPU上推理太慢怎么办
很多人跑通系统后会问:7.8GB的模型文件在CPU上跑,单条文本要2秒,批量分析1000条要30多分钟,太慢了怎么办?我给的方案优先级是:
- 先压缩输入长度。把max_length从128降到64,如果语料本身不长,准确率损失微乎其微,推理速度快了近一倍
- 再用ONNX Runtime导出FP16版本,CPU上实测能快约50%
- 如果数据量实在太大,就把批量任务放到GPU服务器上跑,模型可以不出GPU,只把结果回传MySQL
这里再分享一个经验:“模型量化”要谨慎。情感分析这种细粒度任务,INT8量化可能导致置信度分布畸变,有些模型量化后预测结果完全变了。一定先做小样本验证再决定是否上量化。
7. 部署上线与后续扩展建议
部署分为开发环境、测试环境和生产环境三种形态,我用得最多的是Docker Compose组合:前端Nginx容器 + 后端FastAPI容器 + MySQL容器。docker-compose.yml核心内容示例:
services: backend: build: ./backend ports: - "8000:8000" volumes: - ./models:/app/models environment: - DATABASE_URL=mysql+pymysql://user:pass@mysql:3306/sentiment depends_on: - mysql frontend: build: ./frontend ports: - "80:80" depends_on: - backend mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: sentiment volumes: - ./mysql_data:/var/lib/mysql模型文件我采用挂载卷的方式加载,而不是打进镜像。原因很简单——模型文件经常要换版本重训,挂载卷让升级模型时只需要替换文件并重启容器,不需要重新构建镜像。
最后关于扩展方向我提几个思路:一是支持多语种,比如把模型替换成多语言预训练模型,前端加一个语言选择项;二是增加时间序列分析,按天统计情感趋势变化,再联动告警系统,当负面占比突增时推送通知;三是接入大模型做生成式解释,比如不仅告诉用户“这条是负面”,还生成一句“因为物流延迟导致用户不满”这样的自然语言解释。第三个方向现在的成本已经不高了,很多接口或开源模型都能做到,但要注意推理时延和成本控制。
这套系统从需求到上线,我前后差不多花了两周时间,其中数据处理和模型调优占了大头。如果你也正好要做类似的中文情感分析系统,我建议你先不要急着动代码,先把数据长什么样、要判定几个类别、延迟要求多少这三点搞清楚,后面开发会顺很多。等整个链路跑通了,再回头优化模型精度和推理性能,这样踩的坑会少一半。