ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Python+ChatGPT情感分析实战:源码解析与提示词设计

Python+ChatGPT情感分析实战:源码解析与提示词设计 简介这份资源是一套基于ChatGPT实现情感分析的Python项目源码面向计算机、人工智能、通信工程等专业的在校学生及企业开发者适合作为毕业设计、课程设计、作业或项目初期立项演示也适合想入门自然语言处理的小白进阶学习。压缩包共3个文件包含2个py源码文件与1个md说明文档整体约9KB其中py文件承载情感分析核心逻辑与调用示例md文件提供项目说明与使用指引。项目围绕给定句子判断其所属情感这一任务展开代码经过测试运行成功后才上传答辩评审平均分达到96分已有108人学习下载。读者可借此掌握ChatGPT接口调用、情感分类流程与工程目录组织方式并在此基础上修改扩展实现更丰富的文本分析功能。下载后建议先阅读说明文档仅供学习参考切勿用于商业用途。1. 从一份 Python 情感分析源码说起ChatGPT 到底替我们省了哪一步电商运营每天要翻几百条评论舆情岗要盯住一条负面苗头做毕设的同学要交一个能跑起来的系统——这三类人最后都会撞上同一个问题情感分析怎么落地。传统做法是标注几千条语料、训一个 BERT 或者 TextCNN调参调到怀疑人生换一个领域比如从手机评论换到美团外卖评价准确率立刻掉一截。而「python实现的基于ChatGPT的情感分析源代码文档说明」这个方向本质是把「训练模型」这一步换成「调用大模型做推理」用提示词和少量后处理拿到可用的情感极性判断代码量从上千行压到几百行。它适合谁适合手上有文本、想快速拿到正负面结论、又不打算自己训模型的开发者也适合把情感分析当成系统里一个模块、需要接进 Flask 或 FastAPI 的工程同学。不适合谁不适合要求毫秒级响应、每天百万级调用、或者数据绝对不能出内网的场景——那类需求还是得回到本地小模型。这篇笔记就按「源码怎么组织 → 提示词怎么设计 → 批量怎么跑 → 坑在哪」的顺序把这条路走一遍。2. 源码结构拆解一个能跑的情感分析项目该有哪几个文件拿到一份「python ChatGPT 情感分析」的源码先别急着运行先看目录。绝大多数能用的项目骨架都逃不出下面这几块入口脚本、模型调用封装、提示词模板、数据读写、配置管理。看懂这个结构你换任何一家大模型 API 都能在半小时内改完。2.1 目录骨架与每个文件的职责一个我常用的最小结构长这样你可以直接照着建sentiment_gpt/ ├── main.py # 命令行入口读数据、跑分析、写结果 ├── analyzer.py # 核心类封装单条/批量情感分析 ├── prompts.py # 提示词模板集中管理方便调优 ├── config.py # 读取 API Key、模型名、并发数等配置 ├── utils.py # 文本清洗、结果解析、重试装饰器 ├── data/ │ └── reviews.csv # 输入数据至少一列文本 └── requirements.txt # 依赖清单analyzer.py是整个项目的心脏它不该关心数据从哪来只负责「给我一段文本我还你一个情感标签」。prompts.py单独拆出来是因为提示词是要反复改的混在业务代码里改一次就得翻半天。config.py用环境变量读 Key绝不硬编码——这是血泪经验源码一旦传到公开仓库Key 泄露就是分分钟的事。2.2 依赖安装与 API 客户端初始化先装依赖requirements.txt里通常就这几样pip install openai pandas tqdm tenacity python-dotenvopenai官方 SDK负责发请求pandas读 CSV、Excel处理批量数据tqdm批量跑的时候给个进度条不然几百条数据跑起来像卡死tenacity重试库网络抖动时自动重试比手写 while 循环干净python-dotenv从.env文件读 Key避免写死在代码里。初始化客户端时注意 base_url 和模型名要跟你的账号匹配# config.py import os from dotenv import load_dotenv load_dotenv() # 从 .env 读取环境变量 API_KEY os.getenv(OPENAI_API_KEY) BASE_URL os.getenv(OPENAI_BASE_URL, https://api.openai.com/v1) MODEL_NAME os.getenv(MODEL_NAME, gpt-4o-mini) MAX_RETRY 3 CONCURRENCY 5 # 并发数别一上来就开 50这里MODEL_NAME给个默认值方便本地调试CONCURRENCY控制并发新手最容易犯的错就是一次性把几百条请求全发出去结果触发限流报一堆 429。参数说明MAX_RETRY建议 3 次再多说明网络或额度本身有问题重试也没用。2.3 把情感分析封装成一个类核心类要解决三件事拼提示词、发请求、解析返回。解析这一步是翻车重灾区因为大模型不一定老老实实只回一个词。# analyzer.py import json from openai import OpenAI from tenacity import retry, stop_after_attempt, wait_exponential from config import API_KEY, BASE_URL, MODEL_NAME, MAX_RETRY from prompts import SENTIMENT_PROMPT client OpenAI(api_keyAPI_KEY, base_urlBASE_URL) class SentimentAnalyzer: def __init__(self, modelMODEL_NAME): self.model model retry(stopstop_after_attempt(MAX_RETRY), waitwait_exponential(multiplier1, min2, max10)) def _call(self, text: str) - str: resp client.chat.completions.create( modelself.model, messages[ {role: system, content: 你是一个情感分析引擎只输出JSON。}, {role: user, content: SENTIMENT_PROMPT.format(texttext)}, ], temperature0, # 情感判断要稳定温度必须为 0 max_tokens64, # 输出很短限制 token 省钱 ) return resp.choices[0].message.content def analyze(self, text: str) - dict: raw self._call(text) return self._parse(raw) def _parse(self, raw: str) - dict: try: data json.loads(raw) return { label: data.get(label, neutral), score: float(data.get(score, 0.5)), } except (json.JSONDecodeError, ValueError): # 模型没按格式回降级处理 return {label: unknown, score: 0.0, raw: raw}逻辑说明temperature0是关键情感分析要的是可复现不是创意温度调高会让同一条评论两次跑出不同标签。max_tokens64是因为我们只要一个 JSON给多了纯浪费钱。_parse里做了降级模型偶尔会加一句「好的分析如下」再给 JSON直接json.loads会炸所以用 try 兜住把原始返回塞进raw字段方便事后排查。参数上wait_exponential让重试间隔从 2 秒指数增长到 10 秒封顶避免密集重试把限流撞得更死。3. 提示词设计让 ChatGPT 稳定吐出结构化情感标签很多人觉得调大模型就是「随便写句话」结果跑出来一堆「这条评论看起来是正面的因为……」这种没法程序解析的废话。情感分析要的是机器可读的输出提示词必须把格式锁死。3.1 一个能直接抄的提示词模板# prompts.py SENTIMENT_PROMPT 请对下面的文本做情感分析严格按 JSON 输出不要任何解释。 文本{text} 输出格式 {{label: positive|negative|neutral, score: 0.0-1.0}} 其中 score 表示你对该判断的置信度越接近 1 越确定。 只输出 JSON不要 markdown 代码块不要多余文字。这个模板有三个设计点。第一明确列出三个可选标签不给模型自由发挥空间否则它会冒出「mixed」「slightly positive」这种你没法入库的值。第二要求 score 表示置信度方便后续做阈值过滤——比如只把 score 大于 0.8 的负面评论推给人工复核。第三反复强调「只输出 JSON」因为模型有很强的加解释的惯性不强调就会给你来一段小作文。3.2 中文场景下的标签体系怎么定英文情感分析常用 positive/negative 二分但中文评论里「还行」「凑合」「一般般」这类中性表达占比很高硬塞进正负两类会失真。我的做法是保留三分类但在提示词里给每个标签加一句判定标准标签判定标准典型例子positive明确表达满意、推荐、超出预期「物流快包装也好」negative明确表达不满、投诉、失望「用了三天就坏了」neutral陈述事实、无明显情绪、褒贬都有「收到了还没用」把这张表的内容浓缩进提示词比只写三个英文单词准确率高不少。注意标签体系一旦定了就别中途改否则历史数据和新数据没法合并统计。3.3 用 few-shot 例子压住边界情况遇到反讽、双重否定光靠指令模型容易翻车。加一两个例子效果立竿见影SENTIMENT_PROMPT 请对下面的文本做情感分析严格按 JSON 输出。 示例1 文本这质量真是绝了用一次就散架 输出{{label: negative, score: 0.95}} 示例2 文本东西收到了包装完好 输出{{label: neutral, score: 0.7}} 现在分析 文本{text} 输出示例1 专门治反讽「绝了」表面是褒义实际是负面给模型一个锚点。示例2 治「陈述事实」被误判成正面。注意示例别给太多两三个足够给多了既费 token 又可能让模型照抄示例的 score 值。4. 批量跑数据从单条调用到并发处理与结果落盘单条能跑通只是开始真实场景动辄几千条评论串行跑一条一秒一千条就是十几分钟。这一章解决批量、并发、断点续跑和结果存储。4.1 用 pandas 读数据并做文本清洗# main.py import pandas as pd from tqdm import tqdm from analyzer import SentimentAnalyzer def load_data(path: str) - pd.DataFrame: df pd.read_csv(path) df df.dropna(subset[content]) # 丢掉空文本 df[content] df[content].astype(str).str.strip() df df[df[content].str.len() 1] # 丢掉单字符 df df.drop_duplicates(subset[content]) # 去重省钱 return df.reset_index(dropTrue)清洗这步看着不起眼但去重能直接砍掉 10% 到 30% 的调用量。电商评论里「好评」「不错」这种重复短评特别多不去重就是白花钱。dropna和长度过滤是防止空字符串发过去模型对空输入会返回奇怪结果。4.2 并发调用与限流控制用concurrent.futures做并发但一定要配信号量控制速率from concurrent.futures import ThreadPoolExecutor, as_completed import threading, time def batch_analyze(df, analyzer, concurrency5): results [None] * len(df) lock threading.Lock() sem threading.Semaphore(concurrency) def worker(idx, text): with sem: try: results[idx] analyzer.analyze(text) except Exception as e: results[idx] {label: error, score: 0.0, raw: str(e)} time.sleep(0.2) # 主动降速避开限流 with ThreadPoolExecutor(max_workersconcurrency) as pool: futures [pool.submit(worker, i, t) for i, t in enumerate(df[content])] for _ in tqdm(as_completed(futures), totallen(futures)): pass return results逻辑说明Semaphore保证同时最多只有concurrency个请求在飞time.sleep(0.2)是主动降速看起来慢实际比被限流后重试快得多。results用下标写入而不是 append是为了保证结果顺序和原数据一一对应——并发场景下 append 的顺序是乱的这是新手常踩的坑。参数上concurrency从 5 起步观察有没有 429没有再加到 10别一步到位。4.3 断点续跑与结果落盘跑一千条最怕跑到 800 条崩了重头再来。加个中间落盘def save_with_checkpoint(df, results, out_path, ckpt_every50): df[label] [r[label] for r in results] df[score] [r[score] for r in results] df.to_csv(out_path, indexFalse, encodingutf-8-sig)encodingutf-8-sig是为了 Excel 打开不乱码这个细节很多人栽过。更稳的做法是每 50 条写一次临时文件崩了之后读回已完成的部分跳过已处理的文本。判断依据用文本内容做 key别用行号因为清洗后行号会变。5. 避坑与排查情感分析接大模型最容易翻车的 5 个地方这一章全是踩过的坑按「现象 → 原因 → 解决」写遇到问题直接对号入座。坑一返回结果里带 markdown 代码块json.loads 直接报错。现象是解析函数抛JSONDecodeError打印原始返回发现是json {...} 。原因是模型习惯性把 JSON 包进代码块。解决办法是在提示词里明确「不要 markdown 代码块」同时在解析前做一层清洗raw.strip().removeprefix(json).removesuffix().strip()双保险。坑二并发一开高就大面积 429重试也救不回来。现象是日志里全是RateLimitError重试几次后直接失败。原因是瞬时请求数超过账号的 RPM 限制。解决办法是把并发降到 3 到 5加time.sleep主动降速并且用指数退避重试。别迷信「并发越高越快」被限流后总耗时反而更长。坑三同一条文本两次跑出不同标签。现象是复跑校验时发现结果对不上。原因是temperature没设成 0或者用了会随机采样的模型。解决办法是显式设temperature0并且固定模型版本别用会滚动更新的别名。坑四中性评论被大量误判成正面。现象是「收到了」「还行」这类被判 positive。原因是提示词没给中性判定标准模型默认往正面靠。解决办法是在提示词里补中性标签的判定规则和 few-shot 例子必要时对 score 低于阈值的重新归类为 neutral。坑五API Key 写死在代码里传到公开仓库泄露。现象是收到额度异常消耗的告警。原因是 Key 硬编码在config.py或main.py。解决办法是用.env文件加python-dotenv并且把.env加进.gitignore。已经泄露的 Key 立刻去后台吊销重发别抱侥幸。6. 进阶技巧用缓存和本地小模型把成本压下来跑通之后真正决定这个方案能不能长期用的是成本。我一般会做两件事加缓存、做分层。缓存最简单用文本的哈希做 key把已经分析过的结果存本地 SQLite 或 JSON 文件。同一批数据反复跑、或者增量数据里有重复评论时命中缓存直接返回一分钱不花import hashlib, sqlite3 def get_cache_key(text: str) - str: return hashlib.md5(text.encode(utf-8)).hexdigest() def cached_analyze(analyzer, text, conn): key get_cache_key(text) row conn.execute( SELECT label, score FROM cache WHERE key?, (key,) ).fetchone() if row: return {label: row[0], score: row[1], cached: True} result analyzer.analyze(text) conn.execute(INSERT OR REPLACE INTO cache VALUES (?,?,?), (key, result[label], result[score])) conn.commit() return result分层则是先用本地小模型比如一个几百 MB 的中文情感分类模型过一遍只把置信度低的样本丢给 ChatGPT 复核。这样 80% 的简单样本本地解决20% 的疑难样本才花钱调 API整体成本能降一个数量级。判断哪些该复核就看本地模型输出的概率落在 0.4 到 0.6 之间的全部送上去。验证这套流程有没有效果别只看准确率一个数。我会抽 100 条人工标一遍算混淆矩阵重点看负面类的召回——舆情场景漏掉一条负面比误判十条正面严重得多。如果负面召回低于 0.9就回去调提示词里的负面判定标准或者把复核阈值放宽。最后说个习惯每次改完提示词别直接全量跑先拿 20 条固定测试集跑一遍对比确认没退化再上量。我吃过亏改了一句提示词正面准确率涨了 3 个点负面召回掉了 8 个点全量跑完才发现白烧了一轮钱。希望帮到你。本文还有配套的精品资源点击获取
返回列表