Sélection optimale de segments de texte et réarrangement d'URL dans DeepSearch/DeepResearch
Si vous avez déjà lu le dernier article classique de Jina, "LaConception et mise en œuvre de DeepSearch/DeepResearch"il vaut la peine de se pencher un peu plus sur les détails qui peuvent améliorer considérablement la qualité de votre réponse. Cette fois-ci, nous nous concentrerons sur deux détails :
Extraction de segments de texte optimaux à partir de longues pages webComment utiliser les algorithmes de "late-chunking" pour sélectionner les bribes d'information les plus pertinentes dans un long contenu web. Réorganisation des URL collectésComment utiliser le Reranker pour permettre à l'agent LLM de choisir intelligemment l'URL à explorer parmi des centaines d'URL ?
Certains d'entre vous se souviendront peut-être de notre conclusion dans le billet précédent : "Dans DeepSearch, le modèle Embeddings n'est adapté qu'au dédoublonnage des requêtes pour des tâches telles que STS (Semantic Textual Similarity), et Reranker ne figurait même pas dans notre implémentation de programmation originale de DeepSearch".
Rétrospectivement, les deux types de modèles de rappel ont toujours leur valeur, mais pas de la manière dont nous les concevons habituellement. Nous avons toujours suivi le principe "80-20" dans le domaine de la recherche, et nous n'essayons pas de câbler des modèles pour prendre en charge la valeur émotionnelle, ou pour prouver notre présence sur le marché en tant que fournisseur d'Embeddings et de Reranker. Nous sommes très 80-20, très pragmatiques.Pragmatique au point de ne s'intéresser qu'aux besoins les plus essentiels du système de recherche.
Ainsi, après des semaines d'essais et d'itérations, nous avons découvert des applications non conventionnelles mais très efficaces des Embeddings et du Reranker dans le système DeepSearch/DeepResearch. Après avoir utilisé ces méthodes, nous avons considérablement amélioré la qualité de Jina DeepSearch (vous êtes invités à en faire l'expérience). Nous souhaitons également partager ces expériences avec nos pairs qui travaillent ensemble dans ce domaine.
Sélection de segments de texte optimaux à partir d'un texte long
Le problème est le suivant : avec Jina Reader Après avoir lu le contenu de la page web, nous devons le placer dans le contexte de l'agent en tant qu'élément de connaissance sur lequel il peut raisonner. Bien que le fait d'introduire l'ensemble du contenu dans le contexte du LLM d'un seul coup soit la manière la moins encombrante de le faire, étant donné que le Jeton Compte tenu des coûts et de la vitesse de génération, ce n'est certainement pas la meilleure option. Dans la pratique, nous devons identifier les parties du contenu qui sont les plus pertinentes pour le problème et n'ajouter que ces parties en tant que connaissances dans le contexte de l'agent.
💡 Nous parlons ici des cas où le contenu est encore trop long même après l'avoir nettoyé pour nettoyer le Markdown avec Jina Reader. Par exemple, dans les pages longues comme les GitHub Issues, les posts Reddit, les discussions de forum et les articles de blog.
Les méthodes de sélection basées sur le LLM présentent les mêmes problèmes de coût et de latence, et nous devrons donc déterminer s'il existe des solutions basées sur des petits modèles :Nous avons besoin de modèles plus petits et moins chers qui prennent toujours en charge plusieurs langues.Il s'agit d'un facteur clé, car il n'est pas garanti que les questions ou la documentation soient toujours rédigées en chinois.
D'un côté, nous avons la question (la requête originale ou la question "pauvre en informations") et de l'autre côté, nous avons un grand nombre de contenus Markdown, dont une grande partie n'est pas pertinente. Nous devons sélectionner les éléments les plus pertinents par rapport à la question. C'est un peu comme RAG Le problème du découpage en morceaux que la communauté tente de résoudre depuis 2023 - en utilisant le modèle Retriever pour récupérer uniquement les morceaux pertinents et les placer dans une fenêtre contextuelle pour les résumer.
Cependant, notre situation présente deux différences essentielles :
Un nombre fini de blocs de texte dans un nombre fini de documents.
En supposant que chaque bloc contienne environ 500 tokens, un long document web typique contient entre 200 000 et 1 000 000 tokens (99e percentile). Nous utilisons Jina Reader pour explorer 4 à 5 URL à la fois, ce qui génère quelques centaines de blocs de texte. Cela signifie des centaines de vecteurs et des centaines de similitudes cosinus. Ceci est facilement gérable en mémoire avec JavaScript, et il n'y a pas besoin d'une base de données de vecteurs.
Nous avons besoin de blocs de texte continus pour former un résumé efficace des connaissances.
Nous ne pouvons pas accepter des résumés comme [1-2, 6-7, 9, 14, 17, ...] Des résumés qui consistent en des phrases éparses comme celle-ci. Un résumé des connaissances plus utile serait quelque chose comme [3-15, 17-24, ...]. qui maintiendrait mieux la cohérence du texte. Cela faciliterait la copie et la citation de sources de connaissances par LLM et réduirait également le nombre d'"illusions".
Pour le reste, il s'agit des mêmes mises en garde dont se plaignent les développeurs : chaque bloc de texte ne peut pas être trop long car le modèle vectoriel ne peut pas gérer un contexte trop long ; le découpage entraîne une perte de contexte et rend les vecteurs de chaque bloc de texte indépendamment et identiquement distribués ; enfin, comment diable trouver les limites optimales qui préservent à la fois la lisibilité et la sémantique ? Si vous savez de quoi nous parlons, il y a de fortes chances que vous ayez également été confronté à ces problèmes dans vos implémentations RAG.
Mais pour faire court, utilisez jina-embeddings-v3
(utilisé comme expression nominale) Chunking tardifElle résout parfaitement ces trois problèmes. Le "découpage tardif" préserve les informations contextuelles de chaque bloc, n'est pas sensible aux frontières, et jina-embeddings-v3
Elle est elle-même à la pointe de la technologie dans les tâches de recherche multilingue asymétrique. Les lecteurs intéressés peuvent consulter le billet de blog ou l'article de Jina pour obtenir des détails sur la mise en œuvre globale.
🔗 https://arxiv.org/pdf/2409.04701

Organigramme de la sélection des fragments à l'aide des scores tardifs
Cette figure illustre l'algorithme de sélection des résumés, qui fonctionne comme une convolution unidimensionnelle (Conv1D). Le processus commence par diviser un long document en morceaux de longueur fixe, puis utilise une méthode de partitionnement tardif jina-embeddings-v3
vectoriser ces blocs de texte. Après avoir calculé les scores de similarité entre chaque bloc et la question, une fenêtre coulissante se déplace sur ces scores de similarité pour trouver la fenêtre ayant la moyenne la plus élevée.
Voici le code schématique : il utilise le partitionnement tardif et le regroupement moyen similaire à la "convolution 1D" pour sélectionner les passages les plus pertinents pour le problème.
function cherryPick(question, longContext, options) {
if (longContext.length < options.snippetLength * options.numSnippets)
return longContext;
const chunks = splitIntoChunks(longContext, options.chunkSize);
const chunkEmbeddings = getEmbeddings(chunks, "retrieval.passage");
const questionEmbedding = getEmbeddings([question], "retrieval.query")[0];
const similarities = chunkEmbeddings.map(embed =>
cosineSimilarity(questionEmbedding, embed));
const chunksPerSnippet = Math.ceil(options.snippetLength / options.chunkSize);
const snippets = [];
const similaritiesCopy = [...similarities];
for (let i = 0; i < options.numSnippets; i++) {
let bestStartIndex = 0;
let bestScore = -Infinity;
for (let j = 0; j <= similarities.length - chunksPerSnippet; j++) {
const windowScores = similaritiesCopy.slice(j, j + chunksPerSnippet);
const windowScore = average(windowScores);
if (windowScore > bestScore) {
bestScore = windowScore;
bestStartIndex = j;
}
}
const startIndex = bestStartIndex * options.chunkSize;
const endIndex = Math.min(startIndex + options.snippetLength, longContext.length);
snippets.push(longContext.substring(startIndex, endIndex));
for (let k = bestStartIndex; k < bestStartIndex + chunksPerSnippet; k++)
similaritiesCopy[k] = -Infinity;
}
return snippets.join("\n\n");
}
Lorsque vous appelez l'API Jina Embeddings, n'oubliez pas de définir le paramètre task
En fonction de l'extraction, ouvrir le late_chunking
(math.) genretruncate
Configurez-le également comme suit :
await axios.post(
'https://api.jina.ai/v1/embeddings',
{
model: "jina-embeddings-v3",
task: "retrieval.passage",
late_chunking: true,
input: chunks,
truncate: true
},
{ headers });
Si le problème doit être vectorisé, n'oubliez pas de mettre task
échanger (qqch) contre (qqch d'autre) retrieval.query
Ensuite, il faut l'éteindre. late_chunking
.
Le code d'implémentation complet est disponible sur GitHub :https://github.com/jina-ai/node-DeepResearch/blob/main/src/tools/jina-latechunk.ts
Tri des URL pour les prochaines lectures
Le problème est le suivant : dans chaque processus de recherche approfondie, vous pouvez collecter un certain nombre d'URL à partir des pages de résultats des moteurs de recherche (SERP), et chaque fois que vous ouvrez une page Web, vous pouvez découvrir un grand nombre de nouveaux liens en cours de route, même après la suppression de l'emphase, cela représente encore facilement quelques centaines d'URL. De même, bourrer les LLM de toutes ces URL ne fonctionnera pas, c'est un gaspillage de longueur contextuelle précieuse, et pire encore, nous avons constaté que les LLM choisissaient essentiellement à l'aveuglette. Nous avons donc dû trouver un moyen de guider le LLM pour qu'il choisisse les URL les plus susceptibles de contenir la réponse.
curl https://r.jina.ai/https://example.com \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Retain-Images: none" \
-H "X-Md-Link-Style: discarded" \
-H "X-Timeout: 20" \
-H "X-With-Links-Summary: all"
C'est la meilleure façon de configurer Jina Reader pour qu'il explore une page dans DeepSearch. Il identifiera tous les liens de la page, les placera dans le champ des liens et les supprimera du champ du contenu.
Il s'agit en quelque sorte d'un "PageRank en contexte", à ceci près que nous évaluons des centaines d'URL au cours d'une même session.
Nous prenons en compte plusieurs facteurs : l'heure de la dernière mise à jour, la fréquence d'apparition du nom de domaine, la structure du chemin de la page et, surtout, la pertinence sémantique par rapport à la question, afin de calculer un score composite. Cependant, nous ne pouvons utiliser que les informations disponibles avant même de cliquer sur l'URL.

1. les signaux de fréquenceSi une URL apparaît plusieurs fois dans différentes sources, elle a plus de poids. De même, si un nom de domaine apparaît fréquemment dans les résultats de recherche, les URL de ce domaine se voient attribuer des points supplémentaires. En effet, les domaines populaires ont généralement tendance à contenir des contenus qui font autorité.
2. la structure de l'itinéraireNous analyserons la structure des chemins d'accès des URL afin de déterminer quel contenu est regroupé. Si plusieurs URL appartiennent tous à la même hiérarchie de chemins, ils obtiendront un score plus élevé ; cependant, plus le chemin est profond, plus le bonus de score diminuera progressivement.
3. pertinence sémantique: nous utilisons jina-reranker-v2-base-multilingual
pour évaluer la pertinence sémantique de la question et les informations textuelles (par exemple, le titre et le résumé) de chaque URL, ce qui constitue un problème typique de réorganisation. Les informations textuelles de chaque URL proviennent de plusieurs sources :
Search Engine Results Page (SERP) API Renvoie le titre et le résumé (https://s.jina.ai/ Cette interface, avec "X-Respond-With" : "no-content", renvoie uniquement le titre et le résumé, et non le contenu spécifique). Texte d'ancrage pour les URL de la page (en utilisant l'interface https://r.jina.ai et en définissant "X-With-Links-Summary" : "all", vous obtiendrez des informations sommaires, ou un texte d'ancrage, pour tous les liens de la page).
4. dernière mise à jourLes requêtes de DeepSearch ont des exigences élevées en matière d'actualité, de sorte qu'en général, plus l'URL est récente, plus la valeur est élevée. Cependant, sans la capacité d'indexation à grande échelle de Google, il est difficile de déterminer avec précision l'heure de la dernière mise à jour d'une page web. Nous utilisons une combinaison des signaux suivants pour donner un horodatage avec une note de confiance afin d'afficher en priorité le contenu le plus récent lorsque cela est nécessaire :
Les fonctions de filtrage fournies par l'API SERP (par exemple, le paramètre tbs de s.jina.ai, qui permet de filtrer en fonction du temps). Analyse des informations de l'en-tête HTTP (telles que les champs Last-Modified et ETag). Extraction de métadonnées (par exemple, balises méta et horodatage Schema.org). Content Pattern Recognition (reconnaissance des dates visibles dans le HTML). Mesures pour des plates-formes CMS spécifiques (par exemple WordPress, Drupal, Ghost, etc.)
5. contenu restreintLes plateformes de médias sociaux proposent des contenus dont l'accès est restreint ou payant. Il n'existe aucun moyen d'accéder légalement à ce contenu sans se connecter. C'est pourquoi nous maintenons activement une liste noire de ces URL et domaines problématiques, afin de réduire leur classement et d'éviter de gaspiller des ressources informatiques sur ce contenu inaccessible.
6. diversité des noms de domaineParfois, les meilleures URL proviennent toutes du même domaine, ce qui peut amener DeepSearch à tomber dans un "optimum local", affectant ainsi la qualité des résultats finaux. Comme nous l'avons mentionné précédemment, les principales URL proviennent toutes de StackOverflow. Pour augmenter la diversité des résultats, nous pouvons utiliser une stratégie "explorer et exploiter" : sélectionner les K premières URL de chaque domaine.
Le code complet de l'implémentation du tri des URL se trouve sur notre Github : https://github.com/jina-ai/node-DeepResearch/blob/main/src/utils/url-tools.ts#L192
<action-visit>
- Crawl and read full content from URLs, you can get the fulltext, last updated datetime etc of any URL.
- Must check URLs mentioned in <question> if any
- Choose and visit relevant URLs below for more knowledge. higher weight suggests more relevant:
<url-list>
+ weight: 0.20 "https://huggingface.co/docs/datasets/en/loading": "Load - Hugging FaceThis saves time because instead of waiting for the Dataset builder download to time out, Datasets will look directly in the cache. Set the environment ...Some datasets may have more than one version based on Git tags, branches, or commits. Use the revision parameter to specify the dataset version you want to load ..."
+ weight: 0.20 "https://huggingface.co/docs/datasets/en/index": "Datasets - Hugging Face🤗 Datasets is a library for easily accessing and sharing datasets for Audio, Computer Vision, and Natural Language Processing (NLP) tasks. Load a dataset in a ..."
+ weight: 0.17 "https://github.com/huggingface/datasets/issues/7175": "[FSTimeoutError] load_dataset · Issue #7175 · huggingface/datasetsWhen using load_dataset to load HuggingFaceM4/VQAv2, I am getting FSTimeoutError. Error TimeoutError: The above exception was the direct cause of the following ..."
+ weight: 0.15 "https://github.com/huggingface/datasets/issues/6465": "`load_dataset` uses out-of-date cache instead of re-downloading a ...When a dataset is updated on the hub, using load_dataset will load the locally cached dataset instead of re-downloading the updated dataset."
+ weight: 0.12 "https://stackoverflow.com/questions/76923802/hugging-face-http-request-on-data-from-parquet-format-when-the-only-way-to-get-i": "Hugging face HTTP request on data from parquet format when the ...I've had to get the data from their data viewer using the parquet option. But when I try to run it, there is some sort of HTTP error. I've tried downloading ..."
</url-list>
</action-visit>
résumés
Depuis que la recherche approfondie de Jina a été mise à disposition le 2 février 2025, deux détails techniques ont été découverts qui peuvent améliorer considérablement la qualité.Il est intéressant de noter que les deux détails utilisent des modèles multilingues d'intégration et de reclassement dans une "fenêtre contextuelle".Ce n'est rien comparé aux index massifs précalculés que ces modèles requièrent généralement.
Cela peut laisser présager une polarisation des technologies de recherche à l'avenir. Nous pouvons emprunter à Kahneman la théorie du double processus pour comprendre cette tendance :
Réfléchissez rapidement. Réflexion rapide (grep, BM25, SQL) : recherche rapide de motifs basée sur des règles avec un minimum de calculs. réfléchir lentement Penser lentement (LLM) : raisonnement complet avec une compréhension contextuelle approfondie, mais à forte intensité de calcul. moyengroupe Réflexion à mi-parcours (Embedding, Reranker et al. Recall Model) : a une certaine compréhension sémantique, meilleure que le simple pattern matching, mais beaucoup moins d'inférence que LLM.
L'une des possibilités est la suivante :Les architectures de recherche à deux niveaux sont de plus en plus populairesLa valeur résiduelle du modèle de niveau intermédiaire est alors transférée aux tâches dans une fenêtre contextuelle spécifique : par exemple, le filtrage, la déduplication, le tri, etc. La valeur résiduelle du modèle de niveau intermédiaire est alors transférée vers des tâches dans une fenêtre contextuelle spécifique : par exemple, le filtrage, la déduplication, le tri, etc. Dans ces scénarios, il serait inefficace d'effectuer un raisonnement complet avec le LLM.
Mais quoi qu'il en soit.Sélection de clips clés répondre en chantant Tri des URL Il s'agit toujours de l'aspect fondamental qui affecte directement la qualité d'un système DeepSearch/DeepResearch. Nous espérons que nos conclusions vous aideront à améliorer votre propre système.
L'expansion des requêtes est un autre facteur clé pour déterminer la qualité.Légumes.Nous évaluons activement une variété d'approches, allant de simples réécritures basées sur des invites, à de petits modèles, en passant par des approches basées sur l'inférence. Nous vous invitons à découvrir les résultats de nos recherches dans ce domaine !
© déclaration de droits d'auteur
Article copyright Cercle de partage de l'IA Tous, prière de ne pas reproduire sans autorisation.
Articles connexes
Pas de commentaires...