信息过载的时代,没人有耐心把每篇文章从头读到尾。搜索引擎结果页里那两三行摘要,往往就决定了用户会不会点进你的页面;资讯类App的推送、知识库的检索预览、企业内部的文档流转,几乎处处都需要摘要能力。手工写摘要效率太低,靠截取前一百个字又常常词不达意,所以自动摘要生成成了自然语言处理领域落地最广的方向之一。这篇文章就来把文本摘要工具的技术方案讲透,并给出可以直接跑起来的代码实现。

抽取式摘要与生成式摘要:先分清两条技术路线
自动摘要从实现思路上分为两大类。抽取式摘要(Extractive Summarization)的做法是从原文中挑选出最重要的若干句子,按原顺序拼接成摘要。它不创造新句子,只做筛选,优点是生成的摘要忠实于原文、不会出现事实性错误,工程实现也相对简单;缺点是摘要可能语句之间衔接生硬,长度不太好控制。
生成式摘要(Abstractive Summarization)则类似人类写摘要的方式:模型读完原文后,用自己的语言重新组织表达,可能产生原文中没有出现过的词句。这种方式产出的摘要更流畅自然,但风险在于模型可能“编造”原文没有的信息,也就是幻觉问题,而且对训练数据和算力的要求都明显更高。
实际选型时要看场景。法律文书、医疗报告这类对准确性要求极高的领域,优先用抽取式,因为每一句摘要都能回溯到原文;资讯快讯、社交内容这类追求阅读体验的场景,生成式更合适。目前工业界很多系统采用两者结合的混合方案:先用抽取式筛出候选关键句,再交给生成式模型改写润色,兼顾准确和流畅。
基于TextRank的抽取式摘要实现
TextRank是抽取式摘要中最经典的算法之一,它的思想借鉴了PageRank:把每个句子看作图中的一个节点,如果两个句子之间的相似度超过阈值,就建立一条边,然后迭代计算每个节点的权重,最终权重最高的几个句子就是文章的核心句。这个算法不需要训练数据,纯靠图计算,对中文效果也不错,配合jieba分词可以快速落地。
下面是一段可以直接运行的Python代码,实现中文文章的自动摘要:
import jieba
import jieba.analyse
from collections import defaultdict
import numpy as np
def split_sentences(text):
# 按中文句号、问号、感叹号切分句子
sentences = [s.strip() for s in re.split('[。!?\n]', text) if s.strip()]
return sentences
def get_keywords(text, topk=10):
# 提取关键词,用于计算句子相似度
return jieba.analyse.extract_tags(text, topK=topk)
def text_rank_summary(text, top_n=3):
sentences = split_sentences(text)
n = len(sentences)
if n <= top_n:
return text
# 对每个句子分词并去掉停用词
words = [set(jieba.cut(s)) for s in sentences]
# 构建句子相似度矩阵
sim = np.zeros((n, n))
for i in range(n):
for j in range(i + 1, n):
common = len(words[i] & words[j])
if common > 0:
score = common / (np.log(len(words[i]) + 1) + np.log(len(words[j]) + 1))
sim[i][j] = score
sim[j][i] = score
# 迭代计算TextRank权重
damping, iters = 0.85, 100
rank = np.ones(n) / n
for _ in range(iters):
new_rank = (1 - damping) / n + damping * sim.sum(axis=1) / n * rank.sum()
rank = new_rank / new_rank.sum()
# 取权重最高的句子,按原文顺序输出
top_idx = sorted(np.argsort(rank)[-top_n:])
return ''.join([sentences[i] for i in top_idx])
text = "你的长文本内容放这里。可以是新闻、博客或者报告全文。"
print(text_rank_summary(text, top_n=3))
这段代码的核心逻辑分三步:切句、构建相似度矩阵、迭代计算权重。其中相似度计算用的是词共现的简化版公式,实际工程中可以换成TF-IDF加权或者word2vec向量余弦相似度,效果会更好。gensim库内置了summarization模块(新版本已独立为gensim-summarizer包),调用起来更省事,两行代码就能得到摘要结果,适合快速验证。
基于预训练模型的生成式摘要方案
如果对摘要的流畅度要求较高,就要上生成式模型了。中文场景下常用的选择包括mT5、PEGASUS的中文版本,以及近两年大火的大语言模型。用Hugging Face的transformers库调用这类模型非常方便:
from transformers import pipeline
# 加载中文摘要模型
summarizer = pipeline(
"summarization",
model="csebuetnlp/mT5_multilingual_XLSum"
)
article = "这里放入需要摘要的长文本,建议不超过两千字。"
result = summarizer(article, max_length=150, min_length=40, do_sample=False)
print(result[0]['summary_text'])
需要注意几个实践细节。第一,模型有最大输入长度限制,通常是512或1024个token,超长文本要做截断或者分段摘要再合并,分段摘要时最好用层级策略:先对每段分别生成摘要,再把各段摘要拼起来做一次二次摘要。第二,max_length和min_length参数直接决定摘要长度,要根据业务需求调。第三,如果直接调用ChatGPT、通义千问这类大模型API,提示词的写法很关键,明确要求“只基于原文概括,不要添加原文没有的信息”,可以显著降低幻觉率。
摘要质量评估与常见坑点
摘要做得好不好需要量化评估。学术界最常用的是ROUGE指标,包括ROUGE-1、ROUGE-2和ROUGE-L,分别衡量摘要与人工参考摘要在一元词组、二元词组和最长公共子序列上的重合度。如果你想在自己的数据上对比不同工具的效果,可以用rouge-score这个库快速计算。不过ROUGE只看字面重合,对生成式摘要偏保守,人工评估仍然是不可替代的一环。
落地过程中有几个高频坑。一是长文本问题,很多工具对输入长度有隐性限制,超长就直接截断,导致摘要只覆盖了文章开头;二是中文分词质量,抽取式方案对分词错误很敏感,领域文本建议加载自定义词典;三是多主题文章的摘要偏向,TextRank这类算法容易被高频主题带偏,如果文章前半部分反复出现某个词,后半部分的重要内容可能被忽略,解决办法是先做主题分段再分别摘要。把这些细节处理好,一个稳定可用的自动摘要工具基本就成型了。