Coreference Resolution
"She called him. He did not answer. The doctor was at lunch." Three references, two people, nobody named. Coreference resolution's only job is figuring out who is who.
Learning Objectives
- Explain what coreference resolution solves and why skipping it causes an NER pipeline to miss 60-80% of the mentions it should catch.
- Identify the four mention types (named entity, nominal, pronominal, appositive) and the five architectures used to resolve them, from Hobbs's 1978 rule-based method to 2024+ generative LLM prompting.
- Build a rule-based pronoun resolver that scores candidate antecedents by gender/number agreement, recency, and syntactic role.
- Evaluate a coreference system with CoNLL F1 (the average of MUC, B³, and CEAF-φ4) and pick an approach, rule-based, neural span-based, LLM-prompted, or hybrid, for a given single-document, multilingual, or cross-document use case.
The Problem
Pull every mention of Apple Inc. out of a 300-word article. Easy when the text just says "Apple." Much harder when it says "the company," "they," "Cupertino's technology giant," or "Jobs's firm." Skip the step that ties those back to one entity and your NER pipeline quietly misses 60-80% of the mentions it should have caught.
Coreference resolution is that step: link every expression that points at the same real-world entity into one cluster. It sits between surface-level NLP (NER, parsing) and the semantics downstream tasks actually need (IE, QA, summarization, KG).
It shows up everywhere in 2026 production systems:
- Summarization: "The CEO announced..." vs "Tim Cook announced..." (the summary should name the CEO).
- Question answering: "Who did she call?" means resolving "she."
- Information extraction: a knowledge graph with "PER1 founded Apple" and "Jobs founded Apple" as separate entries is wrong.
- Multi-document IE: merging mentions across articles about the same event is cross-document coreference.
The Concept
The task. Feed in a document, get back a clustering of mentions (spans of text) where every cluster names one real-world entity.
Mention types. A mention shows up in one of four shapes:
- Named entity. "Tim Cook"
- Nominal. "the CEO", "the company"
- Pronominal. "he", "she", "they", "it"
- Appositive. "Tim Cook, Apple's CEO,"
Architectures. Five approaches, roughly in the order the field adopted them:
- Rule-based (Hobbs, 1978). Syntactic-tree pronoun resolution driven by grammar rules. A solid baseline that's surprisingly hard to beat on pronouns specifically.
- Mention-pair classifier. Predicts, for every pair of mentions (m_i, m_j), whether they corefer, then clusters by transitive closure. The standard approach before 2016.
- Mention-ranking. For each mention, ranks candidate antecedents (including "no antecedent") and picks the top one.
- Span-based end-to-end (Lee et al., 2017). A transformer encoder enumerates every candidate span up to a length cap, scores which spans are mentions, scores antecedent probability for each one, then clusters greedily. This is the modern default.
- Generative (2024+). Prompt an LLM directly: "List every pronoun in this text and its antecedent." Works well on easy cases; struggles on long documents and rare referents.
The evaluation metrics. No single metric captures clustering quality on its own, so the field reports five (MUC, B³, CEAF, BLANC, LEA), each scoring the same clusters a little differently, and averages the first three into a score called CoNLL F1. 2026 state of the art on CoNLL-2012 sits around 83 F1.
Known hard cases.
- Definite descriptions that refer back to entities introduced pages earlier.
- Bridging anaphora ("the wheels" pointing at a car mentioned earlier).
- Zero anaphora in languages like Chinese and Japanese, where the referent is never stated at all.
- Cataphora, where the pronoun lands before its referent: "When she walked in, Mary smiled."
Build It
Step 1: pretrained neural coreference (AllenNLP / spaCy-experimental)
Start here: a pretrained model gets you real clusters in five lines, no training required.
import spacy
nlp = spacy.load("en_coreference_web_trf") # experimental model
doc = nlp("Apple announced new products. The company said they would ship soon.")
for cluster in doc._.coref_clusters:
print(cluster, "->", [m.text for m in cluster])On a longer document, expect something like:
- Cluster 1: [Apple, The company, they]
- Cluster 2: [new products]
Step 2: rule-based pronoun resolver (teaching)
code/main.py has a stdlib-only implementation that runs in three passes:
- Extract mentions: named entities (capitalized spans), pronouns (dict lookup), definite descriptions ("the X").
- For each pronoun, look at the previous K mentions and score them by:
- gender/number agreement (heuristic)
- recency (closer wins)
- syntactic role (subjects preferred)
- Link the highest-scoring antecedent.
It won't compete with a neural model, but it makes the decision space visible: every call an end-to-end model has to make, spelled out as an explicit rule.
Step 3: using LLMs for coreference
No model to stand up at all: prompt an LLM directly and parse structured output back out.
prompt = f"""Text: {text}
List every pronoun and noun phrase that refers to a person or company.
Cluster them by what they refer to. Output JSON:
[{{"entity": "Apple", "mentions": ["Apple", "the company", "it"]}}, ...]
"""Watch for two failure modes here. LLMs over-merge, folding "him" and "her" into one person when they're actually two distinct people, and they silently drop mentions once a document runs long. Verify both with span-offset checks instead of trusting the output at face value.
Step 4: evaluation
The standard CoNLL-2012 script computes MUC, B³, and CEAF-φ4, then reports the average. For an in-house eval, start with span-level precision and recall against your annotated test set, then add mention-linking F1.
Pitfalls
- Singleton explosion. Some systems report every mention as its own cluster. B³ scores that leniently, but MUC punishes it, so check all three metrics before trusting one number.
- Pronouns in long context. Performance drops roughly 15 F1 on documents over 2,000 tokens. Chunk carefully rather than feeding in the whole thing at once.
- Gender assumptions. Hard-coded gender rules break on non-binary referents, organizations, and animals. Use learned models or neutral scoring instead.
- LLM drift on long docs. A single API call can't reliably cluster mentions across 50+ paragraphs. Use a sliding window and merge the results.
Use It
Here's the 2026 stack, situation by situation:
| Situation | Pick |
|---|---|
| English, single document | en_coreference_web_trf (spaCy-experimental) or AllenNLP neural coref |
| Multilingual | SpanBERT / XLM-R trained on OntoNotes or Multilingual CoNLL |
| Cross-document event coref | Specialized end-to-end models (2025–26 SOTA) |
| Quick LLM baseline | GPT-4o / Claude with structured-output coref prompt |
| Production dialog systems | Rule-based fallback + neural primary + manual review for critical slots |
The integration pattern that actually ships in 2026 is simple: run NER first, run coref second, then merge the coref clusters back into the NER entities. Downstream tasks see one entity per cluster instead of one entity per surface mention.
Ship It
This lesson ships outputs/skill-coref-picker.md, a skill that makes the same three calls every time instead of re-deriving them per project:
---
name: coref-picker
description: Pick a coreference approach, evaluation plan, and integration strategy.
version: 1.0.0
phase: 5
lesson: 24
tags: [nlp, coref, information-extraction]
---
Given a use case (single-doc / multi-doc, domain, language), output:
1. Approach. Rule-based / neural span-based / LLM-prompted / hybrid. One-sentence reason.
2. Model. Named checkpoint if neural.
3. Integration. Order of operations: tokenize → NER → coref → downstream task.
4. Evaluation. CoNLL F1 (MUC + B³ + CEAF-φ4 average) on held-out set + manual cluster review on 20 documents.
Refuse LLM-only coref for documents over 2,000 tokens without sliding-window merge. Refuse any pipeline that runs coref without a mention-level precision-recall report. Flag gender-heuristic systems deployed in demographically diverse text.Connections
Coreference resolution is a bridge step: it sits between Phase 5's surface-level NLP (NER, POS tagging, parsing) and the semantic tasks that need entities resolved, not just tagged.
| Concept | Where it connects |
|---|---|
| NER (Phase 5 · 06) | Coref runs directly downstream: tag entities first, then merge mentions via coref clusters so one entity isn't counted as several. |
| Entity Linking (Phase 5 · 25) | Once mentions are clustered, entity linking maps the whole cluster to one real-world ID instead of resolving each mention separately. |
| Relation Extraction & Knowledge Graphs (Phase 5 · 26) | A KG built without coref records "PER1 founded Apple" and "Jobs founded Apple" as two facts about two different people. Coref is what collapses them into one. |
| Chunking for RAG (Phase 5 · 23) | A chunk that says "the company" instead of "Apple" is a chunk a retriever can miss; coreference-aware indexing works around the same gap that motivates contextual retrieval. |
| Question Answering (Phase 5 · 13) | "Who did she call?" has no answer until "she" resolves to a name. |
| Summarization (Phase 5 · 12) | A good summary names the entity instead of echoing whatever pronoun the source text happened to be using at that point. |
Everywhere downstream NLP needs to know who or what a piece of text is actually about, coreference is the step that answers it.
The instinct the first time you hit this problem is to reach straight for the fanciest span-based model on the leaderboard. Resist it. Run the rule-based resolver in code/main.py against your actual documents first. Most of the coreference bugs I've chased down in production weren't model failures at all: a definite description the tokenizer split across two spans, an appositive the NER pass never flagged as a mention in the first place. A rule-based baseline and a handful of print statements surface those in an afternoon. Skip straight to fine-tuning a transformer and you'll spend a week debugging a model that was never the problem.
One more thing worth saying directly: don't ship gender heuristics into anything customer-facing. It isn't only a fairness issue, it's a correctness one. The heuristic misfires on organizations and non-human referents just as often as it misfires on people, so "it usually works" isn't a real defense.
Exercises
- Easy. Run the rule-based resolver in
code/main.pyon 5 hand-crafted paragraphs. Measure mention-link accuracy against ground truth. - Medium. Use a pretrained neural coref model on a news article. Compare clusters against your own manual annotation. Where did it fail?
- Hard. Build a coref-enhanced NER pipeline: NER first, then merge via coref clusters. Measure entity-coverage improvement vs NER-only on 100 articles.
Key Terms
| Term | What people say | What it actually means |
|---|---|---|
| Mention | A reference | A span of text that refers to an entity (name, pronoun, noun phrase). |
| Antecedent | What "it" refers to | The earlier mention a later one corefers with. |
| Cluster | The entity's mentions | Set of mentions that all refer to the same real-world entity. |
| Anaphora | Backward reference | Later mention refers to earlier ("he" → "John"). |
| Cataphora | Forward reference | Earlier mention refers to later ("When he arrived, John..."). |
| Bridging | Implicit reference | "I bought a car. The wheels were bad." (wheels of THAT car.) |
| CoNLL F1 | The number on leaderboards | Average of MUC, B³, CEAF-φ4 F1 scores. |
Further Reading
- Jurafsky & Martin, SLP3 Ch. 26: Coreference Resolution and Entity Linking: canonical textbook chapter.
- Lee et al. (2017). End-to-end Neural Coreference Resolution: span-based end-to-end.
- Joshi et al. (2020). SpanBERT: pretraining that improves coref.
- Pradhan et al. (2012). CoNLL-2012 Shared Task: the benchmark.
- Hobbs (1978). Resolving Pronoun References: the rule-based classic.
Code
- main.py (python, 166 lines)