跳到主要内容

04 · 工程精华、边界与代码地图

这一章是“带走的精华”:STORM 里那些不显然但很实用的小设计;它刻意不做什么、会在哪崩;以及完整的代码跳转地图。

1. 巧妙之处(可借鉴的技术)

1.1 引用编号的“局部→全局”统一与越界裁剪

妙在哪: 每个章节是并行写的,LLM 只看到本节资料的局部编号 [1][2];但全文需要一套统一编号,而且 LLM 经常会引用不存在的编号。STORM 用一个占位符两步替换法既统一编号、又不会“替串”。

update_citation_index(utils.py:540-550)先把所有旧编号换成 __PLACEHOLDER_n__,再把占位符换成新编号——避免“把 [1] 换成 [10] 时又被后续规则误伤”:

# 示意,源码精简自 utils.py:540-550
for original in citation_map: # 第一遍:全换成占位符
s = s.replace(f"[{original}]", f"__PLACEHOLDER_{original}__")
for original, unify in citation_map.items(): # 第二遍:占位符→新编号
s = s.replace(f"__PLACEHOLDER_{original}__", f"[{unify}]")

配合 update_section(storm_dataclass.py:249-299):它先正则抓出本节用到的引用号,把超过资料条数的越界引用直接删掉(max_ref_num > len(info_list) 时清除),再只保留真正被引用的资料并重映射编号。最后 reorder_reference_index(storm_dataclass.py:374-412)按引用在全文出现顺序重排成 1,2,3…,并删掉没被引用的参考。

1.2 砍掉被 token 上限截断的“半截句”

妙在哪: LLM 输出常因 max_tokens 在句子中间断掉,留下半句脏话。remove_uncompleted_sentences_with_citations(utils.py:367-425)用正则找最后一个“句末标点(可带引用)”,只保留到那里。顺手还把 [1, 2, 3] 拆成 [1][2][3] 并去重排序,统一引用风格。

1.3 取材用嵌入相似度,不是全量塞

妙在哪: 资料可能很多,全塞进 prompt 又贵又超窗。StormInformationTable.retrieve_information(storm_dataclass.py:119-145)对每个章节查询,用 SentenceTransformer 编码后算 cosine 相似度取 top-k,再按 URL 聚合 snippet返回。Co-STORM 的信息归位也用同一招做候选排序(information_insertion_module.py:149-163)。

1.4 一切皆 dspy.Signature:prompt 即“带类型的函数签名”

妙在哪: STORM 的每个 LLM 调用都写成一个 dspy.Signature 子类(如 AskQuestionWithPersonaWriteSectionInsertInformation),docstring 是指令、InputField/OutputField 是输入输出。好处是 prompt 集中、可读、可被 dspy 优化器调。with dspy.settings.context(lm=...) 在不同步骤切换不同模型;多处 show_guidelines=False 是为了“对不同 LLM 家族更鲁棒”(见 article_polish.py:88-89 的注释)。

1.5 用命名约定做自动统计

妙在哪: LMConfigsif "_lm" in attr_name 反射式地遍历所有以 _lm 结尾的属性来统计 token 用量、收集调用历史(interface.py:443-482);Retriever 同理用 _rm 后缀统计查询数。新增一个模型只要按约定命名即可被自动纳入统计。

2. 边界与局限(诚实)

  • 不是成品文章。 作者明说产出“需要大量编辑才能发表”,定位是写作前的调研辅助(README.md Overview)。
  • 专家“只取每条结果的第一个 snippet”。 TopicExpert.forward 注释直言“Simplify this part by directly using the top 1 snippet”(knowledge_curation.py:218-221)——为省成本牺牲了召回深度。
  • 强英文偏向 + 安全过滤偏保守。 demo 用的 user_input_appropriateness_check(utils.py:714-768)会拒绝非英文输入、个人经历类、以及“要求执行计算/编程”的非研究类请求,且硬编码用 azure/gpt-4o-mini 当判官——作者也承认会有误杀(prompt 里反复道歉)。
  • Co-STORM from_dict 不恢复 LM 配置。 代码里有 FIXME: does not use the lm_config data but naively use default setting(engine.py:556-558)——反序列化会丢失自定义模型配置。
  • 引言/结论被流水线“吃掉”。 成文阶段显式跳过 introduction/conclusion/summary 章节(article_generation.py:96-103),开篇综述完全交给润色阶段的 lead;如果润色没跑,文章就没有像样的开头。
  • 不做多跳引用。 Retriever.retrieve 注释说明会先 remove_citations 清掉来源里的引用,“STORM 不考虑多跳引用”(interface.py:300-305)。

