Maison >Périphériques technologiques >IA >Chunking tardif pour le chiffon: mise en œuvre avec Jina AI
Les applications de génération améliorée (RAG) de récupération ont toujours un compromis entre deux approches: intégrer l'ensemble du document pour un meilleur contexte, ou le décomposer en morceaux plus petits pour une récupération plus précise.
Emballage de l'ensemble du document peut capturer des informations globales, mais peut perdre des détails importants; tandis que les blocs plus courts peuvent préserver les détails, mais ignorer souvent le contexte global.
Le groupe retardé fournit une solution qui le divise en morceaux plus petits et plus faciles tout en maintenant le contexte complet du document.
Cet article introduira le regroupement retardé comme une meilleure alternative à la méthode de section naïve traditionnelle et démontre progressivement sa méthode de mise en œuvre.
Utiliser la génération améliorée de récupération (RAG) et Langchain pour intégrer des données externes avec des modèles de grande langue (LLM). Explorez les cours
Dans le pipeline de chiffons, les documents sont décomposés en morceaux plus petits avant d'être intégrés et stockés dans une base de données vectorielle. Chaque bloc est traité indépendamment et est utilisé pour la récupération au moment de la requête. Cependant, cette approche de «secteur naïf» perd souvent un contexte à longue distance important.
Le problème est que la méthode de section traditionnelle ne tient pas compte de la méthode d'information de l'association lors de la segmentation des documents. Par exemple, dans la documentation sur Paris, l'expression «cette ville» peut finir par être différente du bloc où se trouve «Paris». Sans contexte complet, le modèle de recherche peut être difficile à corréler ces références, ce qui entraîne des résultats inexacts. Dans de longs documents, les contextes critiques sont dispersés sur plusieurs sections, ce qui est encore plus grave.
Le groupe retardé résout ce problème en modifiant le temps pour diviser le document. Le set retardé n'est pas de diviser le document en morceaux en premier, mais d'intégrer l'ensemble du document à l'aide d'un modèle de contexte long. Ce n'est qu'après cela que cela divise le document en petits morceaux.
Principaux avantages du regroupement retardé:
En utilisant de longs modèles de contexte comme Jinai / Jina-Embeddings-V2-Base-en (en soutenant jusqu'à 8192 marques), le regroupement retardé permet d'intégrer efficacement les grandes pièces de texte avant qu'elles ne soient divisées en blocs.
Il s'agit d'un guide étape par étape pour mettre en œuvre un groupe retardé à l'aide du modèle d'intégration de contexte long de Jina. Vous pouvez obtenir gratuitement la clé d'API de Jina ici, et nous utiliserons le texte d'entrée suivant comme démonstration:
<code>input_text = """Berlin is the capital and largest city of Germany, both by area and by population. Its more than 3.85 million inhabitants make it the European Union's most populous city, as measured by population within city limits. The city is also one of the states of Germany, and is the third smallest state in the country in terms of area."""</code>
Tout d'abord, utilisez votre clé API Jina et la fonction d'assistance ci-dessous pour diviser le texte d'entrée en morceaux. Ces blocs sont livrés avec des annotations de span, ce qui aide à diviser les intégres de documents plus tard. L'API de Jina utilise des frontières naturelles telles que les ruptures de paragraphe ou de phrases pour garantir que le bloc est significatif et conserve sa signification.
<code>import json import requests def custom_tokenize_jina_api(input_text: str): url = '<https:></https:>' headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer ENTER_YOUR_JINA_API_KEY' } data = { "content": input_text, "tokenizer": "o200k_base", "return_tokens": "true", "return_chunks": "true", "max_chunk_length": "1000" } # Make the API request response = requests.post(url, headers=headers, json=data) response_data = response.json() chunks = response_data.get("chunks", []) i = 1 j = 1 span_annotations = [] for x in response_data['tokens']: if j == 1: j = len(x) else: j = len(x) + i span_annotations.append((i, j)) i = j return chunks, span_annotations chunks, span_annotations = custom_tokenize_jina_api(input_text) print(chunks) print(span_annotations)</code>
<code>['Berlin is the capital and largest city of Germany, both by area and by population.\n\n', "Its more than 3.85 million inhabitants make it the European Union's most populous city, as measured by population within city limits.\n\n", 'The city is also one of the states of Germany, and is the third smallest state in the country in terms of area.'] [(1, 17), (17, 44), (44, 69)]</code>
Tout d'abord, utilisez un tagger compatible avec le modèle de contexte long, tel que les intégres Embeddings-V2-Base-en, pour diviser l'ensemble du document en balises. Ensuite, créez des incorporations pour chaque balise en utilisant le modèle de convertisseur de contexte long. Cela signifie que chaque mot ou marqueur du document obtient son intégration unique pour capturer sa signification.
<code>from transformers import AutoModel from transformers import AutoTokenizer # load model and tokenizer tokenizer = AutoTokenizer.from_pretrained('jinaai/jina-embeddings-v2-base-en', trust_remote_code=True) model = AutoModel.from_pretrained('jinaai/jina-embeddings-v2-base-en', trust_remote_code=True) inputs = tokenizer(input_text, return_tensors='pt') model_output = model(**inputs) model_output[0].shape</code>
<code>torch.Size([1, 71, 768]) # 71 代表整个文档中的标记数</code>
Une fois que vous avez des incorporations de balises pour l'ensemble du document, vous pouvez faire un groupe retardé. Utilisez l'annotation de la portée à l'étape un pour diviser ces marques en morceaux plus petits. Ensuite, la mise en commun moyenne est appliquée à la moyenne des intégres dans chaque bloc, créant une seule intégration pour chaque bloc. Nous avons maintenant des incorporations de blocs qui contiennent les informations de contexte puissantes de l'ensemble du document.
<code>def late_chunking( model_output: 'BatchEncoding', span_annotation: list, max_length=None ): token_embeddings = model_output[0] outputs = [] for embeddings, annotations in zip(token_embeddings, span_annotation): if ( max_length is not None ): # remove annotations which go bejond the max-length of the model annotations = [ (start, min(end, max_length - 1)) for (start, end) in annotations if start = 1 ] pooled_embeddings = [ embedding.detach().cpu().numpy() for embedding in pooled_embeddings ] outputs.append(pooled_embeddings) return outputs</code>
<code>embeddings = late_chunking(model_output, [span_annotations])[0] len(embeddings)</code>
<code>3 # 与步骤 1 中的块数匹配</code>
pour comprendre les avantages du regroupement retardé, comparons-le à la chasse traditionnelle:
<code>embeddings_traditional_chunking = model.encode(chunks)</code>
<code>import numpy as np cos_sim = lambda x, y: np.dot(x, y) / (np.linalg.norm(x) * np.linalg.norm(y)) q = "Berlin" berlin_embedding = model.encode(q) print(q) print('\n') for chunk, new_embedding, trad_embeddings in zip(chunks, embeddings, embeddings_traditional_chunking): print(chunk.strip()) print(f'Late chunking:', cos_sim(berlin_embedding, new_embedding)) print(f'Traditional chunking:', cos_sim(berlin_embedding, trad_embeddings)) print("------------------------------------------------------------------")</code>
<code>Berlin Berlin is the capital and largest city of Germany, both by area and by population. Late chunking: 0.84954596 Traditional chunking: 0.84862185 ------------------------------------------------------------------ Its more than 3.85 million inhabitants make it the European Union's most populous city, as measured by population within city limits. Late chunking: 0.82489026 Traditional chunking: 0.70843375 ------------------------------------------------------------------ The city is also one of the states of Germany, and is the third smallest state in the country in terms of area. Late chunking: 0.84980094 Traditional chunking: 0.7534553 ------------------------------------------------------------------</code>
Comme vous pouvez le voir dans les deuxième et troisième blocs, le groupe traditionnel montre des scores de similitude de 70 à 75% par rapport au mot "Berlin". Cependant, en utilisant un morceau retardé (en maintenant le contexte de l'ensemble du document), ces scores sont passés à 82 à 84%. Cela suggère que le regroupement retardé fait un meilleur travail de préservation du contexte et de création d'incorporation plus significative, ce qui a donné des résultats de recherche plus précis.
Le regroupement retardé est une amélioration significative du système de récupération de documents, en particulier dans le pipeline de chiffons. Le groupe retardé préserve le contexte complet de chaque bloc en attendant que le document soit entièrement intégré avant de diviser le document. Cela conduit à des intérêts plus précis et significatifs.
Implémentez le chiffon avec Langchain pour créer un chatbot pour répondre aux questions sur la documentation technique. Explorez le projet
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!