公司每个月积累几千条用户反馈(App 评论、客服工单、问卷开放题),之前靠运营同事手动分类打标签,一个人干两三天。这篇记录一下怎么用 LLM 把这个流程自动化的,包括方案设计、模型选择、准确率对比、以及上线后的实际效果。


原始需求

产品运营每月需要从大约 3000 条用户反馈中完成以下工作:

  • 情感分类:正面 / 负面 / 中性
  • 主题标签:从预定义的 15 个标签中选择 1-3 个(如"性能问题"、“UI 体验”、“功能建议”、"客服态度"等)
  • 紧急程度:高 / 中 / 低
  • 输出摘要:每条反馈压缩成一句话

之前纯手工的话,一个熟练的运营同事大约每小时处理 40-50 条,3000 条要六七十个工时。


方案设计

核心思路:用 LLM 做初筛,人工只处理低置信度的结果。

原始反馈(3000 条)
        │
        ▼
LLM 批量处理 → 输出结构化 JSON
        │
        ▼
置信度过滤
        │
        ├── 高置信度(~85%)→ 直接入库
        │
        └── 低置信度(~15%)→ 人工复核

这样人工只需要处理大约 450 条,工作量从 70 小时降到不到 10 小时。


Prompt 设计

这个环节花的时间最长。直接丢一句"帮我分类这条反馈"效果很差,模型返回的标签不稳定,格式也不统一。

最终稳定下来的 prompt 结构:

SYSTEM_PROMPT = """你是一个用户反馈分析助手。请严格按以下 JSON 格式返回结果,不要输出任何其他内容。

{
  "sentiment": "positive" | "negative" | "neutral",
  "tags": ["标签1", "标签2"],
  "urgency": "high" | "medium" | "low",
  "summary": "一句话摘要",
  "confidence": 0.0-1.0
}

可选标签列表(只能从中选择):
性能问题、闪退崩溃、UI体验、功能建议、付费相关、客服态度、
隐私安全、兼容性、加载速度、通知推送、账号问题、内容质量、
社交功能、搜索体验、其他

confidence 字段表示你对本次分类的把握程度,0.8 以上视为高置信度。"""

def build_prompt(feedback_text):
    return [
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": f"请分析以下用户反馈:\n\n{feedback_text}"}
    ]

几个关键细节:

  • 限定标签列表:不给模型自由发挥的空间,否则它会编造标签,下游没法统计
  • 要求 confidence 字段:让模型自评置信度,低于 0.8 的进人工复核队列
  • 强调"不要输出任何其他内容":防止模型在 JSON 前后加解释文字

模型选择:跑了一轮对比

在正式上线前,随机抽了 200 条已经人工标注过的反馈做对比测试。

from openai import OpenAI
import json, time

client = OpenAI(api_key="your-key", base_url="https://ai.tikhub.io/v1")

models_to_test = ["gemini-2.5-flash", "claude-sonnet-4-20250514", "gpt-4.1-mini"]

for model in models_to_test:
    correct = 0
    format_errors = 0
    
    for feedback in test_set:  # 200 条带人工标注的测试集
        resp = client.chat.completions.create(
            model=model,
            messages=build_prompt(feedback["text"]),
            temperature=0.1  # 分类任务用低温度
        )
        try:
            result = json.loads(resp.choices[0].message.content)
            if result["sentiment"] == feedback["human_label"]:
                correct += 1
        except json.JSONDecodeError:
            format_errors += 1
        
        time.sleep(0.3)  # 主动限速
    
    print(f"{model}: 准确率 {correct}/200, 格式错误 {format_errors}/200")

结果:

模型 情感准确率 标签匹配率 JSON 格式正确率 平均耗时/条
Gemini 2.5 Flash 91% 84% 97% 0.8s
Claude Sonnet 4 94% 89% 100% 1.9s
GPT-4.1 Mini 90% 82% 99% 0.6s

Claude Sonnet 准确率最高,但处理 3000 条的总耗时和费用也最高。Gemini Flash 在准确率和速度之间取了一个不错的平衡。

最终方案:日常批量处理用 Gemini 2.5 Flash,人工复核队列里的低置信度条目再用 Claude Sonnet 跑一遍做二次判断。


批量处理的工程细节

3000 条不能一条条串行调,太慢了。但也不能几千个请求一瞬间全发出去,会被限速。

用了一个简单的并发控制:

import asyncio
import aiohttp

CONCURRENCY = 10  # 同时最多 10 个请求
semaphore = asyncio.Semaphore(CONCURRENCY)

async def process_one(session, feedback):
    async with semaphore:
        async with session.post(
            "https://ai.tikhub.io/v1/chat/completions",
            headers={"Authorization": "Bearer your-key", "Content-Type": "application/json"},
            json={
                "model": "gemini-2.5-flash",
                "messages": build_prompt(feedback["text"]),
                "temperature": 0.1
            }
        ) as resp:
            data = await resp.json()
            content = data["choices"][0]["message"]["content"]
            try:
                return json.loads(content)
            except json.JSONDecodeError:
                return {"error": "parse_failed", "raw": content}

async def process_batch(feedbacks):
    async with aiohttp.ClientSession() as session:
        tasks = [process_one(session, fb) for fb in feedbacks]
        return await asyncio.gather(*tasks)

results = asyncio.run(process_batch(all_feedbacks))

CONCURRENCY = 10 是试出来的,太高会触发限速,太低处理太慢。3000 条跑下来大概 8-10 分钟。


上线后的实际效果

跑了两个月之后的数据:

指标 手工时期 自动化之后
处理耗时 约 70 小时/月 自动 10 分钟 + 人工复核约 8 小时
情感分类准确率 95%(人工基准) 92%(自动)/ 96%(自动 + 复核)
从收集到出报告的周期 5-7 个工作日 1 个工作日

准确率从 95% 到 92% 有一点下降,但考虑到时效性的巨大提升(运营能在次日就看到分析结果),产品团队觉得完全可以接受。加上人工复核环节之后,整体准确率反而比纯手工还高了一点。


踩坑记录

反馈文本的预处理很重要:用户反馈里经常有 emoji、火星文、中英混杂、甚至纯表情包回复。直接喂给模型会影响分类效果。上线前加了一步简单的清洗:去掉连续重复的 emoji、过滤纯符号内容、超长文本做截断。

temperature 一定要调低:分类任务不需要创造性,temperature=0.1 甚至 0 可以显著提高输出的一致性。我一开始用默认的 0.7,同一条反馈跑两次标签居然不一样。

定期用新数据校准:模型不会随时间变化,但用户反馈的用词习惯会变。每隔一两个月抽查 100 条做一次准确率校验,发现下降了就调整 prompt 或标签定义。


如果你也有类似的批量文本处理需求,整体思路可以参考。模型选择上,处理中文反馈的话 Gemini Flash 的性价比确实不错,需要更高准确率就上 Claude Sonnet 做兜底。端点方面我这边用的 TikHub AI(ai.tikhub.io)的统一接口,一个 Key 能同时调 Gemini 和 Claude 比较方便,不用分别管两家的账号。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