The strict chronological order of LM calls when STORM processes one topic. Captured from a code walkthrough on 2026-06-02.
┌─ STAGE 1: Knowledge Curation ─────────────────────────────────────────┐
1. FindRelatedTopic(topic)
→ returns ~5 Wikipedia URLs for related subjects
→ [non-LM]: HTTP fetch each URL, BeautifulSoup-parse the TOC
2. GenPersona(topic, related_TOCs)
→ returns N personas as a numbered list
→ [non-LM]: prepend hardcoded "Basic fact writer" → final list of N+1 personas
──── then for EACH persona (run in parallel via thread pool) ────
REPEAT max_conv_turn times:
3. AskQuestionWithPersona(topic, persona, conv_history_so_far)
↑ (falls back to AskQuestion if persona is empty)
→ returns the next question this persona wants to ask the "expert"
→ break early if question is "" or starts with "Thank you so much..."
4. QuestionToQuery(topic, question)
→ returns ~3 search queries
→ [non-LM]: retriever.fetch(queries) → web snippets
5. AnswerQuestion(topic, question, snippets)
→ returns expert's answer (with citation markers)
→ append (question, answer, queries, results) to conv_history
└──────────────────────────────────────────────────────────────────────┘
┌─ STAGE 2: Outline Generation ─────────────────────────────────────────┐
6. WritePageOutline(topic)
→ returns draft outline from parametric knowledge alone
→ SAVED as direct_gen_outline.txt
7. WritePageOutlineFromConv(topic, old_outline=draft, conv=all_transcripts)
→ returns refined outline using the conversations
→ SAVED as storm_gen_outline.txt
└──────────────────────────────────────────────────────────────────────┘
┌─ STAGE 3: Article Generation ─────────────────────────────────────────┐
──── for EACH top-level section in storm_gen_outline (parallel) ────
[non-LM]: ConvToSection — gather conversation turns relevant to this section
8. WriteSection(topic, section_outline, relevant_snippets)
→ returns section text with [n]-style citations
──── assemble all sections in outline order → storm_gen_article.txt ────
└──────────────────────────────────────────────────────────────────────┘
┌─ STAGE 4: Article Polishing ──────────────────────────────────────────┐
9. WriteLeadSection(topic, full_article)
→ returns the summary paragraph that goes at the top
10. PolishPage(full_article_with_lead)
→ optional dedupe pass over the whole article
→ SAVED as storm_gen_article_polished.txt
└──────────────────────────────────────────────────────────────────────┘
Run config: max_perspective=2 → 3 personas total (default + 2), max_conv_turn=2.
| Prompt | Times fired | Why |
|---|---|---|
FindRelatedTopic | 1 | once per topic |
GenPersona | 1 | once per topic |
AskQuestionWithPersona | 6 | 3 personas × 2 turns |
QuestionToQuery | 6 | one per turn |
AnswerQuestion | 6 | one per turn |
WritePageOutline | 1 | the draft |
WritePageOutlineFromConv | 1 | the refinement |
WriteSection | ~10 | one per top-level section of the outline |
WriteLeadSection | 1 | summary |
PolishPage | 1 | dedupe |
| Total | ~34 | matches the log of our actual run |
AskQuestion is the bare fallback when no persona is supplied; STORM's main path always supplies a persona, so in practice you only see AskQuestionWithPersona in real runs. That's why the inventory lists 11 prompts but only 10 fire in any given run.
max_thread_num), so the wall-clock order is interleaved. But within a single persona's thread, the turn-loop is strictly sequential: AskQuestion → QuestionToQuery → AnswerQuestion → next turn.
Source: stanford-storm/storm/knowledge_storm/storm_wiki/modules/ — see knowledge_curation.py, persona_generator.py, outline_generation.py, article_generation.py, article_polish.py.