☰
用LLM自动提炼文章标签:标题+正文双层提取全流程实战
2026/10/19 7:33:59 网站建设 项目流程

干了这么多年内容运营和编辑工具开发,我越来越觉得,文章标签这件事,属于那种“看着小事一桩,实际能决定内容盘子生死”的环节。标签打得准,文章分发效率高、推荐精准、搜索有曝光,甚至能直接反哺商业化变现;标签打得稀烂,内容库就是一团浆糊,后面想做什么数据分析、用户画像、专题聚合,全都无从下手。最近我们团队做了一个“从标题到正文,AI 自动提炼文章标签”的内部方案,用 LLM 把过去编辑手动填标签的流程彻底改掉了。这篇文章把我整套设计思路、技术选型、实操代码和踩坑记录全部分享出来。

先说一下这个方案适合谁看:在内容平台、自媒体团队、出版机构、企业内部知识库这些场景里,每天要处理几十上百篇稿子,标签体系乱成一锅粥,编辑和运营被重复劳动拖垮的团队,这份经验可以直接抄作业。如果你是独立博主,文章量小但希望把标签质量提上去,平时手写标签经常觉得词穷的话,这套思路同样适用,只是落地规模可以缩得小一些。

1. 整体设计思路:为什么标签值得用 AI 重做一遍

1.1 标签的真实价值,不只是“分类”这么简单

很多人把标签理解成简单的文章分类,其实标签在内容体系里的作用,比我刚入行时以为的复杂得多。我用一张表来说明标签在整个内容链路里到底在服务谁。

使用方标签承担的任务标签质量差时会发生什么
推荐系统建立用户兴趣与内容之间的关系推不准,用户刷几下就离开
搜索系统提高关键词命中率,帮助文章被找到搜不出、搜不准,文章白写
运营人员做专题策划、活动聚合找素材像大海捞针
广告系统做内容与广告的匹配匹配不上,收入上不去
作者/编辑复盘内容方向看不出来自己到底在写什么

这里最容易被低估的是“标签”和“分类”的区别。分类是一个树状结构,文章只能挂到一个节点下;标签是扁平结构,一篇文章可以同时挂“爬虫”“网页抓取”“数据清洗”三个标签,它描述的是文章的多维属性。这种多维属性恰恰是 AI 擅长捕捉的,因为人类编辑通常只凭直觉给出两三个词,而不会认真考虑这个内容可能在哪些维度上被需要。

1.2 传统的标签生产模式,问题到底出在哪

我们团队在引入 AI 之前,标签主要靠三种方式生产,各有各的坑。

第一种是全人工打标。编辑读完文章凭经验给出几个词。这种方式的优点是质量基本可控,但缺点太致命:慢、累、标准不统一。同一个编辑心情好的时候可能会多写几个标签,赶稿的时候只给一个。不同编辑对同一篇文章的理解差异更是天壤之别,内容库越做越乱。

第二种是纯规则匹配。列一个关键词词表,文章里出现“Python”就打“Python”标签,出现“爬虫”就打“爬虫”。这种方式处理专业术语还行,但面对语义变化就废了。比如一篇文章通篇在讲“反爬机制绕过”,但整篇没有出现“爬虫”二字,规则就漏了;再比如文章里提到“这个话题水很深”,规则可能把“水很深”这种修饰短语误判为技术关键词。

第三种是用 TF-IDF 做词频统计,把高频词拿来做标签。这个方法的问题在于,标签不等同于高频词。一篇访谈文章反复出现受访者名字,按词频会把名字打上去,但名字根本不适合做内容标签;一篇教程反复出现“方法”“问题”“步骤”这些词,词频很高但对内容刻画毫无意义。

这三类问题本质上指向同一个核心矛盾:标签是需要“理解”之后才能产出的东西,而过去的自动化手段都在做“匹配”,没有做“理解”。标题是文章最浓缩的抽象概括,正文是观点的完整展开,要让标签既符合用户搜索习惯又能反映文章核心价值,就必须先读懂两者之间的关系,这正是大语言模型擅长的事情。

1.3 以标题为纲、以正文为据的双层提炼架构

