Aller au contenu
English

Assembler le contexte

  • Leçon 10
  • 45 min
  • Module 4 : Construire des réponses fondées sur les sources

Ce que vous saurez faire

Décidez quels passages accompagnent la question dans la requête (prompt). Placez les meilleurs en premier, retirez les copies et respectez un nombre fixe de jetons (tokens). Conservez aussi l’identifiant et la source de chaque passage. Ainsi, chaque réponse peut citer un passage, et chaque question coûte à peu près la même chose.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 45 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

  • ~/projects/policy-assistant après le module 3, avec .venv activé (source .venv/bin/activate, ou .venv\Scripts\Activate.ps1 dans PowerShell). python -m pytest affiche 48 passed (48 tests réussis).
  • L’index index.sqlite, créé par python -m policy_assistant ingest au module 3.
  • Si votre projet manque ou ne fonctionne plus, copiez l’instantané end-of-m03 en suivant les étapes de Utiliser un instantané, puis exécutez ingest.

Aucun compte ni aucune clé. Testé avec Python 3.12.13 sur macOS (puce Apple). Les commandes sont les mêmes dans Windows PowerShell; les étapes pour Windows n’ont pas été testées.

Les modèles changent vite. Les chiffres de ce module représentent un instant précis. C’est la méthode qui reste valable.

Certains examens permettent une page de notes. Vous ne pouvez pas y copier tout le manuel, alors vous faites des choix. Vous écrivez les notes qui répondent aux questions probables, sans écrire deux fois la même note. Vous placez les notes les plus importantes en haut, pour les trouver vite. À côté de chaque note, vous indiquez la page du livre pour montrer d’où elle vient.

L’assistant a la même tâche avant chaque réponse. La recherche a trouvé cinq passages. Quelqu’un doit maintenant décider quoi mettre sur la « page » que le modèle lit.

Le problème : pourquoi ne pas envoyer tous les documents?

Section intitulée « Le problème : pourquoi ne pas envoyer tous les documents? »

Tomás propose un raccourci. « La collection compte seulement 36 documents. Mettons-les tous dans la requête, chaque fois. Comme ça, le modèle ne peut rien manquer, et on n’a pas besoin de recherche. »

Amira ne conteste pas. Elle fait un test. Elle a envoyé 20 questions de Grace aux deux modèles de conversation, deux fois. La première fois, chaque question était accompagnée des 5 passages trouvés par la recherche. La deuxième fois, elle était accompagnée des 185 passages de la collection (résultats enregistrés sur Azure). Voici le résultat réel, selon la vérification automatique du cours :

Modèle Cinq passages de la recherche Toute la collection
chat-small (gpt-6-luna) 16 bonnes réponses sur 20 19 bonnes réponses sur 20
chat-strong (gpt-6.1-sol) 15 bonnes réponses sur 20 18 bonnes réponses sur 20

Avec cette petite collection, envoyer toute la collection a donné des réponses aussi bonnes ou meilleures. Le modèle a trouvé la réponse à Q13 : « Larkfield vend-elle des garanties prolongées? » Elle figure seulement dans un document français que la recherche a manqué. Tomás a raison aujourd’hui. Alors, quel est le problème avec son raccourci? Regardez ce que contient chaque requête.

Avec cinq passages de la recherche, la requête médiane contenait 905 jetons d'entrée. Avec les 185 passages, elle en contenait environ 17 850 : 20 fois plus, pour chaque question. Résultats enregistrés sur Azure.
Description textuelle du graphique

Un graphique à deux colonnes. Cinq passages de la recherche : une médiane de 905 jetons d’entrée par question (reclassement, ensemble des 67 questions). Les 185 passages de la collection : une médiane d’environ 17 850 jetons d’entrée par question (de 17 840 à 17 870, selon la longueur de la question; 20 questions). La deuxième colonne représente environ 20 fois la première. Les deux nombres proviennent du décompte de jetons du fournisseur et comprennent les instructions et la question.

