Reclasser les résultats de recherche
Sur cette page
La recherche hybride ramène de bons candidats, mais pas toujours dans le bon ordre. Pour « Qu’a fait l’équipe d’ingénierie au sujet de l’incident INC-2023-Q4-011 ? », on attend la section ingénierie logicielle en tête, puisqu’elle parle de l’équipe et de l’incident ; le système peut pourtant placer la section cybersécurité devant. Le reclassement (reranking) ajoute une dernière étape : un modèle relit la question et chaque candidat, puis réordonne la liste.
Le principe
- La recherche hybride renvoie N candidats.
- Un modèle de reclassement juge la pertinence de chaque candidat pour la question.
- On garde les K meilleurs, que Claude lira pour répondre.
Dans l’étude d’Anthropic sur la récupération contextuelle, la recherche initiale renvoyait 150 morceaux, et le reclassement en gardait 20. Cette étape réduisait encore nettement les échecs de récupération (leçon 54).
Option 1 : Claude comme reclasseur
C’est l’approche de l’ancienne version du cours officiel : on donne à Claude la question et les candidats, et il renvoie les plus pertinents dans l’ordre. Deux précautions la rendent efficace.
Des identifiants plutôt que des textes. Faire recopier les passages retenus serait lent et coûteux en jetons de sortie. On attribue à chaque candidat un identifiant court, et Claude ne renvoie que la liste des identifiants.
Une sortie structurée. Le cours d’origine obtenait la liste par pré-remplissage et séquence d’arrêt, que les modèles actuels refusent (erreur 400). Les sorties structurées de la leçon 13 garantissent un objet {"document_ids": [...]}.
import json
SCHEMA_RERANK = {
"type": "object",
"properties": {"document_ids": {"type": "array", "items": {"type": "string"}}},
"required": ["document_ids"],
"additionalProperties": False,
}
def rerank_with_claude(docs, query, k):
by_id = {f"doc{i}": doc for i, doc in enumerate(docs)}
joined = "\n".join(
f"<document>\n<document_id>{doc_id}</document_id>\n"
f"<document_content>\n{doc['content']}\n</document_content>\n</document>"
for doc_id, doc in by_id.items()
)
prompt = (
"Trouve les documents les plus pertinents pour répondre à la question de l'utilisateur.\n\n"
f"<user_question>\n{query}\n</user_question>\n\n"
f"<documents>\n{joined}\n</documents>\n\n"
f"Renvoie les identifiants des {k} documents les plus pertinents, du plus au moins pertinent."
)
response = client.messages.create(
model=model,
max_tokens=4096,
messages=[{"role": "user", "content": prompt}],
output_config={"format": {"type": "json_schema", "schema": SCHEMA_RERANK}},
)
text = next(block.text for block in response.content if block.type == "text")
ids = json.loads(text)["document_ids"]
return [by_id[doc_id] for doc_id in ids if doc_id in by_id][:k]
Les identifiants sont créés au moment du reclassement : les documents indexés ne changent pas. Un identifiant inventé est ignoré, et la liste est tronquée à k. Le texte se lit en cherchant le bloc text, jamais avec content[0] : sur Sonnet 5.5, un bloc de réflexion peut précéder la réponse. Enfin, max_tokens est assez grand pour la réflexion, qui compte dans ce plafond.
query = "Qu'a fait l'équipe d'ingénierie au sujet de l'incident INC-2023-Q4-011 ?"
candidates = [doc for doc, _ in retriever.search(query, k=10)]
best = rerank_with_claude(candidates, query, k=3)
Option 2 : un modèle de reclassement dédié
Certains modèles sont entraînés pour cette seule tâche. Voyage AI en propose deux, accessibles avec la même clé que ses embeddings : rerank-3, le plus précis, et rerank-3-lite, plus rapide et moins cher.
def rerank_with_voyage(docs, query, k):
result = vo.rerank(query, [doc["content"] for doc in docs], model="rerank-3", top_k=k)
return [docs[r.index] for r in result.results]
Chaque résultat porte l’index du document dans la liste envoyée, le texte du document et un relevance_score. Un reclasseur dédié note tous les candidats en parallèle sans générer de texte, ce qui le rend adapté à des listes longues. L’étude d’Anthropic a utilisé le reclasseur de Cohere ; Voyage en propose aussi.
Le compromis
- Précision : le reclassement améliore l’ordre des résultats, et donc ce que Claude lit.
- Latence et coût : c’est une étape de plus à chaque question. Reclasser davantage de candidats améliore le résultat, mais allonge et renchérit l’étape. Anthropic recommande d’ajuster ce nombre sur votre propre cas d’usage.
À vous de jouer
Mesurer l’effet. Sur cinq questions, comparez les trois premiers résultats de la recherche hybride seule, puis reclassés par Claude, puis par rerank-3. Notez la latence de chaque variante et le nombre de fois où le bon passage arrive en tête.
Sources officielles : Contextual Retrieval (Anthropic : reclassement, 150 puis 20 morceaux) · Embeddings (documentation Claude : reclasseurs Voyage) · Structured outputs (documentation Claude)
Points clés à retenir
- Le reclassement relit la question et chaque candidat, puis réordonne la liste.
- Avec Claude : des identifiants courts, une sortie structurée, et le texte lu par type de bloc.
- Avec un modèle dédié comme
rerank-3: tous les candidats notés en parallèle, sans génération. - Dans l’étude d’Anthropic : 150 candidats, 20 gardés après reclassement.
- Le gain de précision se paie en latence et en coût : ajustez le nombre de candidats.