我的整体设计思路用一句话总结:标题提炼方向,正文验证细节,最后统一融合校准。

为什么要这样分层?因为标题和正文的属性完全不同。标题是高度浓缩的,通常是作者自己提炼出的全文核心,但它包含的信息量太少,甚至有时候为了吸引点击会用比较夸张的表达;正文字量大,包含了真实的细节、案例、方法,但信息密度低,直接让 AI 读完整篇再打标容易淹没重点。

所以整个流程分四层:

  1. 标题输入层:只把文章标题给 AI,让它先给出第一版候选标签,这一步相当于让 AI 快速抓住全文的“纲”。
  2. 正文深挖层:把正文喂给 AI,结合标题,让 AI 找出标题没有覆盖到的重要子主题,补全标签候选。
  3. 融合裁剪层:把两轮候选标签合并,去重、统一表述、控制数量。
  4. 校验输出层:检查标签与文章内容是否一致,过滤不合适的词,输出最终结果。

这个设计最重要的优势是:即使标题写得比较“标题党”,正文深挖层也能把内容拉回真实的方向;即使正文话题很散,标题预提炼层也能保证标签不跑偏。两条腿走路,互为补充。

2. 技术选型:为什么最后选了 LLM 方案

2.1 可落地的标签抽取方案对比

做技术方案选型的时候,我对比了市面上常见的几种路线,不只是 LLM。

写在前面:我已经把和标题相关的几个技术方案从纯字符匹配到机器学习模型全部过了一遍,这里是我的真实对比结果。

方案类型代表技术优点缺点适合场景
硬匹配正则表达式、词表匹配快、便宜、可解释无法处理同义词和语义变化专业术语非常固定的领域
统计方法TF-IDF、TextRank无需标注数据输出的是关键词不是标签,缺乏抽象归纳能力关键词抽取,不是打标
传统多标签分类文本分类模型可控标签体系,效果稳定需要大量标注样本,新标签需要重新训练垂直领域、标签体系封闭的平台
大模型方案LLM 提示词/微调理解语义、能抽象、无需标注数据有幻觉风险,成本相对高标签体系灵活、内容类型复杂、快速迭代需求

2.2 LLM 做“语义摘要型标签”,为什么无可替代

我举一个例子,最初的测试里有篇文章标题是《从零实现一个轻量级 Web 服务器,我踩了这些坑》,正文里大量出现“TCP 三次握手”“Socket 编程”“HTTP 状态码”“阻塞非阻塞”。

传统词频方案给出的标签是:“服务器”“HTTP”“Socket”“踩坑”。看着似乎还行,但它漏掉了一个非常重要的认知标签——“网络编程”。这个标签没有直接出现在正文里,需要读者通读之后才能抽象出来。而 LLM 方案给出的标签是:“Web服务器”“网络编程”“Socket”“HTTP协议”“项目实操”“踩坑经验”,不管是从语义概括还是从用户搜索角度,都更接近编辑人工标注的水平。

在理解标题和正文的关系上,用一句生活化的话来说:传统方案像是一个只做“词面匹配”的检索员,看到“Socket”就盖章“Socket”;LLM 像一个读完文章后帮你写内容摘要的同学,它知道这篇文章本质上是讲网络编程入门实践的。标签的本质是“概括”而非“匹配”,所以 LLM 在这件事上有结构性优势。

2.3 模型本身怎么选:API 还是私有化

我做选型时重点权衡了三个维度:效果、成本、数据隐私。

效果排在第一位。当时试了本地的小参数模型和几家主流的商业化 API,差距非常明显。小参数模型在“抽取类标签”上还能应付,比如从文章里找出已有的技术名词;但到了“抽象类标签”和“合并同义表述”这两个环节就开始力不从心,经常给出一些词不达意的标签。API 方案在理解力上基本没有问题,所以我最终选择了 API。

成本方面,做一个粗略估算:平均每篇文章标题约 30 字,正文字数在 3000 到 8000 字之间,按 Token 换算大约 2000 到 6000 Token。单次调用成本折合人民币几分钱到一两毛钱,取决于模型档次。日均处理 500 篇文章的情况下,每月的标签生成成本在几百到一千出头,相比投入一个专职编辑的人力成本,便宜太多。