Vingt fois plus de jetons signifie un coût d’entrée environ vingt fois plus élevé. Pour les 45 questions quotidiennes de Larkfield, voici le coût de chaque modèle (en dollars américains) :

Modèle Recherche, par jour Collection entière, par jour
chat-small 0,008 0.09
chat-strong 0,14 1,70

Ce sont de petites sommes pour 36 documents. Mais quatre choses changent à mesure que l’assistant grandit :

  • Échelle. 36 documents courts nécessitent déjà 17 850 jetons. Chaque nouvelle politique, chaque guide et chaque version alourdissent et ralentissent chaque question.
  • Accès. La collection entière contient les 6 procédures réservées au personnel. Avec tous les passages dans la requête, chat-small a répondu à Q01, sur une double facturation, à partir de la procédure interne : « Après confirmation des deux frais, Finance rembourse les frais supplémentaires dans les 3 jours ouvrables. » Un assistant destiné aux clients ne doit jamais envoyer au modèle des textes réservés au personnel pour un client.
  • Versions. Les deux politiques de retour, de 30 et de 45 jours, figurent dans chaque requête. Seule la lecture du modèle détermine laquelle s’applique.
  • Citations. Le modèle doit copier un identifiant parmi 185. Dans cet essai, il a produit la seule citation inventée du cours : c23617e24d2, un identifiant inexistant. Vous le retrouverez dans la prochaine leçon.

Le raccourci fonctionne donc aujourd’hui, mais échoue demain. Une longue fenêtre de contexte ne règle pas le problème : un modèle peut accepter bien plus de texte qu’il n’en lit correctement. Contexte et mémoire, dans le cours Les LLM : comment ils fonctionnent et comment en choisir un, a mesuré ce phénomène avec un manuel de produits.

Le contexte est le texte qui accompagne la question dans la requête : ici, les passages. Le budget de contexte est le nombre maximal de jetons que les passages peuvent utiliser. Assembler le contexte repose sur quatre règles :

  1. Gardez l’ordre de la recherche. Le meilleur passage vient en premier. Si un passage doit être retiré, c’est le plus faible.
  2. Retirez les quasi-doublons. Deux passages de documents différents qui utilisent presque les mêmes mots consomment deux fois le budget pour un seul fait.
  3. Respectez le budget. Un passage qui dépasse le budget reste à l’extérieur.
  4. Gardez l’identifiant et la source. Chaque passage entre dans la requête avec un en-tête : identifiant, titre, type, version, dates et section.

Le projet estime les jetons en divisant le nombre de caractères par 4. C’est approximatif, mais suffisant pour un budget; le fournisseur indique le décompte réel ensuite. Le budget de Larkfield est de 1 500 jetons estimés pour les passages.

Que signifie « presque les mêmes mots »? Le projet compare les ensembles de mots des deux passages, sans la ligne du titre. La proportion de mots communs est la similarité de Jaccard : les mots partagés divisés par tous les mots distincts des deux passages. Deux passages dont la similarité de Jaccard atteint 0,9 ou plus sont des quasi-doublons.

La question Q30 de Grace : « Quelle est la durée de la garantie sur la pompe d’une laveuse à pression? » La recherche reclassée donne ces 5 premiers passages, en date du 9 octobre 2026 :

Rang Identifiant du passage Document · section Jetons estimés
1 ff8235f48619 warranty-claims-procedure · Pompes de laveuses à pression (personnel) 104
2 d9a5bd8ea531 warranty-policy · Durées de garantie par catégorie de produits 314
3 50f5713033a7 product-care-pw2400 · Entreposage hivernal 92
4 08705a17f766 product-care-pw2200 · Entreposage hivernal 92
5 34a0b9b8055e product-care-pw2400 · Utilisation sécuritaire 107

Les passages 3 et 4 sont les sections Entreposage hivernal des guides PW-2400 et PW-2200. Sans leurs titres, les deux contiennent les mêmes 27 mots. Ils partagent donc 27 mots sur 27 mots distincts, et leur similarité de Jaccard est de 27 ÷ 27 = 1,0. Suivez maintenant les règles, un passage à la fois :

