介绍 DeepSearcher:本地开源深度研究
深度搜索器
在上一篇文章《我用开源构建了一个深度研究--你也可以!》中,我们解释了研究 Agents 的一些基本原理,并构建了一个简单的原型,可以生成关于给定主题或问题的详细报告。这篇文章和相应的笔记本展示了工具使用、查询分解、推理和反思等基本概念。与 OpenAI 的 "深度研究 "相比,我们上一篇文章中的例子是在本地运行的,只使用了Milvus和 LangChain 等开源模型和工具。(我鼓励大家在继续阅读之前先阅读上述文章)。
在接下来的几周里,人们对理解和重现 OpenAI 的深度研究产生了浓厚的兴趣。例如,请参阅Perplexity Deep Research和Hugging Face 的 Open DeepResearch。这些工具虽然目标相同,但在架构和方法上各不相同:通过浏览网络或内部文档迭代研究某个主题或问题,并输出详细、翔实、结构合理的报告。重要的是,底层代理可以自动推理每个中间步骤应采取的行动。
在本篇文章中,我们将在上一篇文章的基础上介绍 Zilliz 的DeepSearcher开源项目。我们的 Agents 演示了更多概念:查询路由、条件执行流和作为工具的网络爬行。它以 Python 库和命令行工具的形式呈现,而非 Jupyter 笔记本,功能也比上一篇文章更全面。例如,它可以输入多个源文件,并能通过配置文件设置所使用的 Embeddings 模型和向量数据库。虽然 DeepSearcher 仍然相对简单,但它很好地展示了代理式 RAG,并向最先进的人工智能应用进一步迈进。
此外,我们还探讨了对更快、更高效推理服务的需求。推理模型利用 "推理扩展"(即额外计算)来提高输出,再加上一份报告可能需要数百或数千次 LLM 调用,推理带宽成为主要瓶颈。我们在 SambaNova 的定制硬件上使用DeepSeek-R1 推理模型,其每秒输出令牌的速度是最接近的竞争对手的两倍(见下图)。
SambaNova Cloud 还为其他开源模型提供推理即服务,包括 Llama 3.x、Qwen2.5 和 QwQ。推理服务在 SambaNova 的定制芯片(称为可重构数据流单元(RDU))上运行,该芯片专为生成式人工智能模型的高效推理而设计,可降低成本并提高推理速度。更多信息,请访问他们的网站。
输出速度–DeepSeek R1
DeepSearcher 架构
DeepSearcher的架构沿袭了我们之前的文章,将问题分解为四个步骤–定义/提炼问题、研究、分析、综合–不过这次有一些重叠。我们将逐一介绍每个步骤,并重点介绍DeepSearcher的改进之处。
DeepSearcher 架构
定义和提炼问题
Break down the original query into new sub queries: [
‘How has the cultural impact and societal relevance of The Simpsons evolved from its debut to the present?’,
‘What changes in character development, humor, and storytelling styles have occurred across different seasons of The Simpsons?’,
‘How has the animation style and production technology of The Simpsons changed over time?’,
‘How have audience demographics, reception, and ratings of The Simpsons shifted throughout its run?’]
在 DeepSearcher 的设计中,研究和提炼问题之间的界限非常模糊。用户的初始查询被分解为多个子查询,这与上一篇文章的做法非常相似。请参阅上文由查询 "辛普森一家随着时间的推移发生了哪些变化?"生成的初始子查询。不过,接下来的研究步骤将根据需要继续完善问题。
研究和分析
将查询分解成子查询后,Agent 的研究部分就开始了。它大致分为四个步骤:路由、搜索、反射和条件重复。
路由
我们的数据库包含来自不同来源的多个表或 Collections。如果我们能将语义搜索限制在只与当前查询相关的来源上,效率会更高。查询路由器会提示 LLM 决定应从哪些 Collections 中检索信息。
下面是形成查询路由提示的方法:
def get_vector_db_search_prompt(
question: str,
collection_names: List[str],
collection_descriptions: List[str],
context: List[str] = None,
):
sections = []
# common prompt
common_prompt = f"""You are an advanced AI problem analyst. Use your reasoning ability and historical conversation information, based on all the existing data sets, to get absolutely accurate answers to the following questions, and generate a suitable question for each data set according to the data set description that may be related to the question.
Question: {question}
“"”
sections.append(common_prompt)
<span class="hljs-comment"># data set prompt</span>
data_set = []
<span class="hljs-keyword">for</span> i, collection_name <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(collection_names):
data_set.append(<span class="hljs-string">f"<span class="hljs-subst">{collection_name}</span>: <span class="hljs-subst">{collection_descriptions[i]}</span>"</span>)
data_set_prompt = <span class="hljs-string">f"""The following is all the data set information. The format of data set information is data set name: data set description.
Data Sets And Descriptions:
“"”
sections.append(data_set_prompt + “\n”.join(data_set))
<span class="hljs-comment"># context prompt</span>
<span class="hljs-keyword">if</span> context:
context_prompt = <span class="hljs-string">f"""The following is a condensed version of the historical conversation. This information needs to be combined in this analysis to generate questions that are closer to the answer. You must not generate the same or similar questions for the same data set, nor can you regenerate questions for data sets that have been determined to be unrelated.
Historical Conversation:
“"”
sections.append(context_prompt + “\n”.join(context))
<span class="hljs-comment"># response prompt</span>
response_prompt = <span class="hljs-string">f"""Based on the above, you can only select a few datasets from the following dataset list to generate appropriate related questions for the selected datasets in order to solve the above problems. The output format is json, where the key is the name of the dataset and the value is the corresponding generated question.
Data Sets:
“"”
sections.append(response_prompt + “\n”.join(collection_names))
footer = <span class="hljs-string">"""Respond exclusively in valid JSON format matching exact JSON schema.
Critical Requirements:
- Include ONLY ONE action type
- Never add unsupported keys
- Exclude all non-JSON text, markdown, or explanations
- Maintain strict JSON syntax"""
sections.append(footer)
return “\n\n”.join(sections)
我们让 LLM 以 JSON 格式返回结构化输出,以便轻松地将其输出转换为下一步行动的决定。
搜索
通过上一步选择了各种数据库 Collections 后,搜索步骤将使用Milvus 执行相似性搜索。与上一步的情况很像,源数据已经提前指定、分块、嵌入并存储在向量数据库中。对于 DeepSearcher,本地和在线数据源都必须手动指定。我们将在线搜索留给未来的工作。
反思
与前一篇文章不同的是,DeepSearcher 展示了一种真正的代理反思形式,它将先前的输出作为上下文输入到一个提示中,以 "反思 "迄今为止提出的问题和检索到的相关块是否包含任何信息空白。这可以看作是一个分析步骤。
下面是创建提示的方法:
def get_reflect_prompt(
question: str,
mini_questions: List[str],
mini_chuncks: List[str],
):
mini_chunk_str = ""
for i, chunk in enumerate(mini_chuncks):
mini_chunk_str += f"""<chunk_{i}>\n{chunk}\n</chunk_{i}>\n"""
reflect_prompt = f"""Determine whether additional search queries are needed based on the original query, previous sub queries, and all retrieved document chunks. If further research is required, provide a Python list of up to 3 search queries. If no further research is required, return an empty list.
If the original query is to write a report, then you prefer to generate some further queries, instead return an empty list.
Original Query: <span class="hljs-subst">{question}</span>
Previous Sub Queries: <span class="hljs-subst">{mini_questions}</span>
Related Chunks:
<span class="hljs-subst">{mini_chunk_str}</span>
"""</span>
footer = <span class="hljs-string">"""Respond exclusively in valid List of str format without any other text."""</span>
<span class="hljs-keyword">return</span> reflect_prompt + footer
我们再一次让 LLM 返回结构化输出,这次是可由 Python 解释的数据。
下面是在回答上述初始子查询后,通过反射 "发现 "新子查询的示例:
New search queries for next iteration: [
"How have changes in The Simpsons' voice cast and production team influenced the show's evolution over different seasons?",
"What role has The Simpsons' satire and social commentary played in its adaptation to contemporary issues across decades?",
'How has The Simpsons addressed and incorporated shifts in media consumption, such as streaming services, into its distribution and content strategies?']
条件重复
与上一篇文章不同,DeepSearcher 演示了条件执行流程。在反思到目前为止的问题和答案是否完整之后,如果还有其他问题要问,Agents 会重复上述步骤。重要的是,执行流程(while 循环)是 LLM 输出的函数,而不是硬编码。在这种情况下,只有二选一:重复研究或生成报告。在更复杂的 Agents 中,可能会有多个选择,如:跟踪超链接、检索块、存储在内存中、反映等。通过这种方式,Agents 会根据自己的判断继续完善问题,直到决定退出循环并生成报告。在我们的 "辛普森一家 "示例中,DeepSearcher 还进行了两轮额外的子查询来填补空白。
合成
最后,将完全分解的问题和检索到的数据块合成为带有单个提示的报告。下面是创建提示的代码:
def get_final_answer_prompt(
question: str,
mini_questions: List[str],
mini_chuncks: List[str],
):
mini_chunk_str = ""
for i, chunk in enumerate(mini_chuncks):
mini_chunk_str += f"""<chunk_{i}>\n{chunk}\n</chunk_{i}>\n"""
summary_prompt = f"""You are an AI content analysis expert, good at summarizing content. Please summarize a specific and detailed answer or report based on the previous queries and the retrieved document chunks.
Original Query: <span class="hljs-subst">{question}</span>
Previous Sub Queries: <span class="hljs-subst">{mini_questions}</span>
Related Chunks:
<span class="hljs-subst">{mini_chunk_str}</span>
"""</span>
<span class="hljs-keyword">return</span> summary_prompt
与我们的原型相比,这种方法的优势在于,它可以单独分析每个问题,并简单地将输出结果连接起来,从而生成一份所有部分都相互一致的报告,即不包含重复或相互矛盾的信息。一个更复杂的系统可以将两者的某些方面结合起来,使用条件执行流程来构建报告、总结、重写、反思和透视等,我们将把这些工作留待今后进行。
结果
下面是 "辛普森一家随着时间发生了哪些变化?"查询生成的报告样本,DeepSeek-R1 将维基百科上关于辛普森一家的页面作为源材料:
Report: The Evolution of The Simpsons (1989–Present)
1. Cultural Impact and Societal Relevance
The Simpsons debuted as a subversive critique of American middle-class life, gaining notoriety for its bold satire in the 1990s. Initially a countercultural phenomenon, it challenged norms with episodes tackling religion, politics, and consumerism. Over time, its cultural dominance waned as competitors like South Park and Family Guy pushed boundaries further. By the 2010s, the show transitioned from trendsetter to nostalgic institution, balancing legacy appeal with attempts to address modern issues like climate change and LGBTQ+ rights, albeit with less societal resonance.
…
Conclusion
The Simpsons evolved from a radical satire to a television institution, navigating shifts in technology, politics, and audience expectations. While its golden-age brilliance remains unmatched, its adaptability—through streaming, updated humor, and global outreach—secures its place as a cultural touchstone. The show’s longevity reflects both nostalgia and a pragmatic embrace of change, even as it grapples with the challenges of relevance in a fragmented media landscape.
点击此处查看报告全文,以及DeepSearcher 使用 GPT-4o mini 生成的报告对比。
讨论
我们介绍了用于执行研究和撰写报告的 AgentsDeepSearcher。我们的系统建立在前一篇文章的基础上,增加了条件执行流、查询路由和改进的界面等功能。我们从使用小型 4 位量化推理模型的本地推理,转为使用大规模 DeepSeek-R1 模型的在线推理服务,从质上改进了我们的输出报告。DeepSearcher 可与大多数推理服务协同工作,如 OpenAI、Gemini、DeepSeek 和 Grok 3(即将推出!)。
推理模型,尤其是在研究 Agents 中使用的推理模型,是推理的重中之重,而我们有幸能够使用 SambaNova 在其定制硬件上运行的 DeepSeek-R1 最快版本。在演示查询中,我们对SambaNova的DeepSeek-R1推理服务进行了65次调用,输入约2.5万个标记,输出2.2万个标记,花费0.3美元。鉴于该模型包含 6710 亿个参数,并且有 3/4 TB 之大,推理速度给我们留下了深刻印象。点击此处了解更多详情!
我们将在今后的文章中继续迭代这项工作,研究更多的 Agents 概念和研究代理的设计空间。在此期间,我们邀请大家试用DeepSearcher,在 GitHub 上为我们加星,并分享您的反馈意见!
资源
DeepSearcher:关于辛普森一家的 DeepSeek-R1 报告
DeepSearcher:关于《辛普森一家》的 GPT-4o 微型报告
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word