隐私方面,有些内容平台的文章涉及未发布稿件或者商业化数据,不能直接外传。我的处理方案是分两级:常规文章走 API,敏感稿件走本地小模型或者人工打标,后续再优化蒸馏方案。这一套“双轨制”从上线到现在跑得很稳。

3. 核心实现:从标题预提炼到正文深挖的完整流程

3.1 流程全景与输入输出约定

我先定义一下输入输出格式,所有环节都围绕这个约定来。

  • 输入:文章标题 title、正文 content、最大标签数 max_tags(默认 5 个)
  • 输出:标签列表 tags,例如["Web服务器", "网络编程", "Socket", "HTTP协议", "踩坑经验"]

我建议在工程上把每个环节做成独立函数,不要一个脚本把所有逻辑搅在一起。原因后面会讲,每个环节的错误处理方式不一样,拆开才能独立排查问题。整个处理流程如下:

  1. 标题预提炼:让 AI 基于标题生成 3 到 5 个候选标签。
  2. 正文深挖:把正文按规则拆段,选前 N 段最有代表性的内容,结合标题做第二轮提炼。
  3. 融合裁剪:两轮候选标签合并去重,统一表述格式。
  4. 校验输出:再用一次轻量调用做一致性检查,过滤不匹配标签。

这套流程看起来多了一次 LLM 调用,但如果在裁剪阶段做得好,可以省掉最后的校验步骤,整体调用控制在 2 到 3 次,仍然很快。

3.2 标题预提炼:先让模型抓住全文的“纲”

标题预提炼这一步的任务不是直接得到最终标签,而是产出一个“候选池”,让模型先基于标题输出它对文章的理解。提示词我打磨了很久,最稳定的版本是这样的:

你是一名资深的内容编辑,请根据以下文章标题,提炼出这篇文章最可能的主题标签。 要求: 1. 标签必须是文章内容的真实反映,禁止臆测 2. 标签要兼顾抽象概念和具体关键词 3. 每个标签控制在 2 到 8 个字 4. 输出 3 到 5 个标签 5. 只输出 JSON 数组,不要输出其他内容 标题:{title} 输出格式:["标签1", "标签2", "标签3"]

这一步比较关键的细节包括:

  • 明确要求“禁止臆测”,避免模型把自己的联想强加到标题上。
  • 要求把抽象概念和具体关键词都纳入候选池,比如“网络编程”和“Socket”都要有,后面融合裁剪时才有选择空间。
  • 限定“只输出 JSON 数组”,方便程序直接解析。我最初忘了做这个限定,模型经常在标签前后加一些“根据标题分析,标签如下”之类的废话,解析时还要再做清洗。

我先用 200 篇文章测试了这一阶段的输出,质量已经能超过人工打标的 60%。但标题存在明显的两类短板:一是标题“标题党”风格太重,比如《震惊!原来这样写代码效率翻倍》,模型可能提取出“写代码效率”这种泛泛的词;二是标题过于含蓄,具体技术点藏在正文里。所以标题预提炼只能作为第一层候选,不能作为最终结果。

3.3 正文深挖:找到标题之外的重要子主题

正文深挖是整个流程中技术含量最高的部分,直接决定标签最终的覆盖面。

先说明为什么不能把整篇正文一次性扔给模型。我做过对比实验,把 8000 字文章一次性传入和拆分处理后分别测试,一次性传入的问题是:模型处理超长文本时注意力会分散,容易遗漏藏在文章后半部分的细节;而且 Token 费用高,时延也大。拆分处理的效果明显更稳。

我的拆分策略如下:

  1. 把正文按段落切分,过滤掉过短的句子(比如少于 15 字)和疑似模板内容(比如“关注我”“点击收藏”等)。
  2. 按顺序选取前面 40% 的段落、中间 30% 的段落、结尾 30% 的段落各若干段,让样本覆盖全文结构,不遗漏从铺垫到结论的任意重要环节。
  3. 将选中的段落拼接成一个长度可控的“正文采样块”,通常控制在 1500 到 2500 字之间,再交给模型做第二轮提炼。

