A two-LLM workflow for iterative story generation and improvement using a writer model and a critic model.
FictionRefine orchestrates a collaborative workflow between two language models:
- Writer/Reviser (Model A): Generates initial stories and applies revisions
- Critic/Verifier (Model B): Reviews stories and provides detailed feedback
The system iteratively improves stories through cycles of writing, reviewing, revising, and verification until the story meets quality thresholds.
- Comprehensive Critique: Multi-dimensional story evaluation (plot, character, setting, dialogue, mechanics)
- Iterative Improvement: Automated revision cycles with measurable quality improvements
- Flexible Configuration: YAML-based story configuration and model parameters
- Robust Pipeline: Handles model failures, validates outputs, and prevents story collapse
- Rich Output: Detailed artifacts for every step, enabling debugging and analysis
pip install fictionrefinegit clone https://github.com/davealaw/fictionrefine
cd fictionrefine
pip install -e ".[dev]"- Python 3.9+
- LM Studio
- Two language models (writer and critic)
-
Start LM Studio and load two models:
- Model A (writer): e.g.,
qwen/qwen3-30b-a3b-2507 - Model B (critic): e.g.,
gpt-oss-120b
- Model A (writer): e.g.,
-
Run a basic story generation:
fictionrefine \\
--model-a "qwen/qwen3-30b-a3b-2507" \\
--model-b "gpt-oss-120b" \\
--story-config examples/story-config.yaml \\
--outdir runs/my_first_story- Check the results:
cat runs/my_first_story/story_published_clean.txtCreate YAML files to define story parameters:
story:
target_words: 1500
setting: "a haunted lighthouse during a fierce storm"
protagonist: "Mara, an elderly keeper who fears the sea"
conflict: "the lighthouse lamp fails as ships approach"
theme: "confronting one's deepest fears"See examples/ directory for more examples.
fictionrefine --helpKey parameters:
--model-a,--model-b: Model names in LM Studio--story-config: Story configuration file--max-cycles: Number of revision cycles (default: 1)--critic-temperature: Creativity level for critic model (default: 0.5)--context-length: Context window size (default: 32768)
- WRITE: Model A generates a tagged story based on constraints
- REVIEW: Model B provides comprehensive critique with specific suggestions
- REVISE: Model A applies fixes and improvements
- VERIFY: Model B validates changes and scores improvements
- GATE: Accept if quality threshold met, otherwise iterate
- PUBLISH: Output clean, human-readable story
Each run creates a timestamped directory with:
story_published_clean.txt: Final storystep1_write_raw.txt: Initial story draftstep2_review.json: Detailed critiquestep3_revise.json: Applied revisionsstep4_verify.json: Quality verificationrun_summary.json: Overall metrics
- Creative models: Qwen, Llama, Mistral variants
- Temperature: 0.6-0.8 for creativity
- Best for: Narrative generation, creative writing
- Analytical models: GPT variants, Claude alternatives
- Temperature: 0.3-0.6 for consistency
- Best for: Detailed analysis, objective critique
- Short stories (600-800 words): 8192 tokens
- Medium stories (1200-2000 words): 32768 tokens
- Long stories (3000+ words): 65536 tokens
Set context length in LM Studio when loading models.
git clone https://github.com/davealaw/fictionrefine
cd fictionrefine
pip install -e ".[dev]"
pre-commit installpytestblack src/ tests/
ruff src/ tests/
mypy src/- Fork the repository
- Create a feature branch
- Make changes with tests
- Run quality checks
- Submit a pull request
MIT License - see LICENSE file.
If you use FictionRefine in research or production, please cite:
@software{fictionrefine,
title = {FictionRefine: Two-LLM Collaborative Story Generation},
author = {Dave Law},
year = {2025},
url = {https://github.com/davealaw/fictionrefine}
}