Un parcours des 5 premiers résultats de recherche de Q30 vers le contexte. Chaque passage, du meilleur au moins bon, passe par deux questions. Quasi-doublon? Oui pour 08705a17f766, le guide PW-2200, qui contient les mêmes mots que le guide PW-2400 : il est retiré. Respecte le budget de 1 500 jetons? Oui pour les quatre autres : ils sont conservés, chacun avec son en-tête. Le contexte contient 4 passages et 617 jetons estimés. Aucun passage n'est retiré à cause du budget ici.
Assemblage du contexte de Q30 selon les règles du projet. Un quasi-doublon est retiré; les quatre autres passages respectent le budget.
Description textuelle du diagramme

À gauche, les 5 premiers passages de la recherche reclassée pour Q30, avec leurs jetons estimés : 1 ff8235f48619, 104; 2 d9a5bd8ea531, 314; 3 50f5713033a7, 92; 4 08705a17f766, 92; 5 34a0b9b8055e, 107. Ils passent un par un, du meilleur au moins bon, à la première question : quasi-doublon d’un passage déjà conservé? Pour 08705a17f766, la réponse est oui : le guide PW-2200 dit mot pour mot ce que dit le guide PW-2400. Il est donc retiré. Les autres passent à la deuxième question : les jetons utilisés jusqu’ici, plus ce passage, respectent-ils la limite de 1 500? Les quatre la respectent. Chacun est donc conservé avec son en-tête (identifiant, titre, type, version, dates, section). Résultat : un contexte de 4 passages et 617 jetons estimés, le meilleur en premier. Aucun passage n’est retiré à cause du budget dans cet exemple.

Le passage 1 utilise 104 jetons, le passage 2 porte le total à 418, et le passage 3 à 510. Le passage 4 est un quasi-doublon du passage 3; il est donc retiré. Le passage 5 porte le total à 617. Le budget de 1 500 n’est pas atteint.

Le rang détermine quelle copie reste. Le guide PW-2400 occupe le 3e rang, alors il reste, même si les deux guides disent la même chose.

Le budget de 1 500 n’a rien changé pour Q30. Réduisez-le maintenant. Faites d’abord une prédiction, puis déplacez le curseur.

Explorer

Quels passages respectent le budget?

Budget
1 500 jetons
Utilisé
617 jetons
Passages dans la requête
4 sur 5
Passages avec la réponse
2 sur 2

Foncé : jetons utilisés par les passages de la requête. Clair : le budget entier. L’échelle s’arrête à 1 500 jetons.

Budget de 1 500 jetons : 4 sur 5 passages dans la requête, 617 jetons utilisés.

  1. Rang 1 : ff8235f48619 warranty-claims-procedure · Pressure washer pumps · personnel contient la réponse

    Pressure washer pumps - If the pump of a PW-2200 fails within 3 years, send the pump kit PK-2200-07 instead of a new p…

    104jetons

    Dans la requêtejetons 1 à 104

  2. Rang 2 : d9a5bd8ea531 warranty-policy · Warranty periods by product category contient la réponse

    Warranty periods by product category Product category | Examples | Warranty period | Exceptions Hand garden tools | sp…

    314jetons

    Dans la requêtejetons 105 à 418

  3. Rang 3 : 50f5713033a7 product-care-pw2400 · Winter storage

    Winter storage Drain all water from the pump and hoses before temperatures fall below 0 °C. Store it indoors, above 0…

    92jetons

    Dans la requêtejetons 419 à 510

  4. Rang 4 : 08705a17f766 product-care-pw2200 · Winter storage

    Winter storage Drain all water from the pump and hoses before temperatures fall below 0 °C. Store it indoors, above 0…

    92jetons

    Retiréquasi-doublon de 50f5713033a7

  5. Rang 5 : 34a0b9b8055e product-care-pw2400 · Using it safely

    Using it safely Never run the pressure washer for more than 2 minutes with the trigger released: the pump overheats. …

    107jetons

    Dans la requêtejetons 511 à 617

