Milvus
Zilliz
  • Home
  • Blog
  • Présentation de DeepSearcher : Une source ouverte locale pour la recherche en profondeur

Présentation de DeepSearcher : Une source ouverte locale pour la recherche en profondeur

  • Announcements
February 21, 2025
Stefan Webb

DeepSearcher DeepSearcher

Dans l'article précédent, "I Built a Deep Research with Open Source-and So Can You !", nous avons expliqué certains des principes qui sous-tendent les agents de recherche et construit un prototype simple qui génère des rapports détaillés sur un sujet ou une question donné(e). L'article et le carnet de notes correspondant ont démontré les concepts fondamentaux de l'utilisation des outils, de la décomposition des requêtes, du raisonnement et de la réflexion. L'exemple présenté dans notre article précédent, contrairement à Deep Research de l'OpenAI, a fonctionné localement, en utilisant uniquement des modèles et des outils open-source tels que Milvus et LangChain. (Je vous encourage à lire l'article ci-dessus avant de poursuivre).

Dans les semaines qui ont suivi, l'intérêt pour la compréhension et la reproduction de la recherche profonde de l'OpenAI a explosé. Voir, par exemple, Perplexity Deep Research et Hugging Face's Open DeepResearch. Ces outils diffèrent en termes d'architecture et de méthodologie, bien qu'ils partagent le même objectif : effectuer des recherches itératives sur un sujet ou une question en surfant sur le web ou sur des documents internes et produire un rapport détaillé, bien informé et bien structuré. Il est important de noter que l'agent sous-jacent automatise le raisonnement sur l'action à entreprendre à chaque étape intermédiaire.

Dans cet article, nous nous appuyons sur notre article précédent et présentons le projet open-source DeepSearcher de Zilliz. Notre agent démontre des concepts supplémentaires : le routage des requêtes, le flux d'exécution conditionnel et l'exploration du web en tant qu'outil. Il est présenté comme une bibliothèque Python et un outil de ligne de commande plutôt qu'un carnet Jupyter et est plus complet que notre précédent article. Par exemple, il peut saisir plusieurs documents sources et définir le modèle d'intégration et la base de données vectorielle utilisés via un fichier de configuration. Bien qu'il soit encore relativement simple, DeepSearcher est une excellente vitrine du RAG agentique et constitue un pas de plus vers des applications d'IA de pointe.

En outre, nous explorons le besoin de services d'inférence plus rapides et plus efficaces. Les modèles de raisonnement font appel à la "mise à l'échelle de l'inférence", c'est-à-dire à des calculs supplémentaires, pour améliorer leurs résultats, ce qui, combiné au fait qu'un seul rapport peut nécessiter des centaines ou des milliers d'appels LLM, fait de la bande passante de l'inférence le principal goulot d'étranglement. Nous utilisons le modèle de raisonnement DeepSeek-R1 sur le matériel personnalisé de SambaNova, qui est deux fois plus rapide en termes de jetons de sortie par seconde que le concurrent le plus proche (voir la figure ci-dessous).

SambaNova Cloud fournit également un service d'inférence pour d'autres modèles open-source, notamment Llama 3.x, Qwen2.5 et QwQ. Le service d'inférence fonctionne sur la puce personnalisée de SambaNova appelée unité de flux de données reconfigurable (RDU), qui est spécialement conçue pour une inférence efficace sur les modèles d'IA générative, réduisant les coûts et augmentant la vitesse d'inférence. Pour en savoir plus, consultez leur site web.

Output Speed- DeepSeek R1 Vitesse de sortie - DeepSeek R1

Architecture de DeepSearcher

L’architecture de DeepSearcher suit notre précédent article en décomposant le problème en quatre étapes - définir/affiner la question, rechercher, analyser, synthétiser - bien que cette fois avec quelques chevauchements. Nous passons en revue chaque étape, en soulignant les améliorations apportées par DeepSearcher.

DeepSearcher Architecture Architecture de DeepSearcher

Définir et affiner la question

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?’]

Dans la conception de DeepSearcher, les frontières entre la recherche et l'affinement de la question sont floues. La requête initiale de l'utilisateur est décomposée en sous-requêtes, comme dans le billet précédent. Voir ci-dessus les sous-requêtes initiales produites à partir de la requête "Comment les Simpsons ont-ils changé au fil du temps ? Toutefois, l'étape de recherche suivante permettra d'affiner la question si nécessaire.

Recherche et analyse

Après avoir décomposé la requête en sous-requêtes, la partie recherche de l'agent commence. Elle comporte, grosso modo, quatre étapes : l'acheminement, la recherche, la réflexion et la répétition conditionnelle.

Routage

Notre base de données contient plusieurs tables ou collections provenant de différentes sources. Il serait plus efficace de restreindre notre recherche sémantique aux seules sources pertinentes pour la requête en question. Un routeur de requête demande à un LLM de décider à partir de quelles collections les informations doivent être récupérées.

Voici la méthode pour former l'invite de routage de requête :

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&quot;<span class="hljs-subst">{collection_name}</span>: <span class="hljs-subst">{collection_descriptions[i]}</span>&quot;</span>)
data_set_prompt = <span class="hljs-string">f&quot;&quot;&quot;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&quot;&quot;&quot;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&quot;&quot;&quot;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">&quot;&quot;&quot;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)

Nous faisons en sorte que le LLM renvoie une sortie structurée sous forme de JSON afin de convertir facilement sa sortie en une décision sur ce qu'il convient de faire ensuite.

