BookParser (Multi-Agent Narrative Intelligence)

Role: Solo, end-to-end
Tech Stack: Python 3.12, Anthropic API, Pydantic, AsyncIO
Repository: Private

Overview

BookParser is an ETL pipeline that turns novels into structured knowledge graphs.

Unlike standard “Chat with PDF” tools that rely on transient context, BookParser builds a persistent “World Bible” tracking character states, inventory changes, and location graphs across hundreds of pages. It uses a multi-agent architecture to maintain narrative continuity and catch hallucinated data before it hits the database.

System Architecture

The system follows a Hierarchical Agent Pattern where a central Coordinator manages state and delegates tasks to specialized sub-agents.

graph TD
    A[Input: Raw Text/EPUB] --> B(Scene Splitter Agent)
    B --> C{Coordinator Service}

    subgraph "Parallel Extraction Layer"
    C --> D[Character Agent]
    C --> E[Setting Agent]
    C --> F[Item/Inventory Agent]
    end

    D & E & F --> G[Entity Resolution Service]
    G --> H[Global State Tracker]
    H --> C

    C --> I[Validation Gates]
    I --> J[Final JSON Output]

Components

Engineering Details

1. Cost Optimization via Model Cascading

Running frontier models on every paragraph was prohibitively expensive and slow. So I implemented a consolidated extraction strategy.

2. Context Window Management (“RAG-Lite”)

Passing the entire history of the book to the model for every scene saturates the context and confuses the model. So I developed a build_filtered_context() method.

3. Data Integrity & Self-Healing

LLMs are probabilistic, they occasionally return malformed JSON or invent IDs (the_huntingrounds vs hunting_grounds). That kind of hallucination is exactly what my QA background trained me to paranoid-proof against, so I built a strict Validator class.

Code Snippet: The Validation Logic

Ensuring agent-generated IDs strictly match the canonical registry.

def validate_entity_ids(self, entities: List[Dict], registry: Dict) -> bool:
    """
    Acts as a circuit breaker. If an Agent invents a new ID
    that hasn't been registered, the batch is flagged for review.
    """
    validation_passed = True
    for entity in entities:
        canonical_id = self._generate_id(entity['name'])
        if canonical_id not in registry:
            logger.warning(f"Hallucination detected: {canonical_id}")
            validation_passed = False
    return validation_passed

Sample Output

The system produces rich, flat JSON ready for frontend visualization.

{
  "scene_id": 3,
  "location": "third_floor_hallway",
  "characters_present": ["carl", "donut", "mordecai"],
  "inventory_changes": [
    {
      "item_id": "holographic_sign",
      "action": "USED",
      "description": "A magical sign showing directional arrows."
    }
  ]
}

Tech Stack