Les 5 premiers passages réels de Q30 (recherche reclassée), et ce que context.assemble() conserve pour chaque budget. Chaque état a été calculé par le code du projet.
Description textuelle de l’explorateur

L’outil d’exploration présente les cinq passages de Q30 dans l’ordre de recherche, avec leurs jetons estimés : 1 ff8235f48619, la procédure de réclamation de garantie (personnel), 104, contient la réponse; 2 d9a5bd8ea531, le tableau des garanties, 314, contient la réponse; 3 50f5713033a7, entreposage hivernal du PW-2400, 92; 4 08705a17f766, entreposage hivernal du PW-2200, 92, quasi-doublon du passage 3; 5 34a0b9b8055e, utilisation sécuritaire du PW-2400, 107. Un curseur règle le budget, de 100 à 1 000 jetons par pas de 50, puis à 1 500.

De 650 à 1 500, 4 passages entrent dans la requête (617 jetons); seul le quasi-doublon est retiré. À 550 et 600, le passage sur l’utilisation sécuritaire dépasse aussi le budget : 3 passages, 510 jetons. À 450 et 500, seuls les passages 1 et 2 entrent (418 jetons). À 350 et 400, les passages 1, 3 et 5 entrent (303 jetons) : le tableau des garanties ne respecte plus le budget, et des passages plus petits prennent sa place. De 200 à 300, les passages 1 et 3 entrent (196 jetons). À 150, seul le passage 1 entre. À 100, seul le passage 3 respecte le budget; aucun passage contenant la réponse ne reste.

À 300 jetons, le tableau des garanties est exclu. C’est le plus gros passage : après la procédure, il dépasse le budget. La règle « sautez ce qui dépasse, essayez le suivant » remplit alors l’espace avec le passage sur l’entreposage hivernal. Ce passage n’aide pas du tout. Pour un agent, la procédure interne indique encore « dans les 3 ans ». Pour un assistant destiné aux clients, le filtre d’accès retire cette procédure, et aucun passage contenant la réponse ne reste.

Un budget est donc une limite, pas un objectif. Il limite les coûts et le temps. Réglez-le pour que votre plus gros passage utile, ici un tableau, puisse toujours entrer.

L’en-tête : l’identifiant et la source accompagnent le texte

Section intitulée « L’en-tête : l’identifiant et la source accompagnent le texte »

Chaque passage entre dans la requête avec une ligne d’en-tête. Voici le passage 1 de Q30, exactement comme le modèle le voit :

[ff8235f48619] Warranty claims procedure | procedure, version 3, in force from 2026-01-01, no end date | section: Pressure washer pumps
Warranty claims procedure
Pressure washer pumps
- If the pump of a PW-2200 fails within 3 years, send the pump kit PK-2200-07 instead of a new pressure washer.
- For the PW-2400, send the pump kit PK-2400-03.
- Offer a technician visit only if the customer cannot fit the kit.

Chaque partie a un rôle :

  • L’identifiant entre crochets est ce que le modèle cite. La prochaine leçon vérifie chaque citation à partir de cet identifiant.
  • Le type (politique, procédure, article d’aide, contenu de fournisseur) compte quand deux documents se contredisent. La règle 2 de Larkfield dit qu’une politique l’emporte sur un article d’aide.
  • La version et les dates permettent au modèle de choisir la version en vigueur, et à une personne de vérifier ce choix.
  • La section indique à l’agent où chercher dans le document.

Sans l’en-tête, le modèle voit du texte anonyme. Il ne peut pas le citer, et personne ne peut vérifier la réponse.

La règle des quasi-doublons a une exception, et c’est la ligne de code la plus importante. Regardez les sections Délai de retour de la politique de retour, versions 3 et 4. Sans leurs titres, elles partagent 24 de leurs 26 mots distincts. Les deux seuls mots différents sont « 30 » et « 45 ». Leur similarité de Jaccard est de 24 ÷ 26 = 0,923, au-dessus de 0,9.