正文深挖的提示词如下:

你是一名资深的内容编辑,正在为下面这篇文章添加标签。 文章标题:{title} 文章正文(节选):{content_sample} 请基于标题和正文,完成以下任务: 1. 找出标题没有覆盖到的关键主题和子主题 2. 提炼出技术方向、核心概念、应用场景、目标读者等维度上的标签 3. 排除文章中的修饰性内容,比如情绪表达、背景铺垫 4. 输出不超过 5 个标签 5. 只输出 JSON 数组,不要输出其他内容 输出格式:["标签1", "标签2", "标签3"]

这里“维度”这个词是实验之后故意加进去的,因为最初的输出常常全是具体技术词,缺乏场景和读者维度的标签。加上之后,“入门”“实战”“踩坑经验”这类读者决策型标签出现的概率大幅提升。

3.4 融合裁剪:过滤泛词、去重、控制标签数量

融合裁剪这一步做得好,最终标签质量能比直接生成高出一截。具体做四件事。

第一,候选合并。把标题预提炼和正文深挖生成的两个 JSON 数组合并成一个集合。这一步相对机械,直接扩展数组即可。

第二,去重与同义归一。把语义相同的标签合并成一个。比如标题阶段生成了 “Web服务器”,正文阶段生成了 “Web服务端”,需要归一成同一个。这里又要依赖一次 LLM 小调用,提示词设计为:

以下是两个编辑分别给同一篇文章打的标签,请合并重复项,保留更合理的表述: 标签A:{tags_a} 标签B:{tags_b} 只输出 JSON 数组,不要解释。

如果不想多一次调用,也可以用简单的编辑距离算法做近似去重,但当遇到“爬虫”和“网络爬虫”这种语义相同但字面差异较大的词组时,效果不够好。我建议留一次 LLM 调用做同义归一,整条链路才完整。

第三,过滤泛标签。这是最容易翻车的一步。LLM 在标签生成时天然倾向于输出“技术”“方法”“人工智能”“作用”等特别泛的词,因为这些词在它的知识分布里太常见了。我维护了一个禁词表,上线之后不断积累,比如 “方法”“技巧”“介绍”“应用”“一文读懂” 这些泛标签直接过滤。

第四,数量控制。最终标签建议控制在 3 到 8 个。少于 3 个覆盖不了文章全貌,多于 8 个就会稀释重点。我的逻辑是:先按相关性排序,如果候选太多就只保留排序靠前的;如果候选太少,就回到正文深挖环节补充一次。这个“相关性排序”可以直接让模型输出时带上置信度,我用的提示词会要求模型按相关性从高到低排列。这样裁剪时直接从头截断。

3.5 完整代码实现:一个可直接落地的 Python 版本

接下来把整个流程完整代码化。下面这段代码我在实际项目中跑得很稳,你可以直接复制改成自己的 API 配置和禁词表。

