Multi-Stage Story Generation with Validation
The generation architecture used in [[denote:20251019T134950][the drama project]]: progressively refine stories through validated stages.
Pipeline Stages
Context → Sketch → Spec → Full Text
↓ ↓ ↓
Validate Validate Validate
↓ ↓ ↓
Pass/Iterate Pass/Iterate Pass/Done
Stage 1: Sketch
Input: Premise, constraints, requirements Output: High-level story structure
Contains: - Brief premise - Character list with roles - Dramatic arcs (hamartia, peripeteia, anagnorisis per character) - Key story events - Narrative structure type
Tests: Structural, Aristotelian unity, character arcs
Size: ~100-500 tokens
Stage 2: Spec
Input: Validated sketch Output: Detailed scene breakdown
Contains: - Expanded character descriptions - Scene-by-scene breakdown - Beat-level narrative units - Dialogue sketches - Proppian functions mapped
Tests: Propp morphology, Todorov sequences, POV consistency
Size: ~1000-3000 tokens
Stage 3: Full Text
Input: Validated spec Output: Complete prose story
Contains: - Full prose narrative - Polished dialogue - Sensory details - Atmosphere and pacing
Tests: LLM judge quality, narrative consistency, completeness
Size: ~5000-15000 tokens (short story)
Why Multi-Stage?
1. Incremental Validation
Catch structural problems early (in sketch) rather than after generating 10,000 words.
2. Different Strategies Per Stage
- Sketch: Fast, broad exploration (high temperature)
- Spec: Systematic, constrained (medium temperature)
- Full Text: Polished, detailed (lower temperature)
Each stage can use different: - LLMs (cheap for sketch, expensive for full text) - Prompting strategies (basic → iterative → constrained) - Validation rigor (loose → strict)
3. Caching and Reuse
Generate sketch once, try multiple spec variations. Generate spec once, try multiple prose styles for full text.
4. Human-in-the-Loop
Review/edit sketch before committing to full generation.
5. Traceability
Full lineage: sketch_id → spec_id → full_story_id Know exactly where each element came from.
Generation Strategies
Basic
Single LLM call with prompt. Simple, fast, limited control.
Iterative
Generate → Test → Fix Issues → Test Again
Loop until all tests pass or max iterations reached.
Constrained
Use grammar/format constraints to enforce structure during generation.
Multi-Agent
Different agents collaborate: - Plotter: Designs overall structure - Character Designer: Creates character arcs - Writer: Generates prose - Validator: Runs tests - Refiner: Fixes issues
Validation Across Stages
Sketch: Structural + Aristotelian Spec: + Propp + Todorov Full Text: + LLM judge + consistency checks
Tests accumulate. Full text must pass ALL tests from all stages.
Caching Strategy
Cache key = hash(generator_type + config + context + constraints)
Benefits: - Don’t regenerate identical requests - Faster experimentation - Cost reduction (LLM calls expensive)
Database Tracking
Every stage stored:
- story_versions table (sketch, spec, full)
- generation_attempts (all LLM calls, even failed ones)
- test_results (all validation results)
- lineage (parent-child relationships)
Enables analysis: - Which generators work best for which constraints? - Which tests fail most often? - What’s the distribution of iteration counts?
Example Flow
# Start with context
context = GenerationContext(
stage="sketch",
metadata={"premise": "A mysterious dinner party"},
constraints=["6 characters", "single location", "3-hour timeframe"],
)
# Generate sketch
sketch_gen = SketchGenerator(config={"model": "gpt-oss-120b"})
sketch_version = await sketch_gen.generate(context)
# Validate sketch
validators = [
SketchStructureValidator(),
AristotelianUnityValidator(),
PeripeteiaValidator(),
]
results = [await v.validate(sketch_version) for v in validators]
if all(r.passed for r in results):
# Move to spec stage
context.sketch = sketch_version.content
context.stage = "spec"
spec_gen = SpecGenerator()
# ... continue
else:
# Iterate sketch
# Use test feedback to refine
pass
Related Notes
- [[denote:20251019T134950]] - Drama Project
- Narrative Theory as Code - Narrative Theory as Code
Status: Seedling | Created: 2025-10-19