Une règle de quasi-doublons appliquée sans distinction supprimerait donc l’une des sections, et le mot supprimé serait toute la réponse. Le projet ne fusionne jamais deux passages du même document. Leurs différences sont essentielles, et le filtre de date du module 3 détermine déjà quelle version est en vigueur.

Amira a exécuté assemble() sur les 5 premiers passages reclassés de chacune des 67 questions. Les passages utilisaient une médiane de 501 jetons estimés, et un maximum de 871. Le budget de 1 500 n’a donc jamais retiré de passage parmi les 5 premiers. Seule Q30 a perdu un quasi-doublon. Avec les 10 premiers, la médiane était de 1 071 jetons, toujours sous le budget. Six questions ont perdu des quasi-doublons provenant des guides PW.

Le budget sert de protection. Il compte quand quelqu’un augmente le nombre de résultats, appelé top k, allonge les segments ou ajoute beaucoup de documents. Le coût et le temps par question restent alors les mêmes, et les passages les plus faibles sont retirés en premier.

Le projet reçoit un nouveau fichier, policy_assistant/context.py, et ses tests. Travaillez dans ~/projects/policy-assistant, avec .venv activé.

  1. Vérifiez le point de départ :

    Fenêtre de terminal
    python -m pytest

    La sortie se termine par 48 passed.

  2. Créez le fichier policy_assistant/context.py :

    policy_assistant/context.py
    """Assemble the context: choose the passages that go into the prompt, within a token budget.
    1. Keep the search order (the best passage first).
    2. Remove near-duplicates: two passages whose words are almost the same (Jaccard similarity of their
    word sets >= 0.9, title line left out), for example the same paragraph in the PW-2200 and PW-2400
    guides. The first (better-ranked) one stays. Two versions of the same document are NOT merged:
    their differences (30 days or 45 days) are the point, and the date filter decides between them.
    3. Stop before the budget is used up. Tokens are estimated as characters / 4 (good enough for a
    budget; the provider reports the real count).
    Every passage keeps its chunk ID and its source, so that the answer can cite it.
    """
    import math
    import re
    from dataclasses import dataclass, field
    BUDGET = 1500 # estimated tokens of passages per question
    SIMILAR = 0.9
    def estimate_tokens(text: str) -> int:
    return math.ceil(len(text) / 4)
    def word_set(text: str) -> set[str]:
    body = text.split("\n", 1)[1] if "\n" in text else text
    return set(re.findall(r"\w+", body.lower()))
    def jaccard(a: str, b: str) -> float:
    wa, wb = word_set(a), word_set(b)
    return len(wa & wb) / len(wa | wb) if wa | wb else 1.0
    def format_passage(chunk) -> str:
    dates = f"in force from {chunk.effective_from}" + (f" to {chunk.effective_to}" if chunk.effective_to else ", no end date")
    return (f"[{chunk.chunk_id}] {chunk.title} | {chunk.doc_type}, version {chunk.version}, {dates} | "
    f"section: {chunk.section or '-'}\n{chunk.text}")
    @dataclass
    class Context:
    chunks: list = field(default_factory=list)
    dropped: list = field(default_factory=list) # (chunk_id, reason)
    tokens: int = 0
    @property
    def ids(self) -> list[str]:
    return [c.chunk_id for c in self.chunks]
    def text(self) -> str:
    return "\n\n".join(format_passage(c) for c in self.chunks)
    def assemble(chunks: list, budget: int = BUDGET) -> Context:
    ctx = Context()
    for chunk in chunks:
    twin = next((c for c in ctx.chunks if c.doc_id != chunk.doc_id and jaccard(c.text, chunk.text) >= SIMILAR), None)
    if twin is not None:
    ctx.dropped.append((chunk.chunk_id, f"near-duplicate of {twin.chunk_id}"))
    continue
    cost = estimate_tokens(format_passage(chunk))
    if ctx.tokens + cost > budget:
    ctx.dropped.append((chunk.chunk_id, "over budget"))
    continue
    ctx.chunks.append(chunk)
    ctx.tokens += cost
    return ctx
    Ligne Signification
    text.split("\n", 1)[1] Exclut la première ligne, le titre du document. Sinon, les titres « PW-2200 » et « PW-2400 » feraient paraître différents deux paragraphes identiques.
    c.doc_id != chunk.doc_id Compare seulement les passages de documents différents : deux versions d’un même document ne sont jamais fusionnées.
    estimate_tokens(format_passage(chunk)) L’en-tête compte aussi : le modèle le lit.
    continue après « over budget » (budget dépassé) Saute le passage et essaie le suivant, plus petit. Vous avez vu l’effet à 300 jetons.
    ctx.dropped Tous les passages retirés, avec la raison. La prochaine leçon les affiche.
  3. Créez le fichier tests/test_context.py :

    tests/test_context.py
    from types import SimpleNamespace
    from policy_assistant.context import assemble, estimate_tokens, format_passage, jaccard
    def chunk(cid, doc_id, text, version="1"):
    return SimpleNamespace(chunk_id=cid, doc_id=doc_id, version=version, title="T", doc_type="guide",
    effective_from="2026-01-01", effective_to="", section="S", text=text)
    SAFETY = "Never run the pressure washer for more than 2 minutes with the trigger released: the pump overheats."
    def test_estimate_tokens():
    assert estimate_tokens("abcd" * 10) == 10
    def test_near_duplicates_from_two_documents_are_removed():
    a = chunk("a", "product-care-pw2200", "PW-2200 guide\n" + SAFETY)
    b = chunk("b", "product-care-pw2400", "PW-2400 guide\n" + SAFETY)
    assert jaccard(a.text, b.text) == 1.0 # the title line is left out
    ctx = assemble([a, b])
    assert ctx.ids == ["a"] and ctx.dropped == [("b", "near-duplicate of a")]
    def test_two_versions_of_one_document_are_both_kept():
    v3 = chunk("v3", "returns-policy", "Returns\nYou can return an unused item within 30 days.", "3")
    v4 = chunk("v4", "returns-policy", "Returns\nYou can return an unused item within 30 days.", "4")
    assert assemble([v3, v4]).ids == ["v3", "v4"]
    def test_budget():
    chunks = [chunk(str(i), f"d{i}", " ".join(f"w{i}x{j}" for j in range(200))) for i in range(5)]
    cost = estimate_tokens(format_passage(chunks[0])) # 342 estimated tokens per passage
    ctx = assemble(chunks, budget=2 * cost + 10)
    assert len(ctx.ids) == 2 and ctx.tokens == 2 * cost
    assert [reason for _, reason in ctx.dropped] == ["over budget"] * 3
    def test_a_passage_shows_its_id_dates_and_type():
    text = format_passage(chunk("3fa9c2d1b0e4", "d", "Title\nbody"))
    assert text.startswith("[3fa9c2d1b0e4] T | guide, version 1, in force from 2026-01-01, no end date | section: S\n")

    Les tests utilisent de petits passages inventés (SimpleNamespace), alors ils n’ont pas besoin d’index. Le test des versions utilise volontairement le même texte deux fois : même les versions identiques restent.

  4. Exécutez les nouveaux tests, puis tous les tests :

    Fenêtre de terminal
    python -m pytest tests/test_context.py
    python -m pytest

    La première sortie se termine par 5 passed (5 tests réussis), et la deuxième par 53 passed (53 tests réussis).

  5. Lancez python dans le dossier du projet, et assemblez le contexte de Q30. Les premières lignes chargent les deux modèles locaux, comme le fait search :

    Python, in ~/projects/policy-assistant
    from policy_assistant.store import Store
    from policy_assistant.embed import LocalEmbedder
    from policy_assistant.rerank import Reranker
    from policy_assistant.search import Retriever
    from policy_assistant.filters import Filters
    from policy_assistant.context import assemble, estimate_tokens, format_passage
    retriever = Retriever(Store("index.sqlite"), LocalEmbedder(), Reranker())
    question = "How long is the warranty on the pump of a pressure washer?"
    results = retriever.search(question, method="rerank", k=5, filters=Filters(as_of="2026-10-09", audience="staff"))
    for r in results:
    print(r.chunk.chunk_id, r.chunk.doc_id, estimate_tokens(format_passage(r.chunk)))
    context = assemble([r.chunk for r in results])
    print(context.ids, context.tokens)
    print(context.dropped)

    Appuyez sur Entrée sur la ligne vide après la boucle for. Python peut aussi afficher des lignes sur le chargement des modèles. La sortie :

    ff8235f48619 warranty-claims-procedure 104
    d9a5bd8ea531 warranty-policy 314
    50f5713033a7 product-care-pw2400 92
    08705a17f766 product-care-pw2200 92
    34a0b9b8055e product-care-pw2400 107
    ['ff8235f48619', 'd9a5bd8ea531', '50f5713033a7', '34a0b9b8055e'] 617
    [('08705a17f766', 'near-duplicate of 50f5713033a7')]

    Ce sont les chiffres du diagramme. Gardez Python ouvert pour la prochaine section.

