By Sagar Shankaran, Founder of CallSphere
Learn how coreference resolution enables AI agents to track pronouns and references across conversation turns, with practical implementations using spaCy, neural models, and LLM-based approaches.
Key takeaways
Consider this conversation with an AI agent:
Who is "she"? A human immediately knows it refers to Dr. Martinez. But an agent processing messages independently sees only the word "she" with no link to the doctor mentioned two turns earlier. Coreference resolution is the NLP task that connects pronouns, definite descriptions, and other referring expressions to their antecedents.
Without coreference resolution, agents misinterpret follow-up questions, lose track of entities across turns, and produce confused responses. It is one of the most underappreciated capabilities in conversational AI.
A coreference chain is a set of mentions in a text that all refer to the same real-world entity. In the sentence "Alice said she would bring her laptop," the chain is: [Alice, she, her] — all three refer to the same person.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>next action"])
INPUT --> PARSE --> PLAN --> AGENT --> GUARD
GUARD -->|Pass| EXEC --> OUT
GUARD -->|Fail| AGENT
AGENT --> OBS
style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
Types of referring expressions that coreference systems must handle:
The coreferee library adds coreference resolution to spaCy pipelines.
import spacy
nlp = spacy.load("en_core_web_trf")
nlp.add_pipe("coreferee")
def resolve_coreferences(text: str) -> dict:
"""Identify coreference chains in text."""
doc = nlp(text)
chains = []
if doc._.coref_chains:
for chain in doc._.coref_chains:
mentions = []
for mention in chain:
span_tokens = [doc[i] for i in mention]
mention_text = " ".join(t.text for t in span_tokens)
start_idx = span_tokens[0].idx
mentions.append({
"text": mention_text,
"start": start_idx,
})
chains.append(mentions)
return {"text": text, "chains": chains}
text = "Sarah called the restaurant. She asked if they had a table for two."
result = resolve_coreferences(text)
# chains: [['Sarah', 'She'], ['the restaurant', 'they']]
For production agents, LLMs provide the most flexible coreference resolution, especially across conversation turns.
import openai
def resolve_with_llm(conversation: list[dict]) -> str:
"""Resolve pronouns in the latest message using conversation context."""
messages = [
{
"role": "system",
"content": """Rewrite the last user message by replacing all
pronouns and references with the specific entities they refer to.
Use the conversation history for context.
Return ONLY the rewritten message, nothing else.""",
}
]
messages.extend(conversation)
response = openai.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
temperature=0,
)
return response.choices[0].message.content
conversation = [
{"role": "user", "content": "I need help with my order from TechCorp."},
{"role": "assistant", "content": "I can help with that. What is the issue?"},
{"role": "user", "content": "They shipped it to the wrong address."},
]
resolved = resolve_with_llm(conversation)
# "TechCorp shipped my order to the wrong address."
A robust agent maintains an entity registry that tracks all mentioned entities and resolves references against them.
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class Entity:
name: str
entity_type: str
aliases: list[str] = field(default_factory=list)
last_mentioned_turn: int = 0
class ConversationContextTracker:
def __init__(self):
self.entities: list[Entity] = []
self.turn_count = 0
def register_entity(self, name: str, entity_type: str):
"""Add a new entity to the registry."""
for entity in self.entities:
if entity.name.lower() == name.lower():
entity.last_mentioned_turn = self.turn_count
return
self.entities.append(Entity(
name=name,
entity_type=entity_type,
last_mentioned_turn=self.turn_count,
))
def resolve_pronoun(self, pronoun: str) -> Optional[str]:
"""Resolve a pronoun to the most recently mentioned matching entity."""
pronoun_map = {
"he": "PERSON", "him": "PERSON", "his": "PERSON",
"she": "PERSON", "her": "PERSON", "hers": "PERSON",
"it": "THING", "its": "THING",
"they": "ORG", "them": "ORG", "their": "ORG",
}
target_type = pronoun_map.get(pronoun.lower())
if not target_type:
return None
candidates = [
e for e in self.entities
if e.entity_type == target_type
]
if not candidates:
return None
# Return the most recently mentioned entity
return max(candidates, key=lambda e: e.last_mentioned_turn).name
def advance_turn(self):
self.turn_count += 1
The complete pattern preprocesses each user message before the agent's main reasoning loop.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
class CoreferencePreprocessor:
def __init__(self, nlp_pipeline, context_tracker):
self.nlp = nlp_pipeline
self.tracker = context_tracker
def process_message(self, message: str) -> str:
"""Resolve references and update entity registry."""
self.tracker.advance_turn()
doc = self.nlp(message)
# Register new entities found via NER
for ent in doc.ents:
self.tracker.register_entity(ent.text, ent.label_)
# Replace pronouns with resolved entities
resolved = message
for token in reversed(list(doc)):
if token.pos_ == "PRON":
entity_name = self.tracker.resolve_pronoun(token.text)
if entity_name:
resolved = (
resolved[:token.idx]
+ entity_name
+ resolved[token.idx + len(token.text):]
)
return resolved
By resolving coreferences before the agent processes the message, you ensure that tool calls, database queries, and API requests use explicit entity names rather than ambiguous pronouns.
State-of-the-art neural coreference models achieve around 80-85% F1 score on benchmark datasets like OntoNotes. LLM-based resolution using GPT-4 class models tends to perform better in conversational contexts, reaching 90%+ accuracy for common pronoun patterns. However, complex cases involving nested references, cataphora (forward references), or ambiguous gender still challenge all systems.
Maintain a sliding window of the most recently mentioned entities rather than tracking the entire conversation history. Entities mentioned more recently are more likely to be referents. A window of 5 to 10 turns covers the vast majority of coreference patterns in natural conversation. For entities that persist across the entire conversation (like the user's name), promote them to a "pinned" status in your tracker.
Resolve coreferences before intent classification. If a user says "Cancel it," the intent classifier needs to know what "it" refers to in order to route correctly. Is it a subscription cancellation, an order cancellation, or an appointment cancellation? Resolving the pronoun first produces "Cancel the subscription," which the intent classifier can handle accurately.
#CoreferenceResolution #NLP #Anaphora #ContextTracking #AIAgents #Python #AgenticAI #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
A founder's guide to the personal AI assistant market: best AI assistant apps, business-grade options, and how CallSphere's voice agent fits in.
A founder's guide to free AI agents, low-code AI agent builders, and how to know when you should pay for a real platform like CallSphere.
Graphiti is the open-source temporal knowledge graph for AI agents in 2026. Learn how bi-temporal memory beats vector RAG for voice agents and long-running LLMs.
Chatbot app vs ChatGPT in 2026: a founder's clear take on the difference, when to use which, and how a real AI chatbot app development works.
How we built a fault-tolerant HVAC emergency triage and tech-dispatch platform on Kubernetes — three-tier CQRS, 11 micro-agents on the OpenAI Agents SDK + LangGraph, NATS JetStream, DTMF/SMS/WebSocket acceptance, circuit breakers, and an evaluation pipeline that catches regressions before they wake a tech at 3 AM.
Head-to-head: OpenAI Frontier and Anthropic's managed agent stack — strengths, fit, and what each means for enterprise AI voice and chat deployment.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI