| name | comorag-cognitive-memory-rag |
| title | ComoRAG: Cognitive Memory-Organized RAG for Long Narrative Reasoning |
| version | 0.0.2 |
| engine | skillxiv-v0.0.2-claude-opus-4.6 |
| license | MIT |
| url | https://arxiv.org/abs/2508.10419 |
| keywords | ["retrieval-augmented-generation","long-context","narrative-reasoning","memory-workspace","iterative-reasoning"] |
| description | Iteratively retrieve and reason over long narratives using a dynamic memory workspace that integrates retrieved facts into a shared context for complex multi-hop reasoning. |
ComoRAG: Cognitive Memory-Organized RAG for Long Narrative Reasoning
Core Concept
Traditional RAG systems retrieve relevant passages once and generate answers. For long narratives (200K+ tokens), this fails because complex questions require tracking entities, relationships, and events across the entire text. Readers build mental models of stories by revisiting information.
ComoRAG mimics human narrative comprehension through iterative reasoning with a dynamic memory workspace. Each iteration generates exploratory queries, retrieves supporting evidence, and integrates findings into a growing memory structure. This multi-hop approach handles questions requiring global narrative understanding.
Architecture Overview
- Dynamic Memory Workspace: Evolving context that accumulates relevant facts from iterations
- Exploratory Query Generation: Create diverse queries to discover different narrative aspects
- Iterative Retrieval: Retrieve evidence repeatedly, refining understanding with each cycle
- Memory Integration: Incorporate retrieved facts into shared workspace to build comprehensive narrative model
- Reasoning Cycles: Multiple passes over narrative with different focus areas
- Long-Context Handling: Designed for 200K+ token narratives with complex plot structures
Implementation Steps
1. Initialize Memory Workspace
Create a dynamic memory structure that accumulates information across reasoning cycles.
from collections import defaultdict
import json
class MemoryWorkspace:
"""
Dynamic memory workspace for narrative reasoning
Stores entities, relationships, events discovered during reasoning
"""
def __init__(self, max_memory_size=10000):
self.max_memory_size = max_memory_size
self.entities = {}
self.relationships = []
self.events = []
self.facts = []
self.memory_tokens = 0
def add_entity(self, entity_name, entity_type='PERSON'):
"""Register an entity in memory"""
entity_id = len(self.entities)
self.entities[entity_id] = {
'name': entity_name,
'type': entity_type,
'mentions': [],
'properties': {}
}
return entity_id
def add_relationship(self, entity_id1, relation, entity_id2):
"""Add a relationship between entities"""
self.relationships.append({
: entity_id1,
: relation,
: entity_id2
})
():
.events.append({
: time_point,
: action,
: participants,
: location
})
():
.facts.append({
: fact_text,
: evidence_span,
: confidence,
: (.facts)
})
.memory_tokens += (fact_text.split())
():
context =
.entities:
context +=
entity_id, entity .entities.items():
context +=
.relationships:
context +=
rel .relationships[:]:
e1 = .entities[rel[]][]
e2 = .entities[rel[]][]
context +=
.events:
context +=
event .events[:]:
context +=
context +=
.facts:
context +=
fact .facts[-:]:
context +=
context[:max_tokens]
():
entity iteration_results.get(, []):
entity[] [e[] e .entities.values()]:
.add_entity(entity[], entity.get(, ))
rel iteration_results.get(, []):
.add_relationship(rel[], rel[], rel[])
event iteration_results.get(, []):
.add_event(event[], event[], event[])
fact iteration_results.get(, []):
.add_fact(fact[], fact[])
2. Implement Exploratory Query Generation
Generate diverse queries to explore different aspects of the narrative.
class ExploratoryQueryGenerator:
"""
Generate exploratory queries for iterative retrieval
"""
def __init__(self, llm_model):
self.llm = llm_model
self.query_templates = [
"What are the main characters and their relationships?",
"What are the key events in chronological order?",
"What conflicts or tensions exist between characters?",
"What is the motivation for each character's actions?",
"What are the major plot twists or surprises?",
"How do settings change throughout the narrative?",
"What consequences follow from key decisions?",
"What themes or lessons emerge from the story?"
]
def generate_exploration_queries(self, question, memory_workspace, iteration=0):
"""
Generate queries tailored to exploring aspects relevant to the question
"""
if iteration == 0:
queries = [
f"What is directly relevant to: {question}?"
] + self.query_templates[:3]
else:
memory_context = memory_workspace.get_memory_context()
prompt = f"""Based on this memory workspace and the original question,
what additional aspects should we explore?
Original Question: {question}
Current Memory:
{memory_context}
Generate 3 specific exploratory queries to fill gaps in understanding.
Focus on information NOT yet in memory."""
response = .llm.generate(prompt, max_length=)
queries = ._parse_queries(response)
queries
():
re
query_pattern =
queries = re.findall(query_pattern, response_text)
queries[:]
3. Implement Iterative Retrieval
Retrieve evidence based on exploratory queries.
from typing import List
class IterativeRetriever:
"""
Retrieve evidence iteratively, updating based on memory state
"""
def __init__(self, corpus_embedder, vectorstore):
self.embedder = corpus_embedder
self.vectorstore = vectorstore
def retrieve_for_queries(self, queries: List[str], narrative_doc: str,
memory_workspace=None, k=3):
"""
Retrieve evidence for each query
"""
retrieved_passages = []
for query in queries:
if memory_workspace:
contextualized_query = self._contextualize_query(
query, memory_workspace
)
else:
contextualized_query = query
query_embedding = self.embedder.encode(contextualized_query)
passages = self.vectorstore.search(
query_embedding,
k=k,
narrative_id=None
)
for passage in passages:
retrieved_passages.append({
'query': query,
'passage': passage['text'],
'span': passage['span'],
'relevance': passage[]
})
retrieved_passages
():
memory_context = memory_workspace.get_memory_context(max_tokens=)
contextualized =
contextualized
4. Extract and Integrate New Information
Parse retrieved passages to extract structured information.
class InformationExtractor:
"""
Extract entities, relationships, and facts from retrieved passages
"""
def __init__(self, llm_model):
self.llm = llm_model
def extract_from_passage(self, passage):
"""
Extract structured information from a passage
"""
prompt = f"""Extract the following from this narrative passage:
- Named entities (persons, places, things)
- Relationships between entities
- Events and their participants
- Key facts
Passage:
{passage}
Return as JSON with keys: entities, relationships, events, facts"""
response = self.llm.generate(prompt, max_length=300)
extracted = self._parse_json_response(response)
return extracted
def _parse_json_response(self, response_text):
"""Parse JSON from LLM response"""
import json
try:
return json.loads(response_text)
except:
import re
json_match = re.search(r'\{.*\}', response_text, re.DOTALL)
if json_match:
try:
return json.loads(json_match.group())
except:
return {
'entities': [],
'relationships': [],
: [],
: []
}
:
{
: [],
: [],
: [],
: []
}
5. Main Iterative Reasoning Loop
Implement the core iterative reasoning cycles.
class ComoRAGReasoner:
"""
Main ComoRAG reasoning loop
"""
def __init__(self, llm_model, corpus_embedder, vectorstore):
self.llm = llm_model
self.query_generator = ExploratoryQueryGenerator(llm_model)
self.retriever = IterativeRetriever(corpus_embedder, vectorstore)
self.extractor = InformationExtractor(llm_model)
self.memory = MemoryWorkspace()
def reason_over_narrative(self, question, narrative_doc, num_iterations=3):
"""
Iteratively reason over narrative to answer question
"""
print(f"Question: {question}\n")
for iteration in range(num_iterations):
print(f"=== Iteration {iteration + 1} ===")
queries = self.query_generator.generate_exploration_queries(
question, self.memory, iteration
)
print(f"Queries: {queries}")
retrieved = self.retriever.retrieve_for_queries(
queries, narrative_doc, self.memory, k=3
)
print(f"Retrieved {len(retrieved)} passages")
iteration_info = {
: [],
: [],
: [],
: []
}
item retrieved:
extracted = .extractor.extract_from_passage(item[])
iteration_info[].extend(extracted.get(, []))
iteration_info[].extend(
extracted.get(, [])
)
iteration_info[].extend(extracted.get(, []))
iteration_info[].extend(extracted.get(, []))
.memory.merge_with_iteration_memory(iteration_info)
(
)
final_answer = ._generate_answer(question)
final_answer
():
memory_context = .memory.get_memory_context()
prompt =
answer = .llm.generate(prompt, max_length=)
answer
6. Integration and Usage
Use ComoRAG for long-narrative question-answering.
def answer_long_narrative_question(narrative_doc, question, num_iterations=3):
"""
Answer questions about long narratives using ComoRAG
"""
llm = load_llm_model("gpt-4-turbo")
embedder = load_embedder("all-MiniLM-L6-v2")
vectorstore = build_vectorstore(narrative_doc)
reasoner = ComoRAGReasoner(llm, embedder, vectorstore)
answer = reasoner.reason_over_narrative(
question,
narrative_doc,
num_iterations=num_iterations
)
return answer
narrative = "..."
question = "What is the relationship between Character A and Character B?"
answer = answer_long_narrative_question(narrative, question, num_iterations=3)
print(f"Answer: {answer}")
Practical Guidance
Hyperparameters & Configuration
- Iterations: 2-4 (more = better understanding but slower)
- Retrieval k: 2-5 passages per query (3 is good balance)
- Memory Size: 2000-5000 tokens (grow dynamically)
- Query Count: 2-3 per iteration (more queries = better coverage)
- Entity Tracking: Keep top 20-50 entities in workspace
When to Use ComoRAG
- Documents are long (> 50K tokens) with complex narratives
- Questions require multi-hop reasoning across narrative
- You need to track entities and relationships over long spans
- Traditional single-pass RAG fails on complex questions
- You can afford multiple retrieval and reasoning passes
When NOT to Use ComoRAG
- Documents are short (< 10K tokens) — standard RAG sufficient
- Questions are simple fact-lookups (no multi-hop needed)
- Latency is critical (iterative approach is slower)
- Computational resources are very limited
- You need real-time answers (multi-iteration takes time)
Common Pitfalls
- Too Many Iterations: Diminishing returns after 3-4 iterations. More doesn't always help.
- Poor Query Generation: If exploratory queries aren't diverse, memory updates are redundant. Vary query templates.
- Memory Explosion: Track memory size; prune less-relevant facts if it grows too large.
- Retrieval Collapse: If all iterations retrieve the same passages, change retrieval strategy (e.g., add diversity).
- No Baseline Comparison: Always compare against standard RAG to ensure iterative approach helps.
Reference
ComoRAG (2508.10419): https://arxiv.org/abs/2508.10419
Iteratively retrieve and reason over long narratives using a cognitive memory workspace, achieving 11% improvements on 200K+ token narrative reasoning benchmarks through multi-hop exploration and fact integration.