Faites d’abord une prédiction : avec budget=300, quels identifiants assemble() conserve-t-il pour Q30, et pourquoi retire-t-il les autres? Tapez ensuite ceci dans la même session Python :

Python (continued)
small = assemble([r.chunk for r in results], budget=300)
print(small.ids, small.tokens)
print(small.dropped)
Afficher la réponse
['ff8235f48619', '50f5713033a7'] 196
[('d9a5bd8ea531', 'over budget'), ('08705a17f766', 'near-duplicate of 50f5713033a7'), ('34a0b9b8055e', 'over budget')]

Le tableau des garanties (314 jetons) dépasse le budget après la procédure (104); il est donc sauté. Le passage sur l’entreposage hivernal (92) respecte encore le budget, alors il prend l’espace. Sa copie PW-2200 est retirée comme quasi-doublon, et le passage sur l’utilisation sécuritaire (107) porterait le total à 303. Le contexte contient maintenant la procédure interne, qui indique « dans les 3 ans », et un passage sur le gel. Un assistant destiné aux clients ne verrait pas la procédure; il n’aurait donc aucune réponse. Quittez Python avec exit().

Utilisez un budget pour chaque appel au modèle qui contient du texte récupéré. Il rend le coût et la durée d’une question prévisibles. Il élimine d’abord les passages les plus faibles, plutôt que des passages au hasard.