import os import json import time import hashlib import requests from typing import List, Optional # ============ 配置 ============ API_URL = "https://your-api-endpoint/v1/chat/completions" API_KEY = os.getenv("LLM_API_KEY", "") DEFAULT_MAX_TAGS = 5 FORBIDDEN_TAGS = {"方法", "技巧", "介绍", "应用", "作用", "一文读懂", "干货", "总结"} # ============ 基础 LLM 调用 ============ def llm_chat_json(system_prompt: str, user_prompt: str, temperature: float = 0.3, max_tokens: int = 300) -> list: """调用 LLM,要求模型返回 JSON 数组。""" payload = { "model": "your-default-model", "temperature": temperature, "max_tokens": max_tokens, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt} ] } headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"} resp = requests.post(API_URL, json=payload, headers=headers, timeout=30) resp.raise_for_status() content = resp.json()["choices"][0]["message"]["content"] # 清理模型可能输出的多余文字,只保留 JSON 部分 start = content.find("[") end = content.rfind("]") + 1 if start == -1 or end == 0: raise ValueError(f"模型输出不是合法 JSON 数组: {content}") try: return json.loads(content[start:end]) except json.JSONDecodeError: raise ValueError(f"JSON 解析失败: {content[start:end]}") # ============ 标题预提炼 ============ TITLE_PROMPT = """ 你是一名资深的内容编辑,请根据以下文章标题,提炼出这篇文章最可能的主题标签。 要求: 1. 标签必须是文章内容的真实反映,禁止臆测 2. 标签要兼顾抽象概念和具体关键词 3. 每个标签控制在 2 到 8 个字 4. 输出 3 到 5 个标签 5. 只输出 JSON 数组,不要输出其他内容 标题:{title} """ def extract_tags_from_title(title: str) -> List[str]: result = llm_chat_json( system_prompt="你是一个严谨的标签生成助手。", user_prompt=TITLE_PROMPT.format(title=title), temperature=0.2, ) return result # ============ 正文采样 ============ def sample_article_content(content: str, sample_chars: int = 2000) -> str: """按比例从开头、中间、结尾各采样一部分,拼成摘要块。""" paragraphs = [p.strip() for p in content.splitlines() if p.strip()] # 过滤太短的无意义段落 paragraphs = [p for p in paragraphs if len(p) >= 15] total = len(paragraphs) if total == 0: return content[:sample_chars] head = paragraphs[: max(1, int(total * 0.4))] middle = paragraphs[int(total * 0.3): int(total * 0.7)] tail = paragraphs[max(int(total * 0.7), int(total * 0.5)):] sampled = head + middle + tail result = "".join(sampled) return result[:sample_chars] # ============ 正文深挖 ============ BODY_PROMPT = """ 你是一名资深的内容编辑,正在为下面这篇文章添加标签。 文章标题:{title} 文章正文(节选):{content_sample} 请基于标题和正文,完成以下任务: 1. 找出标题没有覆盖到的关键主题和子主题 2. 提炼出技术方向、核心概念、应用场景、目标读者等维度上的标签 3. 排除文章中的修饰性内容,比如情绪表达、背景铺垫 4. 输出不超过 5 个标签 5. 只输出 JSON 数组,不要输出其他内容 输出格式:["标签1", "标签2", "标签3"] """ def extract_tags_from_body(title: str, content: str) -> List[str]: sample = sample_article_content(content) result = llm_chat_json( system_prompt="你是一个严谨的标签生成助手。", user_prompt=BODY_PROMPT.format(title=title, content_sample=sample), temperature=0.3, ) return result # ============ 融合裁剪 ============ MERGE_PROMPT = """ 以下是两个编辑给同一篇文章打的标签,请合并重复项和同义词,保留更合理的表述。 要求: 1. 合并语义相同的标签 2. 剔除含义过宽、没有信息量的泛标签 3. 最终输出 3 到 8 个标签 4. 只输出 JSON 数组,不要输出其他内容 标签A:{tags_a} 标签B:{tags_b} """ def merge_tags(tags_a: List[str], tags_b: List[str]) -> List[str]: # 先做一次简单过滤,减少无效调用 tags_a = [t for t in tags_a if t not in FORBIDDEN_TAGS] tags_b = [t for t in tags_b if t not in FORBIDDEN_TAGS] merged = llm_chat_json( system_prompt="你是一个严谨的标签合并助手。", user_prompt=MERGE_PROMPT.format( tags_a=json.dumps(tags_a, ensure_ascii=False), tags_b=json.dumps(tags_b, ensure_ascii=False) ), temperature=0.1, ) return merged[:DEFAULT_MAX_TAGS] # ============ 编排主流程 ============ def generate_article_tags(title: str, content: str) -> List[str]: tags_from_title = extract_tags_from_title(title) tags_from_body = extract_tags_from_body(title, content) final_tags = merge_tags(tags_from_title, tags_from_body) return final_tags # ============ 带缓存的批量处理版本 ============ _CACHE = {} def generate_article_tags_cached(title: str, content: str) -> List[str]: """同样的内容不重复调用模型,节省成本。""" key = hashlib.md5((title + "||" + content[:2000]).encode("utf-8")).hexdigest() if key in _CACHE: return _CACHE[key] tags = generate_article_tags(title, content) _CACHE[key] = tags return tags if __name__ == "__main__": title = "从零实现一个轻量级 Web 服务器,我踩了这些坑" content = """(这里填入文章正文)""" try: print(generate_article_tags_cached(title, content)) except Exception as e: print(f"标签生成失败:{e}")