3. 横向对比(同 shelf 的不同取舍)

STORM 属于 ai-frontier-reference 的 rag-context / academic 区。和常见 RAG / agent 写作方案相比,它的特异取舍:

维度STORM 的做法常见 RAG 写作的做法
怎么决定“查什么”多视角模拟对话逼出深问题直接对 query 检索
信息组织STORM 用扁平信息表;Co-STORM 用LLM 导航的思维导图向量库 + top-k
多 agent 协调Co-STORM 有显式轮次策略 + 主持人多为固定流程或简单 ReAct
模型抽象dspy Signature + litellm,每阶段可换模型多直接拼 prompt 字符串
人的角色Co-STORM 让人实时插话引导多为一问一答

Co-STORM 的“思维导图作为人机共享概念空间”和“主持人用未被使用的信息开新话题”,是它相对一般多 agent 讨论框架的两个鲜明增量。

4. 代码地图(导航索引)

主题文件路径关键符号
STORM-Wiki 流水线入口knowledge_storm/storm_wiki/engine.pySTORMWikiRunner.runrun_knowledge_curation_moduleSTORMWikiLMConfigs
抽象接口/数据类knowledge_storm/interface.pyEngineKnowledgeCurationModuleArticleInformationRetrieverLMConfigs
知识采集(模拟对话)knowledge_storm/storm_wiki/modules/knowledge_curation.pyConvSimulatorWikiWriterTopicExpertAskQuestionWithPersonaAnswerQuestion
视角生成knowledge_storm/storm_wiki/modules/persona_generator.pyStormPersonaGenerator.generate_personaCreateWriterWithPersonaget_wiki_page_title_and_tocGenPersona
大纲生成knowledge_storm/storm_wiki/modules/outline_generation.pyWriteOutline.forwardWritePageOutlineWritePageOutlineFromConv
分节成文knowledge_storm/storm_wiki/modules/article_generation.pyStormArticleGenerationModule.generate_articleConvToSectionWriteSection
润色knowledge_storm/storm_wiki/modules/article_polish.pyStormArticlePolishingModule.polish_articlePolishPageModuleWriteLeadSectionPolishPage
STORM 数据类/信息表knowledge_storm/storm_wiki/modules/storm_dataclass.pyStormInformationTable.retrieve_informationStormArticle.update_sectionreorder_reference_index
Co-STORM 引擎/轮次策略knowledge_storm/collaborative_storm/engine.pyCoStormRunner.stepDiscourseManager.get_next_turn_policyTurnPolicySpecwarm_start
Co-STORM agentsknowledge_storm/collaborative_storm/modules/co_storm_agents.pyCoStormExpertModeratorSimulatedUserPureRAGAgent
思维导图(知识库)knowledge_storm/dataclass.pyKnowledgeBase.reorganizeKnowledgeBase.insert_informationKnowledgeNodeConversationTurn
信息归位/节点扩展knowledge_storm/collaborative_storm/modules/information_insertion_module.pyInsertInformationModule.layer_by_layer_navigation_placementExpandNodeModule._expand_nodeInsertInformation
接地式问答knowledge_storm/collaborative_storm/modules/grounded_question_answering.pyAnswerQuestionModule.forwardQuestionToQueryAnswerQuestion
文本处理工具knowledge_storm/utils.pyArticleTextProcessing.update_citation_indexremove_uncompleted_sentences_with_citationsclean_up_outlineuser_input_appropriateness_check
检索层 / 模型层knowledge_storm/rm.py / knowledge_storm/lm.pyBingSearch 等 RM、LitellmModel

5. 相关阅读