Après avoir sélectionné diverses collections de bases de données à l'étape précédente, l'étape de recherche effectue une recherche de similarité avec Milvus. Comme dans l'article précédent, les données sources ont été spécifiées à l'avance, découpées en morceaux, intégrées et stockées dans la base de données vectorielle. Pour DeepSearcher, les sources de données, locales et en ligne, doivent être spécifiées manuellement. Nous laissons la recherche en ligne pour de futurs travaux.

Réflexion

Contrairement à l'article précédent, DeepSearcher illustre une véritable forme de réflexion agentique, en introduisant les résultats précédents en tant que contexte dans une invite qui "réfléchit" à la question de savoir si les questions posées jusqu'à présent et les morceaux extraits pertinents contiennent des lacunes en matière d'information. Cela peut être considéré comme une étape d'analyse.

Voici la méthode de création de l'invite :

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>
&quot;&quot;&quot;</span>


footer = <span class="hljs-string">&quot;&quot;&quot;Respond exclusively in valid List of str format without any other text.&quot;&quot;&quot;</span>
<span class="hljs-keyword">return</span> reflect_prompt + footer

Une fois de plus, nous faisons en sorte que le LLM renvoie une sortie structurée, cette fois sous forme de données interprétables par Python.

Voici un exemple de nouvelles sous-questions "découvertes" par réflexion après avoir répondu aux sous-questions initiales ci-dessus :

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?']

Répétition conditionnelle

Contrairement à notre précédent billet, DeepSearcher illustre un flux d'exécution conditionnel. Après avoir réfléchi si les questions et les réponses sont complètes, s'il y a des questions supplémentaires à poser, l'agent répète les étapes ci-dessus. Il est important de noter que le flux d'exécution (une boucle while) est une fonction de la sortie LLM plutôt que d'être codé en dur. Dans ce cas, il n'y a qu'un choix binaire : répéter la recherche ou générer un rapport. Dans le cas d'agents plus complexes, il peut y avoir plusieurs choix tels que : suivre un hyperlien, récupérer des morceaux, stocker en mémoire, réfléchir, etc. De cette manière, la question continue d'être affinée comme l'agent le souhaite jusqu'à ce qu'il décide de sortir de la boucle et de générer un rapport. Dans notre exemple des Simpsons, DeepSearcher effectue deux tours supplémentaires pour combler les lacunes avec des sous-requêtes supplémentaires.

Synthétiser

Enfin, la question entièrement décomposée et les morceaux récupérés sont synthétisés dans un rapport avec une seule invite. Voici le code permettant de créer l'invite :

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>
&quot;&quot;&quot;</span>
<span class="hljs-keyword">return</span> summary_prompt

Cette approche présente l'avantage, par rapport à notre prototype qui analysait chaque question séparément et concaténait simplement les résultats, de produire un rapport dont toutes les sections sont cohérentes entre elles, c'est-à-dire qu'elles ne contiennent pas d'informations répétées ou contradictoires. Un système plus complexe pourrait combiner des aspects des deux, en utilisant un flux d'exécution conditionnelle pour structurer le rapport, résumer, réécrire, réfléchir et pivoter, et ainsi de suite, ce que nous laissons pour des travaux futurs.

Résultats

Voici un échantillon du rapport généré par la requête "Comment les Simpsons ont-ils changé au fil du temps ?" avec DeepSeek-R1 qui utilise la page Wikipédia sur les Simpsons comme source :

Report: The Evolution of The Simpsons (1989Present)
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.

Vous trouverez le rapport complet ici, ainsi qu'un rapport produit par DeepSearcher avec GPT-4o mini pour comparaison.

Discussion

Nous avons présenté DeepSearcher, un agent permettant d'effectuer des recherches et de rédiger des rapports. Notre système est construit sur l'idée de notre article précédent, en ajoutant des fonctionnalités telles que le flux d'exécution conditionnel, le routage des requêtes, et une interface améliorée. Nous sommes passés de l'inférence locale avec un petit modèle de raisonnement quantifié de 4 bits à un service d'inférence en ligne pour le modèle massif DeepSeek-R1, ce qui a permis d'améliorer qualitativement notre rapport de sortie. DeepSearcher fonctionne avec la plupart des services d'inférence comme OpenAI, Gemini, DeepSeek et Grok 3 (bientôt !).

Les modèles de raisonnement, en particulier ceux utilisés dans les agents de recherche, reposent sur l'inférence, et nous avons eu la chance de pouvoir utiliser l'offre la plus rapide de DeepSeek-R1 de SambaNova, qui fonctionne sur leur matériel personnalisé. Pour notre requête de démonstration, nous avons effectué soixante-cinq appels au service d'inférence DeepSeek-R1 de SambaNova, entrant environ 25k tokens, sortant 22k tokens, et coûtant 0,30 $. Nous avons été impressionnés par la vitesse d'inférence étant donné que le modèle contient 671 milliards de paramètres et a une taille de 3/4 de téraoctet. Pour plus de détails, cliquez ici !

Nous continuerons à itérer sur ce travail dans de futurs articles, en examinant d'autres concepts agentiques et l'espace de conception des agents de recherche. En attendant, nous invitons tout le monde à essayer DeepSearcher, à nous suivre sur GitHub et à nous faire part de vos commentaires !

Ressources

    Try Managed Milvus for Free

    Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

    Get Started

    Like the article? Spread the word

    Continuer à Lire