注意几个细节:

  • temperature参数在标题预提炼和正文深挖阶段设为 0.2 到 0.3,保持稳定;在合并裁剪阶段设为 0.1,因为这一步要的是确定性归一,不需要创造力。温度越低输出越保守,这是控制幻觉最直接的手段。
  • 采样函数里把“开头 40%、中间 30%、结尾 30%”分开取,是因为文章通常在开头讲背景、中间讲操作、结尾讲总结,三个部分各含关键信息,按段落比例分布采样最保险。
  • 缓存键只用正文前 2000 字,避免超长 Key,同时不影响重复判断的准确率,因为同标题同开头基本可以确认为同一篇文章。

3.6 提示词工程中的几个稳定增效技巧

这节是很有价值的实操心得,直接分享几个我在打磨过程中验证有效的提示词小技巧。

技巧一:给模型一个“身份+流程指令”。在正文深挖的提示词里先说明“你是一名资深内容编辑”,再说明“正在为下面这篇文章添加标签”。实验对比中,带身份描述的标签结果比裸提示词在准确率上高出大约 5 到 8 个百分点,原因是身份描述激活了模型关于编辑工作方式的常识。

技巧二:把“不要做什么”写清楚。比如“禁止臆测”“排除修饰性内容”“只输出 JSON 数组”。大模型对否定指令的遵从度其实不稳定,但明确写出来仍然能减少大量无效输出。我测试过在提示词里同时写明“要做什么”和“不要做什么”的稳定度最高。

技巧三:关键变量统一通过格式化字符串注入。不要在提示词里手写拼接内容,避免引号冲突和长文本遗漏。用.format()或 f-string 注入即可,JSON 解析时也更稳。

4. 常见问题与排查实录

这套系统上线跑了几个月,遇到过不少实际问题,我挑几个最具代表性的,整理成速查表。

问题表现原因解决方案
标签过泛输出“人工智能”“方法”“技巧”模型倾向于输出高频泛词维护禁词表,并在提示词中要求“剔除含义过宽标签”
漏掉关键子主题文章后半段的案例没出现在标签里一次性传长文本导致注意力分散采用分段采样,开头/中间/结尾分别抽内容
标签幻觉出现文章完全没有提到的概念标题过于抽象,或模型被自己的知识先验带偏降低 temperature,增加“禁止臆测”指令,抽样人工复核
标签数量不稳有时 2 个,有时 10 个模型对数量限制的遵从不稳定提示词中把数量要求放在靠前位置,并在融合裁剪阶段强控 max_tags
批量调用超时处理 500 篇时频繁报错同步请求阻塞,或模型限流改用并发池,限制最大并发数 5,增加指数退避重试逻辑
不同模型效果差异大本地小模型输出乱、API 模型效果正常小模型抽象理解能力不足API 为主,敏感数据走小模型双轨,后续做联合精排

下面挑几个重点问题展开说说。

4.1 标签泛化问题:限都限不住,后来怎么解决的

标签过泛是这个项目里我最头疼的问题。模型总喜欢在标签列表里塞“人工智能”这种大而全的词,尤其当文章标题里出现了“AI”字样时。一个“AI + 医疗影像”的文章,模型很可能给出“人工智能”“医疗”“影像”这三个标签,而实际上“肺结节检测”“深度学习模型”“医学图像分割”才是更有价值的细粒度标签。

后来我做了三件事来解决。第一,在提示词里加入明确限制:“标签必须具体到能区别于同主题下的其他文章,禁止使用含义过宽的词”。模型收到这个指令后泛标签数量明显减少。第二,维护禁词表,把已经识别的泛标签直接过滤。第三,在融合裁剪的提示词里专门加一条“剔除没有信息量的泛标签”,因为合并同义词时模型也会顺带做一次判断。

