ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GPT Researcher Detailed Report 深度解析:基于 STORM 架构的长篇研究报告生成机制

GPT Researcher Detailed Report 深度解析:基于 STORM 架构的长篇研究报告生成机制 GPT Researcher Detailed Report 深度解析基于 STORM 架构的长篇研究报告生成机制【免费下载链接】gpt-researcherAn autonomous agent that conducts deep research on any data using any LLM providers项目地址: https://gitcode.com/GitHub_Trending/gp/gpt-researcher导读本文围绕 gpt-researcher 项目中的 Detailed Report详细报告报告类型深入讲解其如何借鉴 STORM 论文的「先规划、再分主题撰写、最后汇总」思想突破单次 LLM 上下文窗口限制生成带目录、章节完整且内容不重复的长篇研究报告。你将掌握DetailedReport类从初始研究、子主题生成、去重撰写到最终组装的完整调用链并了解它在服务端WebSocket中如何被路由触发、如何与 MCP 及max_search_results等参数协同工作。一、背景为什么需要 Detailed Report标准的 research_report 一次生成一篇报告受限于 LLM 上下文窗口面对复杂主题时往往只能给出概要性结论难以覆盖多个子维度。gpt-researcher 的 Detailed Report 采用了一种完全不同的架构——其设计灵感来自 2024 年发表的 STORM 论文关于 LLM 驱动的知识密集型长文写作系统核心思路是将复杂主题拆解为多个子主题subtopics对每个子主题独立开展研究并撰写小节跨小节跟踪已撰写内容避免信息重复最终拼装为「引言 目录 各小节正文 结论」的完整长报告。该报告类型在代码中的正式标识为detailed_report定义于 gpt_researcher/utils/enum.py 的ReportType枚举DetailedReport: In-depth detailed analysis report. DetailedReport detailed_report二、核心架构六大步骤的完整流水线backend/report_type/detailed_report/README.md明确了 Detailed Report 的六步工作流这也是理解整套机制的主线触发初始研究报告基于用户任务task运行一次标准的 GPT Researcher 研究报告作为全局研究基础从研究摘要生成子主题由初始研究总结出若干子主题提取并累积子主题报告的标题为每个子主题生成草稿章节标题并累积逐个生成子主题报告撰写每个子主题时确保已累积的标题信息不被重复生成去重机制编写引言与目录额外生成引言段落并根据整篇报告内容构建目录Table of Contents组装最终报告按照「引言 目录 各子主题报告」的顺序拼接成最终文档。这套流程在源码中对应 backend/report_type/detailed_report/detailed_report.py 的DetailedReport.run()async def run(self) - str: await self._initial_research() subtopics await self._get_all_subtopics() report_introduction await self.gpt_researcher.write_introduction() _, report_body await self._generate_subtopic_reports(subtopics) self.gpt_researcher.visited_urls.update(self.global_urls) report await self._construct_detailed_report(report_introduction, report_body) return report可以看到run()本身就是六步流程的编排器先做初始研究再取子主题、写引言、生成子主题正文最后组装含结论与参考文献。三、DetailedReport 类源码解析3.1 构造参数与内部状态DetailedReport.__init__接收的构造参数detailed_report.py参数类型说明querystr主研究问题report_typestr报告类型传入即detailed_reportreport_sourcestr报告信息来源如web_searchsource_urlslist初始来源 URL 列表document_urlslist附加文档 URLquery_domainslist限定搜索的域名config_pathstr配置文件路径toneAny报告语气对应Tone枚举如Tone.FORMALwebsocketWebSocket用于实时推送日志/进度的 WebSocketsubtopicslist预定义子主题可选headersdictHTTP 请求头complement_source_urlsbool是否补充来源 URLmcp_configs-MCP 服务器配置可选mcp_strategy-MCP 调用策略可选max_search_resultsint每次搜索的最大结果数覆盖值构造时还会生成唯一研究 ID格式为detailed_{timestamp}_{query的MD5前8位}def _generate_research_id(self, query: str) - str: timestamp str(int(time.time())) query_hash hashlib.md5(query.encode()).hexdigest()[:8] return fdetailed_{timestamp}_{query_hash}同时DetailedReport内部通过GPTResearcher(**gpt_researcher_params)初始化一个主研究实例并将report_type强制固定为research_report主研究阶段使用普通研究报告。若传入了max_search_results会直接覆盖主实例的cfg.max_search_results_per_query。类内部维护三个跨子主题的关键状态这是去重机制的基础self.existing_headers: List[Dict]记录每个子主题已生成的标题self.global_context: List[str]全局研究上下文随各子主题研究不断累积self.global_written_sections: List[str]全局已撰写章节内容供后续子主题规避重复。3.2 初始研究与子主题生成_initial_research()调用self.gpt_researcher.conduct_research()完成第一轮研究并把context与visited_urls保存到全局状态。_get_all_subtopics()调用gpt_researcher.get_subtopics()对应 agent.py从中提取subtopics.subtopics列表每个子主题被归一化为{task: subtopic.task}结构若返回格式异常则会打印告警信息。3.3 子主题研究报告的生成_generate_subtopic_reports()遍历所有子主题逐个调用_get_subtopic_report()并把成功的子主题报告以\n\n\n分隔符拼接成subtopics_report_body。_get_subtopic_report()是 Detailed Report 的灵魂其流程为创建子主题研究实例为当前子主题新建一个GPTResearcherreport_type固定为subtopic_report同时把主研究的agent、role、tone、visited_urls、parent_query、subtopics传入确保子主题研究与主线保持一致subtopic_assistant GPTResearcher( querycurrent_subtopic_task, report_typesubtopic_report, ... parent_queryself.query, subtopicsself.subtopics, visited_urlsself.global_urls, agentself.gpt_researcher.agent, roleself.gpt_researcher.role, toneself.tone, ... )传播配置mcp_configs/mcp_strategy会被显式传给子主题实例源码注释明确说明「Propagate MCP configuration so follow-up researchers can use MCP」max_search_results同样会覆盖到子主题实例的cfg.max_search_results_per_query。注入全局上下文将主研究的global_context同时兼容字符串与 MCP 返回的 dict 两种元素格式见_hashable_context()去重后赋给子主题实例。子主题研究执行subtopic_assistant.conduct_research()。生成草稿标题调用get_draft_section_titles()获取该子主题的草稿章节标题再经extract_headers()解析出标题文本列表。去重查询调用get_similar_written_contents_by_draft_section_titles()用当前子主题的草稿标题去匹配global_written_sections中已写过的内容找出「相似已写内容」。撰写子主题报告write_report(existing_headers..., relevant_written_contents...)在撰写时同时传入历史标题与相关已写内容从而让 LLM 在生成时主动规避重复。更新全局状态把本次子主题报告的章节extract_sections追加进global_written_sections更新global_context与global_urls并把{subtopic task: ..., headers: ...}追加进existing_headers。值得注意的细节_hashable_context()专门处理了 MCP 上下文dict 形式与普通字符串上下文并存的情况将 dict 规范化为Title: ...\nContent: ...文本后再做set()去重避免对 dict 直接求 hash 报错。3.4 最终报告组装_construct_detailed_report()完成收尾detailed_report.py用table_of_contents(report_body)从正文字段中自动提取目录调用write_report_conclusion(report_body)生成结论通过add_references(conclusion, visited_urls)为结论追加参考文献最终拼接为introduction toc report_body conclusion_with_references。主研究实例在run()中还执行了self.gpt_researcher.visited_urls.update(self.global_urls)把各子主题访问过的 URL 合并回主实例确保参考文献完整。源码注释同时指出图片已在conduct_research()阶段预生成、并在write_report()阶段嵌入因此子主题撰写阶段无需重复生成图片。四、如何使用 Detailed Report4.1 编程方式调用docs/docs/examples/detailed_report.md给出了直接在 Python 中调用DetailedReport的示例。结合当前仓库构造参数如下import asyncio from fastapi import WebSocket from gpt_researcher.utils.enum import Tone from backend.report_type import DetailedReport async def generate_report(websocket: WebSocket): detailed_report DetailedReport( queryThe impact of artificial intelligence on modern healthcare, report_typedetailed_report, report_sourceweb_search, source_urls[], # 可传入初始来源 URL config_pathpath/to/config.yaml, toneTone.FORMAL, # 报告语气 websocketwebsocket, # 实时日志通道 subtopics[], # 可预定义子主题 headers{} # 附加 HTTP 请求头 ) final_report await detailed_report.run() return final_report # 在 FastAPI 中通过 WebSocket 暴露 app.websocket(/generate_report) async def websocket_endpoint(websocket: WebSocket): await websocket.accept() report await generate_report(websocket) await websocket.send_text(report)DetailedReport从 backend/report_type/init.py 导出from .detailed_report.detailed_report import DetailedReport与BasicReport并列。4.2 通过服务端触发在前端发起研究请求时将报告类型指定为detailed_report后端 backend/server/websocket_manager.py 会按ReportType.DetailedReport.value分支实例化DetailedReportelif report_type ReportType.DetailedReport.value: researcher DetailedReport( querytask, query_domainsquery_domains, report_typereport_type, report_sourcereport_source, source_urlssource_urls, document_urlsdocument_urls, tonetone, config_pathconfig_path, websocketlogs_handler, # 使用日志处理器而非原始 WebSocket headersheaders, mcp_configsmcp_configs if mcp_enabled else None, mcp_strategymcp_strategy if mcp_enabled else None, max_search_resultsmax_search_results, ) report await researcher.run()从这段代码可以看出三个工程细节日志处理器传入的是logs_handler而非原始 WebSocket用于统一封装日志推送MCP 可选只有mcp_enabled为真时才传入mcp_configs/mcp_strategy且采用每请求配置方式避免污染全局环境变量源码注释引用了 issue #1676 关于os.environ跨会话污染的教训参数覆盖max_search_results可在服务端层面直接传入进而下推给主研究实例与所有子主题研究实例。4.3 与 BasicReport 的对比同目录的 backend/report_type/basic_report/basic_report.py 展示了标准模式的实现其run()极为精简async def run(self): await self.gpt_researcher.conduct_research() report await self.gpt_researcher.write_report() return report对比可见BasicReport是「一次研究、一次撰写」的单轮模式适合主题相对聚焦、篇幅适中的报告DetailedReport则是「研究 → 拆解 → 多轮子研究 → 去重撰写 → 组装」的多轮模式适合需要长文、多维度覆盖的复杂主题代价是更多的 LLM 调用与更长的生成时间。五、关键机制与工程细节5.1 防冗余设计去重核心Detailed Report 去重的完整闭环依赖三个工具方法与两个状态容器extract_headers(markdown_text)agent.py从 Markdown 中提取各级标题extract_sections(markdown_text)agent.py提取 Markdown 章节内容table_of_contents(markdown_text)agent.py构建目录get_draft_section_titles()/get_similar_written_contents_by_draft_section_titles()agent.py前者生成草稿标题后者匹配已写内容。工作逻辑是每个子主题撰写前先产出自己的草稿标题 → 与global_written_sections比对找出相似已写内容 → 把「历史标题 相似已写内容」一并注入write_report()的提示词中 → 撰写后再将新章节与标题回写全局状态。这样后续子主题就知道「哪些内容已经写过」避免在不同小节中重复表述同一信息。5.2 MCP 与上下文规范化MCP 场景下子主题研究返回的上下文可能是 dict如{title: ..., body: ...}而普通研究上下文是字符串。_hashable_context()负责把两者统一转成字符串后去重否则set()会因 dict 不可哈希而抛异常。这也说明 Detailed Report 对 MCP 数据源有完整的向下兼容处理。5.3 参考文献与图片最终报告通过add_references()基于主实例合并后的visited_urls生成参考文献保证长报告中每个小节引用过的来源都能汇总到文末。图片在conduct_research()阶段即已预生成、在write_report()阶段嵌入子主题报告所以最终组装时无需再处理图片逻辑这也降低了长报告组装阶段出错的可能性。六、适用场景与使用建议Detailed Report 适合以下场景需要长篇幅、多章节的研究报告如行业分析、政策综述、技术全景调研主题天然存在多个子维度一次生成容易遗漏或浅尝辄止对结构完整性有要求最终产物自带引言、目录、正文与结论参考文献。使用时建议注意report_source、query_domains、source_urls等约束会同时作用于主研究与所有子主题研究可在构造时统一限定若希望每次搜索获取更多结果可通过max_search_results覆盖默认的max_search_results_per_query该值会级联传播到每个子主题实例预定义subtopics可以让拆解阶段更可控适合对主题已有清晰框架的场景由于多轮研究意味着更多 token 消耗与更长的运行时间生产环境建议配合 WebSocket 实时日志观察进度日志中会输出 MCP 初始化、mcp_init 等事件。七、小结Detailed Report 是 gpt-researcher 中面向「深度长文」的核心报告类型它把 STORM 论文中「分解写作 迭代精化」的思想落地为一个六步流水线通过DetailedReport类统一编排主研究、子主题研究、去重撰写与最终组装。无论是作为库直接调用还是通过后端 WebSocket 服务以detailed_report报告类型触发它都能在保持信息不重复的前提下生成结构完整、来源可溯的长篇研究报告。其核心实现集中在 backend/report_type/detailed_report/detailed_report.py配合 gpt_researcher/agent.py 中的标题提取、目录构建与去重匹配工具构成了完整的工程闭环。【免费下载链接】gpt-researcherAn autonomous agent that conducts deep research on any data using any LLM providers项目地址: https://gitcode.com/GitHub_Trending/gp/gpt-researcher创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表