Retrieval contextuel
Sur cette page
Découper un document a un coût caché : chaque morceau perd son lien avec l’ensemble. « Le chiffre a progressé de 3 % » ne dit plus de quelle entreprise, de quel trimestre, de quel indicateur il parle. Le retrieval contextuel répare cette perte : avant d’indexer chaque morceau, on demande à Claude d’écrire quelques phrases qui le situent dans le document.
Le principe
Pour chaque morceau, on envoie à Claude le document source et le morceau, avec une consigne du type : « Écris un contexte court et précis qui situe ce passage dans l’ensemble du document, afin d’améliorer sa récupération. Réponds uniquement par ce contexte. »
Claude peut répondre par exemple : « Cette section fait partie d’un rapport annuel de recherche interdisciplinaire. Elle mentionne l’incident INC-2023-Q4-011, également traité dans la section d’analyse de cybersécurité. » On colle ce contexte devant le morceau, et c’est ce morceau contextualisé qu’on indexe, dans l’index vectoriel comme dans BM25.
Selon l’article d’Anthropic qui a présenté la technique, les embeddings contextuels réduisent de 35 % les échecs de récupération parmi les 20 premiers résultats ; 49 % en y ajoutant BM25 contextuel, et 67 % avec un reranking en plus.
Le code, avec le cache de prompts
Le document entier est envoyé une fois par morceau : sans précaution, on paierait sa lecture autant de fois qu’il y a de morceaux. Le cache de prompts de Bedrock règle le problème. On place le document en premier, suivi d’un point de cache cachePoint, puis la partie propre à chaque morceau :
def situate_chunk(document, chunk):
response = client.converse(
modelId=model_id,
messages=[{
"role": "user",
"content": [
{"text": f"<document>\n{document}\n</document>"},
{"cachePoint": {"type": "default"}},
{"text": (
f"Voici le passage à situer dans ce document :\n<chunk>\n{chunk}\n</chunk>\n\n"
"Écris un contexte court et précis qui situe ce passage dans l'ensemble du document, "
"afin d'améliorer sa récupération lors d'une recherche. "
"Réponds uniquement par ce contexte."
)},
],
}],
)
content = response["output"]["message"]["content"]
context = "".join(block["text"] for block in content if "text" in block)
return f"{context}\n\n{chunk}"
for chunk in chunks:
retriever.add_document({"content": situate_chunk(text, chunk)})
Tout ce qui précède le cachePoint est mis en cache au premier appel ; les appels suivants, qui commencent par le même document, le relisent depuis le cache, plus vite et moins cher. Sur Claude Haiku 5.5, un point de cache demande au moins 512 tokens avant lui, et le cache dure 5 minutes par défaut, prolongées à chaque utilisation. Le champ usage de la réponse indique les tokens lus et écrits dans le cache (cacheReadInputTokens, cacheWriteInputTokens). La section 6 détaille le cache.
Les documents trop longs
Si le document source est trop long pour un prompt, le cours officiel propose de fournir un contexte réduit : quelques morceaux du début, qui contiennent souvent un résumé, et les morceaux qui précèdent immédiatement celui qu’on situe.
def local_context(chunks, i, num_start=2, num_prev=2):
start = chunks[:num_start]
previous = chunks[max(num_start, i - num_prev):i]
return "\n\n".join(start + previous)
for i, chunk in enumerate(chunks):
retriever.add_document({"content": situate_chunk(local_context(chunks, i), chunk)})
max(num_start, ...) évite de répéter un morceau déjà présent dans le début du document, un doublon que produit le code du cours officiel. Ici, le contexte change à chaque morceau : le cache ne sert plus, puisqu’aucun préfixe n’est commun.
Ce qu’il faut en attendre
Sur un document simple, le gain reste modeste. La technique prend toute sa valeur avec des documents complexes, pleins de renvois entre sections et de passages qui ne se comprennent qu’avec leur contexte. Elle a un coût : un appel à Claude par morceau à l’indexation, que le cache atténue.
À vous de jouer
Avant, après. Indexez votre document deux fois, avec et sans contexte, dans deux Retriever. Pour les cinq questions de la leçon 41, comparez le rang de la bonne section. Affichez aussi usage pour le deuxième appel à situate_chunk : le cache a-t-il servi ?
Sources officielles : Contextual retrieval (Claude Academy) · Contextual Retrieval (Anthropic) · Prompt caching for faster model inference et fiche Claude Haiku 5.5 (documentation AWS)
Points clés à retenir
- Un morceau isolé perd son contexte ; Claude écrit quelques phrases qui le situent avant l’indexation.
- On indexe le morceau contextualisé, dans l’index vectoriel comme dans BM25.
- Selon Anthropic : 35 % d’échecs de récupération en moins, 49 % avec BM25, 67 % avec un reranking.
- Le document en premier puis un
cachePoint: sa lecture est mise en cache pour tous les morceaux. - Document trop long : le début et les morceaux précédents suffisent comme contexte.