实战项目二:自动摘要生成器

📂 所属阶段:第六阶段 — 工业级 NLP 项目实战
🔗 相关章节:BERT 家族详解 · Prompt Engineering 基础


1. 摘要的两大流派

1.1 抽取式 vs 生成式

抽取式摘要:
- 从原文中直接挑选关键句子组成摘要
- 不生成新词,保留原文表达
- 方法:TextRank、TF-IDF、BERT 句子排序

生成式摘要:
- 像人一样理解后重新组织语言
- 可以改写、压缩、生成新词
- 方法:T5、BART、ChatGPT

2026 年主流:
- 短文本 → 抽取式(快,成本低)
- 长文本 → 生成式(质量高、GPT-4 效果最佳)

2. 抽取式摘要(TextRank)

# extractive_summary.py
from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
import jieba

def cosine_sim(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-8)

def textrank_summary(text, top_k=3):
    """TextRank 摘要抽取"""
    sentences = [s.strip() for s in text.split("。") if len(s.strip()) > 10]

    # TF-IDF 向量化
    vectorizer = TfidfVectorizer(tokenizer=lambda x: jieba.lcut(x))
    tfidf_matrix = vectorizer.fit_transform(sentences).toarray()

    # 构建相似度矩阵
    n = len(sentences)
    similarity = np.zeros((n, n))
    for i in range(n):
        for j in range(n):
            if i != j:
                similarity[i][j] = cosine_sim(tfidf_matrix[i], tfidf_matrix[j])

    # TextRank 迭代
    scores = np.ones(n) / n
    d = 0.85
    for _ in range(50):
        new_scores = (1 - d) / n + d * similarity.T @ scores
        if np.allclose(scores, new_scores, atol=1e-5):
            break
        scores = new_scores

    # 取 top_k
    top_indices = sorted(scores.argsort()[-top_k:][::-1])
    return "。".join([sentences[i] for i in top_indices])

# 示例
text = "自然语言处理是人工智能的重要分支。它研究计算机与人类语言的交互。自然语言处理包括语音识别、文本分类、机器翻译等任务。近年来,大语言模型取得了突破性进展。BERT和GPT是代表性模型。ChatGPT在对话系统中表现出色。"
print(textrank_summary(text))
# 模型输出关键句子组成的摘要

3. BERT 抽取式摘要

# bert_extractive.py
from transformers import pipeline

# 直接使用 Hugging Face 的预训练中文摘要模型
summarizer = pipeline(
    "summarization",
    model="facebook/bart-large-cnn",  # 英文
    # 中文模型:michaelrwang/distilbart-cnn-12-6
)

def bert_summary(text, max_length=130, min_length=30):
    """BERT 抽取式摘要"""
    result = summarizer(text, max_length=max_length, min_length=min_length, do_sample=False)
    return result[0]["summary_text"]

# 示例
print(bert_summary("自然语言处理是..."))

4. ChatGPT 生成式摘要

# openai_summary.py
from openai import OpenAI

client = OpenAI(api_key="your-api-key")

def gpt_summary(text, style="简洁"):
    """用 GPT-4o 生成摘要"""
    prompt = f"""请为以下文章生成一个{style}摘要:

{text}

要求:
1. 字数控制在100字以内
2. 保留核心信息和关键数据
3. 语言简洁流畅
4. 直接输出摘要,不要解释"""
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
        max_tokens=200,
    )
    return response.choices[0].message.content

5. 评估指标:ROUGE

# rouge_score.py
def evaluate_summary(reference, hypothesis):
    """手动计算 ROUGE-1 / ROUGE-2(简化版)"""
    from collections import Counter

    def rouge_n(ref, hyp, n):
        ref_ngrams = set([tuple(ref[i:i+n]) for i in range(len(ref)-n+1)])
        hyp_ngrams = set([tuple(hyp[i:i+n]) for i in range(len(hyp)-n+1)])
        overlap = len(ref_ngrams & hyp_ngrams)
        if len(hyp_ngrams) == 0:
            return 0
        return overlap / len(hyp_ngrams)

    ref_tokens = list(reference)
    hyp_tokens = list(hypothesis)

    return {
        "rouge-1": rouge_n(ref_tokens, hyp_tokens, 1),
        "rouge-2": rouge_n(ref_tokens, hyp_tokens, 2),
    }

# 使用 rouge 库
from rouge import Rouge
rouge = Rouge()
scores = rouge.get_scores(hypothesis, reference, avg=True)
print(scores)
# {'rouge-1': {'f': 0.86, 'p': 0.90, 'r': 0.82}

6. FastAPI 摘要服务

# app.py
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI(title="摘要生成 API")

class SummarizeRequest(BaseModel):
    text: str
    method: str = "chatgpt"  # chatgpt / textrank / bert

@app.post("/summarize")
def summarize(req: SummarizeRequest):
    if req.method == "chatgpt":
        result = gpt_summary(req.text)
    elif req.method == "textrank":
        result = textrank_summary(req.text)
    else:
        result = bert_summary(req.text)
    return {"summary": result, "method": req.method}

# 部署:uvicorn app:app --host 0.0.0.0 --port 8000

7. 小结

摘要系统选择指南:

文本长度 < 500 字:
  → 抽取式(TextRank / BERT)→ 快,成本低

文本长度 500-5000 字:
  → BERT 抽取式 or T5 生成式

文本长度 > 5000 字:
  → 分段处理 + GPT-4 摘要

2026 年推荐:
- 快速原型:TextRank
- 高质量:GPT-4o / Claude
- 开源可部署:T5 / BART

💡 实践建议:实际生产中"抽取+生成"结合效果最好——先用抽取选出关键句,再用生成模型润色压缩,能显著提升摘要质量。


🔗 扩展阅读