Mettre toute la collection dans une seule requête est un choix raisonnable dans un cas. La collection est petite et ne grandit pas. Elle n’a ni étiquettes d’accès ni versions, et le coût par question n’a pas d’importance. La collection de Larkfield ne remplit pas trois de ces conditions.

Ce que le budget vous coûte :

  • Il peut éliminer la réponse. Un budget inférieur à votre plus grand passage utile, ici le tableau de garantie, l’élimine. Vérifiez la taille de vos tableaux.
  • L’estimation est approximative. La formule caractères ÷ 4 convient au texte anglais. Le texte français, les codes de produits et les identifiants utilisent plus de jetons par caractère. Gardez une marge.
  • La règle des quasi-doublons peut se tromper. Elle compare les mots, pas le sens. Deux courts passages de documents différents peuvent sembler identiques même si un nombre important diffère. Les sections Parts (pièces) des guides PW ne diffèrent que par les numéros de pièces. Leur similarité est de 0,818 : sous 0,9, donc les deux restent. Vérifiez le seuil avec vos propres documents.

Erreur courante

La règle des quasi-doublons qui a supprimé la nouvelle politique

Symptôme : Tomás simplifie assemble() : « Pourquoi seulement entre documents? Une copie, c’est une copie. » Il retire c.doc_id != chunk.doc_id. Un test échoue : test_two_versions_of_one_document_are_both_kept. Il trouve le test trop strict et le supprime. Désormais, quand le filtre de date est désactivé, une question sur les retours peut perdre un des deux passages Return window (délai de retour). Aucun message ne prévient qui que ce soit.

