FEATURED · 精选文章

OpenResearch:开源大模型研究代理,打造自动化信息调研管线

发布时间 / 2026/9/20 3:50:13
来源 / 创域科博编辑部
栏目 / 资讯中心
OpenResearch:开源大模型研究代理,打造自动化信息调研管线 今年上半年我被一个任务折腾得够呛老板轻描淡写丢来一句“研究一下xxx”然后我一整个下午都在浏览器标签页里打转。搜索、打开、扫一眼、发现不相关、关闭、再搜索最后赶出一份两页汇报还得小心翼翼地附上来源链接。这种活儿干多了之后我的想法很简单与其每次都手动重复“搜、读、筛、写”不如把它做成一套自动化研究管线。于是就有了OpenResearch这个项目。OpenResearch是一套完全开源的大模型研究代理research agent。它不是那种你问一句、它答一句的聊天机器人而是一个能自己拆解研究问题、多路搜索来源、阅读原文、抽取证据最终生成带可靠引用研究报告的编排系统。简单说它把“做案头调研”这件事拆成了机器可执行的工作流而我只需要在最后做审核和润色。这篇文章会把整个项目的设计思路、核心实现、踩坑记录都摊开讲。如果你正在做信息密集型的调研工作——技术选型、竞品分析、学术文献综述、行业报告——而且受够了“复制粘贴然后忘记出处”的流水线那这个项目应该对你有参考价值。文章里包含大量可直接照抄的关键模块代码和参数设计从零开始搭一套最小可用版本大概需要半天时间后续再逐步升级成完整平台。1. 先说清楚OpenResearch做的不是“问答”是“研究”很多人第一次看到这类项目会有一个误解这不就是给大模型接一个搜索引擎吗不是。问答和研究的本质区别在于问答是一次性获取已封装好的信息而研究是一个多轮、多源、带验证的决策过程。我要在一篇三千字的报告里写“某方案成本更低”那我必须知道是谁在什么场景下发现了这件事这个结论是否可迁移到我当前的约束条件下。这背后涉及的信息检索、交叉验证、置信度权衡恰恰是最适合程序化但最难做好的部分。1.1 让AI替代研究员的真正难点决策远比生成重要我最早用普通对话式大模型做调研时遇到几个过不去的坎信息时效性差。训练数据有截止日期很多实时变化的价格、版本、市场数据它根本不知道。没有真正的阅读过程。模型只能基于记忆回答不会因为我说“请再查一下官网的文档”而真正打开官网。引用不可靠。它可能会给出看起来像模像样的出处最后却发现是编的。无法自主拆解问题。一个“XX行业现在怎么样了”的问题研究员会主动拆成市场规模、主要玩家、技术趋势、监管风险但对话式AI只会给你一个平均化的笼统回答。所以我把OpenResearch设计成一个自主决策循环不是一次prompt调用。系统内部有一个调度器负责把主问题分解为子问题调度检索器去获取材料再让大模型逐段阅读并抽取证据最后统一合成报告并验证引用链。整个过程可视化为一个流水线研究请求 - 任务规划器(Planner) - 多路检索器(Retriever) - 证据抽取器(Extractor) - 证据存储(Memory/Knowledge Graph) - 报告合成器(Writer) - 引用验证器(Verifier) - 最终报告这中间每一步都在和外部工具或模型交互任何一个环节掉链子最后报告的质量都会受影响。这也是这个项目最有意思的地方——它更像是在搭一个自动化系统而不是在写一个prompt。1.2 为什么不直接用现成的商业研究工具我对照过市面上的几类方案方案优点缺点手动浏览器调研质量可控时间消耗大、难以并行多个话题对话式AI问答响应快时效性差、引用不可靠、问题拆解弱商业研究助手功能全、体验好价格高、封闭生态、无法深度定制内部流程OpenResearch自建方案开源可控、可插拔组件、透明可审计需要自己维护和调试我选择自建的核心原因有两个一是透明性我能看到每个结论是哪个来源支撑的而不是黑盒输出二是可定制我可以把公司内部的文档库、特定行业数据库都接进去商业产品很难提供这种自由度。如果你对结果质量要求不高、预算有限直接用现成的商业工具当然省事但如果你需要深度融入自己的数据和工作流自研路线会走得更远。2. 架构拆解一个研究代理需要哪些模块OpenResearch的整个系统由五个核心模块组成Planner、Retriever、Extractor、Writer、Verifier。此外还有一个贯穿全局的Memory模块用来存放中间抽取出的实体、关系、证据片段。每个模块职责单一接口清晰这样可以单独替换任何组件而不影响全局。2.1 Planner把模糊问题变成可执行的检索计划刚开始我犯过一个错误直接把用户的问题丢给检索器。结果就是搜索出来的内容五花八门质量极低。后来意识到人的研究第一步永远是“理解问题并切分问题”这一步必须由模型显式完成。Planner模块接收原始问题输出结构化的研究计划包括需要调查的子问题列表每个子问题建议检索的关键词与检索源类型子问题之间的依赖关系预期的产出格式我让Planner采用“先发散、再收敛”的两轮策略。第一轮模型被要求列出所有可能相关的子问题不限制数量第二轮根据优先级和资源预算选择最重要的5到8个子问题。这个预算机制对控制成本和深度至关重要后续我在避坑部分会详细展开。2.2 Retriever多路召回才能避免单一信息源的偏见如果只用一个搜索引擎或只用一个文献库研究结论很容易被单一信息源的偏好带偏。比如只看技术博客你会高估新技术的成熟度只看官方文档你会忽略真实使用中的坑。所以Retriever设计成多路召回Web搜索主要通过自建SearXNG元搜索实例聚合Google、Bing等结果学术搜索直接调用arXiv API、Semantic Scholar API用于论文类调研知识库检索连接内部文档系统的向量化检索接口用于公司内部资料调研网页深度抓取对高价值来源如官方文档、权威报告做正文级别的抓取而不只是摘要多路召回的结果汇总后会经过一个粗排阶段按来源权威性、内容相关度、时效性加权排序保留Top K个候选供后续抽取模块使用。2.3 Extractor与Memory把整篇文档变成可验证的证据Retriever拿到的是几十篇完整的网页或论文不可能全部塞进最终报告。Extractor负责逐篇阅读拆出细粒度的证据片段每一条证据都保留原文片段quote出处source / URL / 发布时间涉及实体entities与子问题的关联IDquestion_id内容类型statistic, comparison, background, risk...这些证据会被写进Memory模块。我最初用MySQL表存后来迁移到图数据库Neo4j因为研究过程中经常需要回答这类问题“A方案与B方案在不同报告中的成本对比是否一致”这本质上是一个多实体关系查询图结构天然合适。当然如果你只是想快速跑通原型用一个SQLite表加JSON字段也足够支撑前中期。2.4 Writer与Verifier研究结论必须来自证据而不是模型记忆Writer模块的工作不是自由发挥而是在证据约束下写作。它接收Memory中与某个子问题关联的所有证据要求生成的每个段落必须引用至少一个证据ID严禁使用未出现在证据列表中的数据或观点。这样可以大幅降低“编造引用”的概率。Verifier则是在报告生成后做一次后置校验重点检查每条核心结论是否有对应的证据引用引用的证据原文是否能支持结论语义一致性打分同一数据在不同来源中是否冲突冲突是否已在报告中注明Verifier的输出是一张校验表标出“通过”“存疑”“失败”。只有所有关键结论都标记为“通过”的报告才会被输出给用户。从经验看这一道关卡能拦截掉大约三成质量不合格的报告非常值得部署。3. 最小可跑版本从零实现一套OpenResearch核心流程理论聊完了来看代码。这里我给出一套最小可运行的Python实现使用FastAPI做API封装调用大模型接口完成规划和写作检索使用SearXNG自建实例加arXiv官方API。3.1 数据模型先定义清楚对象后面才不会乱整个系统的数据流从ResearchRequest开始到Report结束。我推荐用Pydantic定义清晰的数据模型这是后续所有模块交互的基础。from pydantic import BaseModel, Field from typing import List, Optional from enum import Enum from datetime import datetime class SourceType(str, Enum): WEB web ACADEMIC academic INTERNAL internal class SubQuestion(BaseModel): id: str question: str keywords: List[str] source_types: List[SourceType] depth: int Field(1, description子问题检索深度3以上为高优先级) class ResearchRequest(BaseModel): title: str main_question: str budget: int Field(5, description最大子问题数量) max_results_per_search: int Field(10) class EvidenceItem(BaseModel): id: str question_id: str source: str url: str published_at: Optional[datetime] None quote: str summary: str entities: List[str] [] evidence_type: str statistic # statistic, comparison, background, risk... class Report(BaseModel): title: str sections: List[ReportSection] class ReportSection(BaseModel): heading: str sub_question_id: str content: str evidence_ids: List[str] confidence: float Field(ge0, le1)这些模型贯穿始终。注意EvidenceItem.evidence_type字段我在实际使用中发现按类型分类证据对后续写作和验证非常有帮助。比如写“风险”章节时只检索risk类型的证据写“市场现状”时只检索statistic类型。3.2 Planner实现用一次大模型调用生成研究计划Planner的核心是让大模型输出严格的JSON结构。为了提高稳定性我用了function calling而不是让模型自由文本输出。import json from openai import OpenAI client OpenAI() PLANNER_TOOLS [ { type: function, function: { name: submit_research_plan, description: 提交拆分后的研究计划, parameters: { type: object, properties: { sub_questions: { type: array, items: { type: object, properties: { id: {type: string}, question: {type: string}, keywords: {type: array, items: {type: string}}, source_types: { type: array, items: {type: string, enum: [web, academic, internal]} }, depth: {type: integer, minimum: 1, maximum: 5} }, required: [id, question, keywords, source_types, depth] } } }, required: [sub_questions] } } } ] def make_plan(request: ResearchRequest): messages [ {role: system, content: ( 你是一位高级研究员。请把用户的研究主问题拆解为不超过 f{request.budget}个子问题。 每个子问题聚焦于一个独立可检索的方面不要交叉重叠。 关键词必须具体优先使用名词组合。 )}, {role: user, content: request.main_question} ] resp client.chat.completions.create( modelgpt-4o, messagesmessages, toolsPLANNER_TOOLS, tool_choice{type: function, function: {name: submit_research_plan}} ) args json.loads(resp.choices[0].message.tool_calls[0].function.arguments) return [SubQuestion(**item) for item in args[sub_questions]]这个实现有几个细节值得说。第一depth字段是预算控制的关键后续调度器可以根据总预算决定每个子问题的检索深度。第二强制模型通过function calling输出基本杜绝了JSON语法错误。第三在system prompt里明确要求“每个子问题聚焦于独立可检索的方面”能显著减少子问题间的重叠避免重复检索。3.3 Retriever实现SearXNG元搜索与arXiv并行召回在OpenResearch项目里我用Docker部署了一个SearXNG实例因为它提供了干净的JSON API接口让代码不需要依赖某些特定搜索引擎的爬虫协议减少被限制的风险。import requests import urllib.parse SEARXNG_URL http://localhost:8888/search def search_web(query: str, max_results: int 10): params { q: query, format: json, safesearch: 0, language: zh-CN,en-US, } resp requests.get(SEARXNG_URL, paramsparams, timeout30) resp.raise_for_status() results resp.json().get(results, []) # 只保留前max_results条过滤掉明显无关的 return [ {title: r[title], url: r[url], content: r.get(content, )} for r in results[:max_results] ]搜学术文献时我走arXiv API返回的结果含摘要足够抽取阶段使用了。def search_arxiv(query: str, max_results: int 8): params { search_query: fall:{urllib.parse.quote(query)}, start: 0, max_results: max_results, sortBy: relevance, sortOrder: descending, } headers {User-Agent: OpenResearch/1.0 (research agent; contact: examplemail.com)} resp requests.get(http://export.arxiv.org/api/query, paramsparams, headersheaders, timeout30) resp.raise_for_status() # 解析Atom XML import xml.etree.ElementTree as ET ns {atom: http://www.w3.org/2005/Atom} root ET.fromstring(resp.text) entries root.findall(atom:entry, ns) results [] for entry in entries[:max_results]: title entry.find(atom:title, ns).text.strip().replace(\n, ) link entry.find(atom:id, ns).text.strip() summary entry.find(atom:summary, ns).text.strip()[:500] results.append({title: title, url: link, content: summary}) return results这里提醒一句arXiv API虽然免费但一定要带User-Agent否则很容易被限流。官方文档明确要求调用者标识自己这是基本的礼貌也是防止被封号的手段。3.4 Writer与Verifier生成带强引用的报告并检验它报告合成阶段我采用的prompt策略是“证据约束下写作”。所有内容必须来自提供的EvidenceItem列表报告中的每个句子后面用[evidence_id]标记来源。def write_section(sub_question: SubQuestion, evidence_list: List[EvidenceItem]): evidence_text for ev in evidence_list: evidence_text f\n[Evidence {ev.id}] 来源: {ev.url}\n摘要: {ev.summary}\n原文摘录: {ev.quote}\n messages [ {role: system, content: ( 你是一位严谨的研究报告撰写者。你的任务是基于给定的证据写一个章节。 规则1) 只能使用给定的证据不得使用训练记忆中的事实 2) 每个结论句后必须用[证据ID]标注来源 3) 如果证据之间存在冲突需明确写出不同来源存在分歧 4) 如果某方面证据不足需明确写现有证据不足以支持该结论。 )}, {role: user, content: f研究问题{sub_question.question}\n可用证据{evidence_text}\n请开始写作。} ] resp client.chat.completions.create( modelgpt-4o, messagesmessages, temperature0.3, max_tokens800 ) return resp.choices[0].message.contentVerifier我实现成一个独立的检查函数避免和Writer耦合。核心逻辑是抽出报告中所有[evidence_id]标记逐一检查是否存在对应EvidenceItem再对没有标记的句子做大模型一致性打分。def verify_report(report: Report, all_evidence: dict): verification_results [] pattern r\[([Ee]vidence-[0-9a-f-])\] # evidence_id 形如 evidence-uuid for section in report.sections: citations re.findall(pattern, section.content) for cite in citations: if cite not in all_evidence: verification_results.append({ section: section.heading, status: FAIL, reason: f引用 {cite} 不存在 }) # 提取没有引用的句子 sentences re.split(r(?[。.!?]), section.content) for sent in sentences: clean_sent sent.strip() if not clean_sent: continue if not re.search(pattern, clean_sent): verification_results.append({ section: section.heading, status: WARN, reason: f句子缺失引用: {clean_sent[:50]} }) return verification_resultsWARN级别的结果不会阻塞输出但我会在最终报告上标记“未完全验证”。实际使用下来这个简单的正则校验能起到很大的威慑作用——模型知道输出会被检查因此会更谨慎地在句子后添加引用。4. 实测运行中的四类拦路虎踩坑记录与修复方案项目进入真实使用阶段后我遇到的坑远比想象中多。这里列出四个影响最大的问题以及我最终的修复方案。4.1 子问题无限发散预算失控的第一现场第一次完整跑流程时我提了一个还算常规的问题“对比分析国内主流向量数据库的选型优劣”。结果Planner生成了23个子问题包括“什么是向量数据库”“历史沿革”“每种数据库的License差异”“社区活跃度指标”“性能benchmark方法论”。每个子问题又触发4-5次检索、每次检索后又展开抓取最后那轮实验花掉了大几十块钱的API费用耗时40分钟我差点当场放弃这个项目。根因在Planner prompt里完全没有提及“聚焦”和“预算”。我后来改了两处在system prompt中明确“优先覆盖用户直接关心的对比维度背景型信息不需要单独检索除非证据中出现明显知识缺口”。增加了一个全局检索预算参数所有子问题的depth之和不能超过15。每次Planner输出后如果超预算就按子问题优先级裁掉尾部。修复之后同样的主问题生成6个子问题总成本降到了之前的四分之一耗时压到12分钟以内。这个调整带来的收益非常直接。4.2 引用幻觉模型“自信地编造”比我想象的更隐蔽早期版本里Writer可以自由发挥。结果有一次做“某某框架并发性能”调研模型在报告里写出一句“根据[Inconclusive]实验室的实测数据该框架在高并发场景下吞吐量达到每秒12万次”我找遍了全文证据都没有这条数据。更麻烦的是它编的引用ID格式和我真实的证据ID格式一样导致人眼很难识别。我做了三层防御提取阶段过滤EvidenceItem必须包含原文quote字段不允许只有summary没有quote。有原文摘录的证据后续核查才有依据。写作阶段强约束在Writer prompt中明确写“如果证据中没有某个数据不要猜测该数据你可以写‘相关来源未提供该指标’”。验证阶段做交叉检查Verifier除了正则检查引用存在性还会对每个核心数据点包含数字的句子做一次额外大模型调用让“审判模型”判断该数字是否被任一证据支持。三层做下来编造数据的问题基本被根除。偶尔仍会有小瑕疵比如模型把证据里的“60%”理解为“600人”但大方向已经可靠。4.3 检索源限流自建SearXNG也被远端封SearXNG本身不是数据源它是聚合器。实际限制你的是上游搜索引擎。我在高频测试时频繁收到429 Too Many Requests一度以为是SearXNG配置问题。排查后发现两个原因。第一我并发开了8个worker去同时search每个search映射到上游的2-4个引擎请求相当于瞬间向上游打了十几个请求这是肯定会被限制的。第二SearXNG对一些引擎默认带域名随机化但我的实例只有一个域名权重集中。修复方案很朴素检索并发度限制到2请求间隔增加到3到5秒对每个URL做结果缓存同一个域名下的相同查询在7天内不重复请求针对特别重要的来源页面抓取正文时用带重试的请求库指数退避调整后连续跑十轮完整研究流程也没再出现429。稳定的检索层对研究代理至关重要它的不稳定会让整个系统频繁断片。4.4 上下文窗口与成本膨胀资料太多模型读不下当检索器召回40篇文档、每篇正文上万字时无论如何也没办法把这些原文完整喂给Writer。一开始我偷懒只取每篇文档的前2000个字符结果重要信息经常在末尾出现报告质量惨不忍睹。后来我实现了一个简单的证据压缩与排序管道先用FastText给每个检索片段做质量分过滤掉导航栏、广告、版权声明等噪音。对每篇文档按段落分块每个块用Embedding计算与子问题的相似度取Top K块进入抽取。抽取阶段的全过程只保留“证据级”摘要而不是整篇文章。这样一步单篇文档的体积从10KB压缩到1KB以内且因为只保留了高相关度片段最终报告的信噪比显著提升。这个思路其实借鉴了传统信息检索里的“查询相关段落抽取”在RAG系统里也非常通用。5. 我用OpenResearch跑过的三类真实任务经过一段时间的打磨这个项目已经从“玩具”变成了我实际工作流的一部分。这里列出三类我日常跑的任务类型和效果供你判断值不值得自己也搭一套。5.1 技术选型调研类任务这类任务的典型问题是“对比我们目前考虑的A、B、C三个开源项目从社区活跃度、功能完整性、许可证合规性、运维成本四个维度给结论。”传统做法是一个人花三天时间分别搜索每个项目的GitHub、文档、博客、Issue区最后汇总。用OpenResearch跑一次大约15分钟能产出一个4-6页的选型报告。最让我满意的是它的证据链非常清晰比如“A项目在上季度新增了42个contributor”这种数据会直接链接到GitHub的Contributor页面我可以一键点击核实。不过这类任务里我的经验是不要完全相信模型对“运维成本”的判断。运维成本往往是隐性的比如部署复杂度、依赖冲突概率这些信息很难从公开网页中直接招到。报告会把已有证据列出来但最终的决策判断还是要人来顶。5.2 学术文献综述类任务接入arXiv API之后我在写论文前会用OpenResearch快速做一次“文献地图扫描”。例如输入“结构化大模型输出推理的最新进展”它会自动把相关论文分成方法类、评测类、应用类并给出每篇论文的核心贡献和局限。学术场景对比商业搜索最大的不同是它能把“理解”这一层做好。普通搜索给你100篇论文链接你还是要逐一打开摘要OpenResearch会把100篇的摘要和观点按主题聚类直接输出一份综述框架。当然学术写作最终引用的参考文献列表我建议还是要人工逐一审核原文避免模型在归纳时出错。5.3 竞品动态持续监控类任务进一步升级后我把OpenResearch做成了一套周期性监控服务。每天凌晨自动对指定竞品官网、官方博客、产品文档更新做增量检索并合并到主知识图中。当检测到重大变化时推送当日简报到内部群。这个用法有一个关键设计只生成增量摘要不重写完整报告。因为每次全量重写报告不仅浪费token还会让人失去对比视角。用增量摘要配合历史版本对比反而更容易发现变化。5.4 当我决定哪些任务不用它我也遇到几个不适合用这类系统的场景。一是高度依赖内部隐性知识的任务比如“评估这条业务线明年该不该扩张”大量关键信息根本不存在公开页面里二是需要深度分析而非信息聚合的任务比如“解读某篇论文的核心创新点”这需要人真正理解逻辑而不是拼凑证据三是强时效性且数据规模巨大的场景比如“实时统计每秒新增订单量”这是时序数据系统的活不是调研系统该做的。6. 下一步规划和给同路人的几条建议项目到现在已经稳定跑了两个多月我下一个阶段的规划围绕三件事展开。首先是多智能体协作。现在OpenResearch是单线流程Planner拆完子问题后是顺序执行的。我计划改成并行调度每个子问题由一个独立的worker负责worker之间共享Memory但独立推进。这样可以把整体耗时从十几分钟压缩到几分钟。其次是人工反馈闭环。我准备在Verifier后面加一个“人工审核标记”入口用户对某条结论点击“认可”或“存疑”后这个信号会写回数据库用来调整后续检索和抽取阶段的权重。有了人工反馈系统就变成了可学习的工具而不是每次都从零开始的无状态服务。最后是更多的证据源接入。比如接入公开的数据APIGitHub、Crunchbase、WHO、世界银行等让统计数据直接来自第一手来源而不是二手博客的转述。这也是消除模型幻觉最根本的办法——数据本身结构化拿过来不再依赖自然语言转述。如果看到这里的你也打算自己搭一套研究代理我有几条掏心窝的建议先跑最小闭环再优化成本。不要一开始就追求完美用最简单的顺序流程把一个8个子问题的小任务跑通你就有了改进的基准。证据ID是灵魂。从第一天起就严格维护证据的溯源链这会让后面所有调试都变得容易也能让你在面对老板“这数据哪来的”时从容应对。人必须在环上。研究代理做得再好目前也只是“研究助理”不是“研究员”。最终的判断、权衡、决策仍然需要人来完成。设计系统时一定要留出人工审核的环节而不是期望全自动。我在实际使用中最深的感触是OpenResearch这类系统的价值不是让我们少动脑而是把我们从机械的“寻找、翻阅、摘抄”中解脱出来把时间留给真正需要判断力的地方。每次看到一份报告生成出来我依然会逐条点开关键证据核实但“打开标签页、扫一眼、关掉”的重复劳动已经消失了大半。如果你也有类似的调研负担这个方向值得投入。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