Two fundamentally different mechanisms hide behind one task name, and the difference matters enormously in a regulated setting.
Extractive summarisation selects sentences from the original and returns them verbatim. It cannot invent anything, because every word came from the source. Abstractive summarisation generates new text, which reads far better and can state things the document never said.
For anything that touches a customer file or a regulator, that distinction is the whole decision.
Model families 4
Sub-categories within this task. The distinction that
matters is not which is best, but which fits your constraints.
Extractive
Tiny to none.
Use when
Faithfulness is non-negotiable. Nothing can be hallucinated because nothing is generated.
Avoid when
You need it to read well. Output is choppy and repetitive.
Best quality, and you can steer format and focus by instruction — 'summarise only the fee dispute, in three bullets, quoting amounts exactly'.
Avoid when
High volume, or you cannot put a verification step in front of the output.
Examples
Any instruct LLM
In a bank 4
The third line in each is the part that makes it
harder than the textbook version.
Call and chat summaries into the CRM
Agents finish an interaction and a summary is written to the customer record automatically.
The wrinkleThat record is discoverable and may be produced in a dispute. A hallucinated 'customer agreed to the charge' is a serious problem. Most implementations keep the summary as a draft the agent must confirm, which also creates the accountability trail.
Credit memo and committee pack drafting
Condense financials, covenants and analyst commentary into a standard memo format.
The wrinkleNumbers must be exact. The practical pattern is to extract figures deterministically and let the model write only the prose around them — never let it restate a number.
Regulatory change summaries
Consultation papers and rule changes summarised for the business lines they affect.
The wrinkleOmission is as damaging as invention. Extractive or heavily grounded approaches are safer, and a subject expert reviews before circulation.
Complaint case summaries for review queues
Long complaint threads condensed so a reviewer can triage quickly.
The wrinkleLower stakes because a human reads the original next. This is the best place to start with abstractive summarisation.
Code 3
Named functions and the arguments that actually
change the outcome. Comments flag the traps.
Abstractive, with the arguments that matter
max_length is in tokens, not words, and it silently truncates the input rather than warning you.
from transformers import pipeline
summ = pipeline("summarization", model="facebook/bart-large-cnn")
out = summ(long_text,
max_length=130, # OUTPUT length cap, in tokens
min_length=40, # stops it returning one short sentence
do_sample=False, # deterministic: same input, same output.
# Essential if you need reproducibility.
truncation=True)
print(out[0]["summary_text"])
# BART's encoder caps at 1024 tokens. Anything past that is DISCARDED
# without an error. Check before you trust the result:
tok = summ.tokenizer
n = len(tok(long_text)["input_ids"])
if n > 1024:
print(f"WARNING: {n} tokens in, {n - 1024} silently dropped")
Extractive, when nothing may be invented
Every sentence returned is byte-identical to one in the source, so faithfulness is guaranteed structurally rather than hoped for.
from sumy.parsers.plaintext import PlaintextParser
from sumy.nlp.tokenizers import Tokenizer
from sumy.summarizers.text_rank import TextRankSummarizer
parser = PlaintextParser.from_string(long_text, Tokenizer("english"))
sentences = TextRankSummarizer()(parser.document, 5)
for s in sentences:
assert str(s) in long_text # holds by construction
print("-", s)
Checking for hallucination
A cheap, imperfect guard: every number in the summary should appear in the source. Catches the most damaging class of error.
import re
def unsupported_numbers(summary, source):
"""Numbers in the summary that never appeared in the source."""
num = lambda t: set(re.findall(r"\d[\d,]*\.?\d*", t))
return num(summary) - num(source)
bad = unsupported_numbers(summary, long_text)
if bad:
print("REJECT - invented figures:", bad)
# For a stronger check, run an NLI model over each summary sentence
# against the source and flag anything not entailed.
from transformers import pipeline
nli = pipeline("text-classification",
model="microsoft/deberta-large-mnli")
for sent in summary.split(". "):
r = nli(f"{long_text[:1500]} [SEP] {sent}")[0]
if r["label"] != "ENTAILMENT":
print("unsupported:", sent)
What catches people out 3
ROUGE does not measure correctness
It counts n-gram overlap with a reference summary. A summary can score well and still state the opposite of the source. For any regulated use you need factual consistency checks, not just ROUGE.
Input truncation is silent
Feed 4,000 tokens to a 1,024-token model and it summarises the first quarter without complaint. Since documents often put conclusions at the end, this fails in exactly the way that matters. Always measure input length.
Chunk-and-combine changes the failure mode
The usual fix for long documents — summarise chunks, then summarise the summaries — loses cross-chunk relationships and compounds any error from the first pass. Prefer a long-context model where you can.