这三层下来,泛标签占比从最初的 40% 降到了 10% 以下。不过说实话,10% 的比例仍然存在,因为有些标签是“语境泛化”的,比如一篇技术对比文章,标签“对比”就很合理,但禁词表没法穷举,只能靠后续人工定期抽检。

4.2 标题与正文信息差太大,标签偏离真实内容

这个坑出现最多的场景是“教程型文章”用了“经验分享型标题”。举个例子,标题是《记一次生产事故的复盘》,文章正文其实通篇在讲“Redis 缓存雪崩”“熔断降级”“高并发架构设计”。标题预提炼阶段给出的标签是“生产事故”“复盘”,这个方向没错,但完全丢了核心技术内容。如果直接拿这个结果当最终标签,这篇文章在搜索“缓存雪崩”时就不会被检索到。

正文深挖环节就是为这种情况兜底的。我用一个简单的对比实验来说明:只跑标题阶段,这篇“生产事故复盘”的标签是["生产事故", "复盘", "经验"];跑完整流程后,标签变成了["Redis", "缓存雪崩", "高并发架构", "生产事故", "熔断降级"],覆盖面提升非常明显。

这个案例也提醒我:正文采样绝不能简单粗暴地只取开头几百字。如果按开头取,只能拿到“从前有一个系统”,拿不到核心技术点。所以才需要按结构采样,中间部分一定要取,那是绝大多数教程文章的核心内容所在。

4.3 幻觉标签:怎么判断,怎么压下去

幻觉标签是这个项目里风险最高的一个问题,比标签泛化还危险。泛标签最多是没用,幻觉标签是错误信息。比如一篇讲“MySQL 索引优化”的文章,模型可能生成一个“数据库分库分表”标签,但正文根本没提分库分表,这就是幻觉。它在语义上跟数据库相关,模型就自动脑补了。

我压幻觉标签的措施按有效性排序是:

  • 第一,降温度。标签生成任务真不需要太多创造性,temperature = 0.2和temperature = 0.7幻觉比例差很多。
  • 第二,提示词里强约束:“标签只能基于给定文章内容,禁止反向推断。” 这一步约束效果有限,但必不可少。
  • 第三,抽样人工审核,每周从自动生成的结果里随机抽 100 篇,人工检查幻觉标签占比,持续监测模型效果是否漂移。
  • 第四,当某个标签在同一模型近期输出中反复出现且不在正文关键词列表里时,把它列入“重点抽检词表”,单独加一道规则过滤。

即使做了这么多防护,我仍建议在实际业务中不要把标签生成做成“一次性全自动”,至少要保留一个“人机协同”的校验节点。下面一节专门讲这个问题。

4.4 批量处理性能优化:并发、重试和降级

批量处理是另一个容易翻车的地方。最开始我直接遍历文章列表同步调用 API,处理 300 篇耗时约两小时,而且中途经常有请求失败。后来用concurrent.futures做了简单的并发控制,处理时间从 2 小时压缩到了 25 分钟。核心思路如下:

from concurrent.futures import ThreadPoolExecutor, as_completed def batch_generate(articles: list, max_workers: int = 5) -> dict: results = {} with ThreadPoolExecutor(max_workers=max_workers) as executor: future_map = { executor.submit(generate_article_tags_cached, art["title"], art["content"]): art["id"] for art in articles } for future in as_completed(future_map): art_id = future_map[future] try: results[art_id] = future.result() except Exception as e: results[art_id] = { "status": "failed", "error": str(e) } return results

另外两个细节值得单独强调。

重试策略:遭遇限流时,直接重试通常会失败,使用“指数退避 + 抖动”的效果好得多。

降级策略:当系统连续三次调用都超时或返回异常时,自动把整个流程降级为“仅用标题预提炼 + 规则标签抽取”,保证批处理流程不中断。宁可标签质量略低,也不能让线上流程完全卡死。

性能目标实测:并发数控制在 5 到 8,单篇延迟约 12 秒,500 篇文章可在 20 到 30 分钟内完成。如果时延要求更严,可以只用标题预提炼阶段,单篇延迟能压到 3 秒以内,只是覆盖度会有所下降。