Cause : les sections Return window des versions 3 et 4 ont une similarité de Jaccard de 0,923. La règle modifiée élimine le deuxième passage comme quasi-doublon. Le modèle voit seulement la version classée en premier. La date ne décide donc plus.

Correction : ne fusionnez jamais deux passages du même document. Gardez le test et ajoutez un cas réel : les passages Return window des versions 3 et 4 doivent rester. Laissez le filtre de date choisir la version, pas un score de similarité.

Ce que cela signifie pour un vrai service d’IA : une règle qui retire les « copies » doit savoir ce qu’est une copie. Dans les documents versionnés, les petites différences constituent le contenu.

Vérifiez votre compréhension

Pour ces 20 questions, la collection entière dans la requête a donné des réponses aussi bonnes que la recherche, ou meilleures. Donnez deux raisons pour lesquelles Larkfield utilise quand même la recherche avec un budget.

Afficher la réponse

Deux raisons parmi les suivantes. Le coût : environ 17 850 jetons d’entrée par question au lieu d’environ 900. Pour chat-strong, à 45 questions par jour, cela représente 1,70 $ US au lieu de 0,14 $ US. Ce coût augmente avec chaque document. L’accès : le modèle reçoit les procédures réservées au personnel pour chaque question. chat-small a répondu à Q01 à partir de la procédure du personnel. Les versions : les deux politiques de retour sont toujours dans la requête. Seule la lecture du modèle détermine le choix. Les citations : avec 185 identifiants, le modèle a inventé une citation (c23617e24d2). Le résultat obtenu sur 36 documents ne tient pas pour une collection qui grandit.

Vérifiez votre compréhension

Prédisez : les 5 premiers résultats d'une question contiennent les passages Return window des versions 3 et 4 (Jaccard 0,923). Le filtre de date est désactivé. Que conserve assemble(), et pourquoi?

Afficher la réponse

Il conserve les deux, s’ils respectent le budget. La règle des quasi-doublons compare seulement les passages de documents différents. Ces deux passages appartiennent à la politique de retour. Les seuls mots qui diffèrent, 30 et 45, constituent la réponse. Chaque passage conserve son en-tête avec sa version et ses dates. Le modèle et une personne peuvent donc voir quelle version s’applique.

Vérifiez votre compréhension

Pourquoi chaque passage entre-t-il dans la requête avec un en-tête contenant son identifiant, son type, sa version, ses dates et sa section?

Afficher la réponse

L’identifiant permet au modèle de citer le passage et au code de vérifier la citation. Le type indique quel document l’emporte quand deux documents se contredisent. Une politique l’emporte sur un article d’aide. La version et les dates indiquent quelle version est en vigueur à la date de la question. La section indique à l’agent où chercher. Sans l’en-tête, le texte est anonyme : la réponse ne peut pas le citer et personne ne peut le vérifier.

Récapitulatif

  • Le contexte est le texte qui entre dans la requête avec la question. Le budget de contexte le limite : celui de Larkfield est de 1 500 jetons estimés (caractères ÷ 4).
  • assemble() conserve l’ordre de recherche et élimine les quasi-doublons de documents différents (similarité de Jaccard de 0,9 ou plus). Il ignore les passages qui dépassent le budget. Il conserve l’en-tête de chaque passage : identifiant, titre, type, version, dates et section.
  • Deux versions d’un même document ne sont jamais fusionnées : les versions 3 et 4 diffèrent seulement par « 30 » et « 45 ».
  • La collection entière dans une seule requête a donné des réponses aussi bonnes sur 36 documents. Elle a consommé 20 fois plus de jetons et inclus du texte réservé au personnel dans chaque requête. Elle a aussi produit une citation inventée. Cette approche ne passe pas à l’échelle.
  • Un budget trop petit peut éliminer le meilleur passage. Prévoyez assez de place pour votre plus grand passage utile.

Ensuite, vous demandez au modèle une réponse composée d’affirmations, chacune accompagnée des identifiants de ses passages. Vous vérifiez chaque citation dans le code.

Leçon suivante : Répondre et citer