Wenn Sie Jina's letzten langen, klassischen Artikel "The" bereits gelesen habenEntwurf und Implementierung von DeepSearch/DeepResearch", dann lohnt es sich, ein wenig tiefer in die Details einzusteigen, die die Qualität Ihrer Antwort erheblich verbessern können. Dieses Mal werden wir uns auf zwei Details konzentrieren:
-
Extrahieren optimaler Textsegmente aus langen Web-SeitenWie man Late-Chunking-Algorithmen verwendet, um die relevantesten Informationsschnipsel aus langen Webinhalten auszuwählen. -
Neuordnung der gesammelten URLsWie kann man Reranker verwenden, damit der LLM-Agent intelligent auswählen kann, welche URL unter Hunderten von URLs gecrawlt werden soll?
Einige von Ihnen erinnern sich vielleicht an unsere Schlussfolgerung im letzten Beitrag: "In DeepSearch eignet sich das Embeddings-Modell nur für die Abfrage-Deduplizierung für Aufgaben wie STS (Semantic Textual Similarity), und Reranker war nicht einmal in unserer ursprünglichen DeepSearch-Programmimplementierung enthalten."
Im Nachhinein betrachtet haben beide Arten von Erinnerungsmodellen immer noch ihren Wert, nur nicht in der Art und Weise, wie wir normalerweise an sie denken. Wir haben uns bei der Suche immer an das "80-20"-Prinzip gehalten und versuchen nicht, Modelle fest zu verdrahten, um für den emotionalen Wert zu sorgen oder unsere Marktpräsenz als Anbieter von Embeddings und Rerankern zu beweisen. Wir sind sehr 80-20, sehr pragmatisch.Pragmatisch bis zu dem Punkt, an dem wir uns nur um die wichtigsten Bedürfnisse des Suchsystems kümmern.
So entdeckten wir nach wochenlangem Ausprobieren und Iterieren einige unkonventionelle, aber sehr effektive Anwendungen von Embeddings und Rerankern im DeepSearch/DeepResearch-System. Durch den Einsatz dieser Methoden konnten wir die Qualität von Jina DeepSearch deutlich verbessern (Sie sind herzlich eingeladen, sie zu testen). Wir möchten diese Erfahrungen auch mit unseren Kollegen teilen, die auf diesem Gebiet zusammenarbeiten.
Auswahl optimaler Textsegmente aus einem langen Text
Das Problem ist folgendes: Mit Jina Leser Nachdem wir den Inhalt der Webseite gelesen haben, müssen wir ihn in den Kontext des Agenten als ein Stück Wissen einfügen, über das er nachdenken kann. Den gesamten Inhalt auf einen Schlag in den Kontext des LLM zu packen, wäre zwar die am wenigsten umständliche Art, dies zu tun, da der Token Aufgrund der Kosten und der Geschwindigkeit der Erstellung ist dies sicherlich nicht die beste Option. In der Praxis müssen wir die Teile des Inhalts identifizieren, die für das Problem am relevantesten sind, und nur diese Teile als Wissen zum Kontext des Agenten hinzufügen.
💡 Hier geht es um Fälle, in denen der Inhalt immer noch zu lang ist, selbst nachdem er mit Jina Reader in sauberes Markdown umgewandelt wurde. Zum Beispiel bei langen Seiten wie GitHub Issues, Reddit-Beiträgen, Forumsdiskussionen und Blogbeiträgen.
LLM-basierte Screening-Methoden haben die gleichen Kosten- und Latenzprobleme, so dass wir herausfinden müssen, ob es Lösungen mit kleinen Modellen gibt:Wir brauchen kleinere, billigere Modelle, die dennoch mehrere Sprachen unterstützen.Dies ist ein entscheidender Faktor, da es keine Garantie dafür gibt, dass Fragen oder Unterlagen immer auf Chinesisch vorliegen.
Auf der einen Seite haben wir die Frage (die ursprüngliche Anfrage oder die Frage nach "schlechten Informationen") und auf der anderen Seite haben wir eine Menge Markdown-Inhalte, von denen viele irrelevant sind. Wir müssen die relevantesten Teile für die Frage heraussuchen. Das ist so ähnlich wie RAG Das Chunking-Problem, das die Community seit 2023 zu lösen versucht, indem sie das Retriever-Modell verwendet, um nur relevante Chunks abzurufen und sie in ein Kontextfenster für die Zusammenfassung zu stellen.
In unserer Situation gibt es jedoch zwei wesentliche Unterschiede:
-
Eine endliche Anzahl von Textblöcken in einer endlichen Anzahl von Dokumenten.
Wenn man davon ausgeht, dass jeder Block etwa 500 Token enthält, hat ein typisches langes Webdokument etwa 200.000 bis 1.000.000 Token (99. Perzentil). Wir verwenden Jina Reader, um 4-5 URLs auf einmal zu crawlen, was einige hundert Textblöcke erzeugt. Das bedeutet Hunderte von Vektoren und Hunderte von Kosinus-Ähnlichkeiten. Dies lässt sich mit JavaScript leicht im Speicher verarbeiten, und eine Vektordatenbank ist nicht erforderlich.
-
Wir brauchen zusammenhängende Textblöcke, um eine effektive Zusammenfassung des Wissens zu erstellen.
Wir können Zusammenfassungen wie [1-2, 6-7, 9, 14, 17, ...] nicht akzeptieren. Zusammenfassungen, die aus verstreuten Sätzen wie diesem bestehen. Eine sinnvollere Zusammenfassung des Wissens wäre etwas wie [3-15, 17-24, ...]. was die Kohärenz des Textes besser erhalten würde. Dies würde es dem LLM erleichtern, aus Wissensquellen zu kopieren und zu zitieren, und würde auch die Anzahl der "Illusionen" reduzieren.
Der Rest sind die gleichen Vorbehalte, über die sich Entwickler beschweren: Jeder Textblock darf nicht zu lang sein, weil das Vektormodell nicht mit einem zu langen Kontext umgehen kann; Chunking führt zum Verlust von Kontext und macht die Vektoren in jedem Textblock unabhängig und identisch verteilt; und wie zum Teufel findet man die optimalen Grenzen, die sowohl die Lesbarkeit als auch die Semantik erhalten? Wenn Sie wissen, wovon wir sprechen, dann haben Sie wahrscheinlich auch mit diesen Problemen in Ihren RAG-Implementierungen zu kämpfen.
Aber lange Rede, kurzer Sinn - verwenden Sie jina-einbettungen-v3
(in Form eines Nominalausdrucks) Spätes ChunkingSie löst alle drei Probleme perfekt. Die "späte Aufteilung" bewahrt die Kontextinformationen der einzelnen Blöcke, ist unempfindlich gegenüber Grenzen und jina-einbettungen-v3
selbst auf dem neuesten Stand der Technik bei asymmetrischen mehrsprachigen Retrievalaufgaben. Interessierte Leser können Jina's Blogpost oder Paper verfolgen, um Details über die gesamte Implementierung zu erfahren.
🔗 https://arxiv.org/pdf/2409.04701
Flussdiagramm der Fragmentauswahl anhand von späten Bewertungen
Diese Abbildung veranschaulicht den Zusammenfassungsauswahlalgorithmus, der wie eine eindimensionale Faltung (Conv1D) funktioniert. Das Verfahren unterteilt ein langes Dokument zunächst in Abschnitte fester Länge und verwendet dann eine für die späte Partitionierung aktivierte jina-einbettungen-v3
diese Textblöcke vektorisieren. Nach der Berechnung der Ähnlichkeitswerte zwischen jedem Block und der Frage wird ein gleitendes Fenster über diese Ähnlichkeitswerte bewegt, um das Fenster mit dem höchsten Durchschnitt zu finden.
Hier der schematische Code: Verwendung von Late Partitioning und Average Pooling, ähnlich der "1D-Faltung", um die für das Problem wichtigsten Passagen herauszufiltern.
function cherryPick(Frage, longContext, Optionen) {
if (longContext.length < options.snippetLength * options.numSnippets)
return longKontext; }
const chunks = splitIntoChunks(longContext, options.chunkSize);
const chunkEmbeddings = getEmbeddings(chunks, "Abruf.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 = [.
const similaritiesCopy = [. .similarities];
for (let i = 0; i < options.numSnippets; i++) {
let bestStartIndex = 0; let bestScore = -unendlich; let bestScore = -unendlich
let bestScore = -Infinity;
for (let j = 0; j bestScore) {
bestScore = windowScore; const windowScore = average(windowScores); if (windowScore > bestScore) {
bestStartIndex = j; }
}
}
const startIndex = bestStartIndex * options.chunkSize;
const endIndex = Math.min(startIndex + options.snippetLength, longContext.length); snippets.push(longContext.substring(startIndex, longContext.length)); }
snippets.push(longKontext.substring(startIndex, endIndex));
for (let k = bestStartIndex; k < bestStartIndex + chunksPerSnippet; k++)
similaritiesCopy[k] = -Infinity;
}
return snippets.join("\n\n");
}
Wenn Sie die Jina Embeddings API aufrufen, denken Sie daran, die Aufgabe
Auf Abruf eingestellt, öffnen Sie die spätes_Klingeln
(math.) Gattungabschneiden.
Richten Sie es auch wie folgt ein:
await axios.post(
'https://api.jina.ai/v1/embeddings',
{
model: "jina-embeddings-v3",
task: "abfrage.passage",
late_chunking: true,
Eingabe: chunks,
truncate: true
}, { headers })
{ headers });
Wenn das Problem vektorisiert werden soll, denken Sie daran, dass Sie Aufgabe
(etw.) gegen (etwas anderes) tauschen abruf.abfrage
Dann schalten Sie es aus. spätes_Klingeln
.
Der vollständige Implementierungscode ist auf GitHub zu finden:https://github.com/jina-ai/node-DeepResearch/blob/main/src/tools/jina-latechunk.ts
URL-Sortierung für "Weiter lesen"
Das Problem ist folgendes: In jedem langen DeepSearch-Prozess können Sie einen Haufen URLs von der Suchmaschinen-Ergebnisseite (SERP) sammeln, und jedes Mal, wenn Sie eine Webseite öffnen, können Sie eine Menge neuer Links auf dem Weg herausfinden, selbst nach der De-Emphasis sind es immer noch leicht ein paar hundert URLs. Die LLMs mit all diesen URLs vollzustopfen, wird nicht funktionieren, es ist eine Verschwendung wertvoller kontextueller Länge, und schlimmer noch, wir haben festgestellt, dass die LLMs im Grunde nur blind auswählen. Wir mussten also einen Weg finden, den LLM zu leiten, damit er die URLs auswählt, die am ehesten die Antwort enthalten.
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-Zusammenfassung: alle"
Dies ist der beste Weg, um Jina Reader für das Crawlen einer Seite in DeepSearch zu konfigurieren. Es werden alle Links auf der Seite herausgesucht, in das Links-Feld eingefügt und aus dem Inhaltsfeld gelöscht.
Man kann sich das wie einen "In-Context-PageRank" vorstellen, mit dem Unterschied, dass wir Hunderte von URLs in einer einzigen Sitzung bewerten.
Wir berücksichtigen mehrere Faktoren: Zeitpunkt der letzten Aktualisierung, Häufigkeit des Auftretens des Domänennamens, Struktur des Seitenpfads und vor allem die semantische Relevanz für die Frage, um einen zusammengesetzten Score zu berechnen. Wir können jedoch nur Informationen verwenden, die verfügbar sind, bevor wir überhaupt auf die URL klicken.
1. die FrequenzsignaleWenn eine URL mehrmals in verschiedenen Quellen erscheint, wird sie stärker gewichtet. Wenn ein Domänenname häufig in den Suchergebnissen auftaucht, erhalten URLs von dieser Domäne zusätzliche Punkte. Dies liegt daran, dass populäre Domains im Allgemeinen mehr maßgebliche Inhalte enthalten.
2. die Struktur der RouteWir analysieren die Pfadstruktur der URLs, um festzustellen, welche Inhalte in Gruppen zusammengefasst sind. Wenn mehrere URLs alle zur gleichen Pfadhierarchie gehören, erhalten sie eine höhere Punktzahl; je tiefer der Pfad jedoch ist, desto geringer wird der Punktebonus.
3. semantische Relevanz: Wir verwenden jina-reranker-v2-basis-mehrsprachig
die semantische Relevanz der Frage und die Textinformationen (z. B. Titel und Zusammenfassung) jeder URL zu bewerten, was ein typisches Umordnungsproblem darstellt. Die Textinformationen für jede URL stammen von mehreren Stellen:
-
Search Engine Results Page (SERP) API Gibt Titel und Zusammenfassung zurück (https://s.jina.ai/ Diese Schnittstelle mit "X-Respond-With": "no-content" gibt nur den Titel und die Zusammenfassung zurück, nicht den spezifischen Inhalt). -
Ankertext für URLs auf der Seite (die Verwendung der Schnittstelle https://r.jina.ai und die Einstellung "X-With-Links-Summary": "all" liefert zusammenfassende Informationen oder Ankertext für alle Links auf der Seite).
4. zuletzt aktualisiertEinige der DeepSearch-Abfragen haben hohe Anforderungen an die Aktualität, so dass im Allgemeinen der Wert umso höher ist, je neuer die URL ist. Ohne die umfangreichen Indexierungsmöglichkeiten von Google ist es jedoch schwierig, den Zeitpunkt der letzten Aktualisierung einer Webseite genau zu bestimmen. Wir verwenden eine Kombination aus den folgenden Signalen, um einen Zeitstempel mit einem Vertrauenswert zu erhalten, damit wir bei Bedarf vorrangig die neuesten Inhalte anzeigen können:
-
Filterfunktionen, die von der SERP-API bereitgestellt werden (z. B. der tbs-Parameter von s.jina.ai, der eine Filterung nach Zeit ermöglicht). -
Analyse der HTTP-Header-Informationen (z. B. Last-Modified- und ETag-Felder). -
Extraktion von Metadaten (z. B. Meta-Tags und Schema.org-Zeitstempel). -
Content Pattern Recognition (erkennt in HTML sichtbare Daten). -
Metriken für bestimmte CMS-Plattformen (z.B. WordPress, Drupal, Ghost, etc.)
5. eingeschränkte InhalteEinige soziale Medienplattformen haben Inhalte, deren Zugang eingeschränkt oder kostenpflichtig ist. Es gibt keine Möglichkeit, legal auf diese Inhalte zuzugreifen, ohne sich anzumelden. Daher führen wir aktiv eine schwarze Liste dieser problematischen URLs und Domains, wodurch ihre Rankings gesenkt werden und die Verschwendung von Computerressourcen für diese unzugänglichen Inhalte vermieden wird.
6. die Vielfalt der DomänennamenManchmal stammen die Top-URLs alle aus derselben Domäne, was dazu führen kann, dass DeepSearch in ein "lokales Optimum" fällt, was die Qualität der Endergebnisse beeinträchtigt. Wie bereits erwähnt, stammen die Top-URLs alle von StackOverflow. Um die Vielfalt der Ergebnisse zu erhöhen, können wir eine "Explore-and-Exploit"-Strategie anwenden: Wählen Sie die Top-K-URLs aus jeder Domain aus.
Die vollständige Code-Implementierung der URL-Sortierung finden Sie auf unserem Github: https://github.com/jina-ai/node-DeepResearch/blob/main/src/utils/url-tools.ts#L192
- Crawlen und Lesen des gesamten Inhalts von URLs, Sie können den Volltext, das Datum der letzten Aktualisierung usw. von jeder URL erhalten.
- Überprüfen Sie die in genannten URLs, falls vorhanden.
- Wählen Sie relevante URLs aus und besuchen Sie sie, um mehr zu erfahren. Eine höhere Gewichtung deutet auf eine höhere Relevanz hin.
<url-list
+ weight: 0.20 "https://huggingface.co/docs/datasets/en/loading": "Load - Hugging FaceDies spart Zeit, denn anstatt auf den Datensatz zu warten Dies spart Zeit, denn anstatt auf den Download des Dataset Builders zu warten, werden die Datensätze direkt im Cache gesucht. Setzen Sie die Umgebung .... Einige Datasets können mehr als eine Version haben, basierend auf Git-Tags, Zweigen oder Übertragungen. Verwenden Sie den Parameter revision, um die Version des Datasets anzugeben, die Sie laden möchten. laden möchten ..."
+ weight: 0.20 "https://huggingface.co/docs/datasets/en/index": "Datasets - Hugging Face🤗 Datasets ist eine Bibliothek für den einfachen Zugriff auf und die gemeinsame Nutzung von Datensätzen für Audio. Computer Vision- und Natural Language Processing (NLP)-Aufgaben. load a dataset in a ..."
+ Gewicht: 0.17 "https://github.com/huggingface/datasets/issues/7175": "[FSTimeoutError] load_dataset - Problem #7175 - huggingface/ datasetsWenn ich load_dataset verwende, um HuggingFaceM4/VQAv2 zu laden, erhalte ich FSTimeoutError. Fehler TimeoutError: Die obige Ausnahme war die direkte Ursache des Problems Die obige Ausnahme ist die direkte Ursache der folgenden ..."
+ weight: 0.15 "https://github.com/huggingface/datasets/issues/6465":"`load_dataset` verwendet einen veralteten Cache, anstatt einen .... neu herunterzuladen. Wenn ein Datensatz auf dem Hub aktualisiert wird, wird bei der Verwendung von load_dataset der lokal zwischengespeicherte Datensatz geladen, anstatt den aktualisierten Datensatz erneut herunterzuladen." + weight: 0.15 "":"`load_dataset` verwendet einen veralteten Cache, anstatt den aktualisierten Datensatz erneut herunterzuladen.
+ Gewichtung: 0.12 "https://stackoverflow.com/questions/76923802/hugging-face-http-request-on-data-from-parquet-format-when-the-only-way- to-get-i": "Umarmung Gesicht HTTP-Anfrage auf Daten aus Parkett-Format, wenn die . Ich musste die Daten aus ihrem Datenviewer mit der Parquet-Option holen, aber wenn ich versuche, es auszuführen, gibt es eine Art HTTP-Fehler. Ich habe versucht, ... "
</url-list
</action-visit
Zusammenfassungen
Seit der Veröffentlichung von Jina's DeepSearch am 2. Februar 2025 wurden zwei technische Details entdeckt, die die Qualität drastisch verbessern können.Interessanterweise nutzen beide Details mehrsprachige Embedding- und Rerankermodelle in einer Art "In-Context-Fenster".Das ist nichts im Vergleich zu den umfangreichen vorberechneten Indizes, die diese Modelle in der Regel erfordern.
Dies könnte ein Vorbote dafür sein, dass sich die Zukunft der Suchtechnologie in eine polarisierende Richtung bewegen wird. Wir können Kahnemans Theorie der dualen Prozesse heranziehen, um diesen Trend zu verstehen:
-
Denken Sie schnell. Schnelles Denken (grep, BM25, SQL): schneller, regelbasierter Mustervergleich mit minimalem Rechenaufwand. -
langsam denken Langsam-Denken (LLM): umfassende Schlussfolgerungen mit tiefem kontextuellem Verständnis, aber rechenintensiv. -
mittelBand Mittendrin denken (Embedding, Reranker et al. Recall Model): Verfügt über ein gewisses semantisches Verständnis, besser als einfacher Mustervergleich, aber weit weniger Inferenz als LLM.
Eine Möglichkeit ist:Zweistufige Sucharchitekturen werden immer beliebterDie leichtgewichtige, effiziente SQL/BM25 kümmert sich um die Eingabe des Abrufs und leitet die Ergebnisse dann direkt an den LLM für den Abruf der Ausgabe weiter. Der Restwert des Middle-Tier-Modells wird dann auf Aufgaben innerhalb eines bestimmten Kontextfensters verlagert: z. B. Filtern, Entdoppeln, Sortieren usw. In diesen Szenarien wäre es ineffizient, das komplette Reasoning stattdessen mit LLM durchzuführen.
Aber egal.Auswahl der wichtigsten Clips im Gesang antworten URL-Sortierung Nach wie vor ist es der grundlegende Aspekt, der die Qualität eines DeepSearch/DeepResearch-Systems direkt beeinflusst. Wir hoffen, dass unsere Erkenntnisse Ihnen helfen werden, Ihr eigenes System zu verbessern.
Die Erweiterung der Abfrage ist ein weiterer wichtiger Faktor bei der Bestimmung der Qualität.Gemüse.Wir evaluieren derzeit eine Vielzahl von Ansätzen, die von einfachen, auf Aufforderungen basierenden Umschreibungen über kleine Modelle bis hin zu inferenzbasierten Ansätzen reichen. Seien Sie gespannt auf unsere weiteren Forschungsergebnisse in dieser Richtung!