5. 标签质量评估与人机协同落地

5.1 怎么评估自动标签好不好用

很多团队会忽略评估这一步,直接凭感觉说“效果不错”。其实标签生成是可以做量化评估的,我的评估方法分三层。

第一层,准确率。抽取 100 篇文章,每篇由两个人分别标注“正确标签数”,计算正确标签占所有生成标签的比例。准确率达到 70% 以上,我认为这个系统进入可灰度状态;超过 80%,基本可以大规模上线。这里有个经验:模型标签比人工标签更“全”但不够“准”,经常出现多个同义标签,比如同时给“Nginx”和“Nginx 配置”,评估时算 1 个正确标签而不是 2 个。

第二层,覆盖率。核心是检查正文中最核心的 3 个主题是否都能在标签里找到对应表达。这一层直接决定文章的检索和推荐能不能命中。覆盖率标准我设定为:核心主题覆盖率达到 80% 以上。

第三层,可用性。就是标签是否适合对外展示。有些标签虽然准确,但看起来像“垃圾标签”,比如“教大家一个方法”这种,属于机器生成的典型语感问题。这类标签只能靠禁词表和人工抽检逐步清理。

5.2 人机协同的编辑工作流设计

全自动生成标签不是最优解,我实践中认为正确姿势是“AI 生成初稿 + 编辑快速确认”。具体工作流如下:

  1. AI 生成标签后,在编辑的后台展示为“推荐标签”状态。
  2. 编辑可以一键采纳全部标签,也可以修改、删除、增加。
  3. 编辑确认后的标签进入正式状态,并同步回 AI 模型做在线学习参考。

这样做的好处是:编辑不用从零开始想标签,工作负担大幅降低;AI 的生成结果持续被人工修正,相当于每次人工确认都是一次免费标注。经过一段时间后,可以统计“不修改直接采纳”的比例,当这个比例超过 85%,说明 AI 生成质量足够高,此时再考虑全自动。

我最初做的时候没有加“确认”这一步,直接全自动,结果出现了一些标签与内容偏离的案例,被用户反馈之后才意识到:让专业编辑在发布环节做一层轻量把关,是在成本和质量之间最平衡的模式。

5.3 标签系统的后续扩展方向

这套“标题+正文提炼标签”的架构,后续可以很方便地扩展到几个方向。

第一个方向是自动摘要生成。标签本身就是对文章最浓缩的摘要,把标签扩展成一句完整的话,就能输出文章摘要。提示词稍做调整,让模型先提炼标签,再基于标签生成摘要,摘要质量比直接生成更好。

第二个方向是话题聚类和关联推荐。有了统一规范的标签体系之后,把相同标签的文章归并到同一个内容聚合页,直接提升专题页和推荐流的丰富度。

第三个方向是 SEO 优化。自动生成的标签可以直接用于页面关键词标签、搜索描述、站内相关推荐模块,帮内容在搜索引擎和站内搜索里都获得更好的曝光。

第四个方向是面向用户阅读体验的“内容地图”。在文章顶部展示标签后,用户扫一眼就能判断“这篇文章跟我有没有关系”,停留率和跳出率都能得到改善。

这套系统不会取代编辑,而是把编辑从“从无到有想标签”的低价值劳动中解放出来,让编辑把精力放到真正重要的选题策划和内容判断上。

我在实际项目中还有一个切身的感受:标签系统的价值,前期不在技术,而在于公司内部对“标签到底怎么定义”达成一致。这个一致不是开会能解决的,而是要让系统跑起来,让编辑看见 AI 生成的标签,再逐步修正到大家公认的标准上。这个过程大概需要一两周,但只要坚持迭代,标签生成质量会在一段时间内持续上升。最后再分享一个细节:给标签生成模块单独接一个日志系统,把每次的标题、正文采样、模型输出、最终标签、编辑修改记录全部存下来。这不仅能帮你持续优化提示词,也能在出问题时快速定位是模型的问题还是流程的问题。这套方案我已经跑了大半年,如果你正在被人工打标折磨,照着这个思路复现一套,一定省下大量时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询