Comment savoir si un RAG est bon
Séparer l'évaluation d'un RAG en deux moitiés, la recherche et la réponse. Pour la recherche, le taux de réussite ; pour la réponse, un autre modèle comme juge, qui compare à une réponse de référence pour juger l'exactitude et aux documents pour juger la fidélité. Le juge a rendu 60 verdicts, je les ai vérifiés un par un, et il se trompe lui aussi.
- Environ 45 minutes
- Niveau : Intermédiaire
- Testé : 2026-09-14 deepseek-flash, deepseek-v4-pro (juge)
Le code et les sorties des programmes sont reproduits tels qu’ils ont tourné : commentaires et sorties sont donc en chinois.
Jusqu'ici, nous n'avons évalué que « la recherche a-t-elle trouvé juste ? ». Mais ce que l'utilisateur voit au final, c'est la réponse. La recherche peut être parfaite et la réponse fausse : le modèle peut avoir mal lu les documents, mélangé deux passages, ou ajouté malgré lui ses propres « connaissances ». À l'inverse, même si la recherche n'a pas trouvé le passage le plus exact, la réponse peut être juste.
L'évaluation d'un RAG se divise donc en deux moitiés : la recherche, et la réponse. Cette leçon montre comment faire les deux, en insistant sur l'évaluation des réponses et l'un de ses grands pièges.
Évaluer les deux moitiés séparément
Évaluer séparément permet, en cas de problème, de savoir où réparer :
| Recherche | Réponse | Signification | Où réparer |
|---|---|---|---|
| Juste | Juste | Normal | |
| Fausse | Fausse | Documents non trouvés, le modèle ne peut pas répondre juste | La recherche : découpage, réécriture, méthode de recherche |
| Juste | Fausse | Bons documents fournis, mal utilisés par le modèle | La génération : prompt, modèle |
| Fausse | Juste | Le modèle a peut-être répondu juste de mémoire | Vérifier s'il a enfreint « uniquement d'après les documents » |
En ne regardant que la justesse de la réponse finale, on ne distingue pas le deuxième cas du troisième, et on modifie au hasard.
L'évaluation de la recherche est déjà faite : taux de réussite et MRR de la leçon 3. Cette leçon évalue les réponses.
Ce qu'on évalue dans une réponse
Pour les réponses d'un RAG, on regarde le plus souvent deux choses :
- L'exactitude : la réponse est-elle juste ? Il faut une réponse de référence pour comparer.
- La fidélité : chaque affirmation de la réponse trouve-t-elle un appui dans les documents récupérés ? Elle ne se soucie pas de savoir si la réponse est juste, seulement si elle « sort du cadre ».
On évalue la fidélité à part parce qu'elle révèle un problème sournois : une réponse juste par hasard, mais fondée sur la mémoire du modèle plutôt que sur les documents. Juste cette fois, fausse peut-être la prochaine, et impossible à retracer.
Préparer les réponses de référence
J'ai écrit une réponse de référence pour chacune des 20 questions de la leçon 3, chacune d'après le passage d'origine utilisé pour l'évaluation de la recherche, par exemple :
{"question": "怎么关闭 SSL 证书校验?", ..., "reference": "传 verify=False,比如 httpx.get(url, verify=False);用 Client 时在创建客户端时传入。"}
{"question": "httpx 和 requests 在处理重定向上有什么不一样?", ..., "reference": "requests 默认跟随重定向,httpx 默认不跟随;httpx 要显式传 follow_redirects=True(单个请求或 Client 上都可以)。"}
Une réponse de référence n'a pas besoin d'être longue : il suffit d'écrire clairement les points qui doivent y figurer. Mais on va voir que la façon de l'écrire influence directement la notation.
Un modèle comme juge
Pour 20 questions avec chacune deux réponses (une sans documents, une avec RAG), juger à la main une par une est fastidieux. La méthode courante consiste à faire juger par un autre modèle, un modèle juge (LLM-as-a-judge). Le juge est le plus fort deepseek-v4-pro, avec la réflexion activée :
def judge_correct(question, reference, answer):
return judge(f"""判断"回答"是否正确地回答了"问题"。以"参考答案"为准:回答包含参考答案的要点、且没有和它矛盾的内容,就算正确。
回答比参考答案多说了一些内容没关系,只要多说的部分没有错误。
输出 json:{{"correct": true 或 false, "reason": "一句话理由"}}
问题:{question}
参考答案:{reference}
回答:{answer}""")
def judge_faithful(context, answer):
return judge(f"""判断"回答"里的每一个事实性说法,是否都能在"资料"里找到依据。
回答说"资料里没有"之类的话不算事实性说法。只要有一处说法在资料里找不到依据,就判为不忠实。
输出 json:{{"faithful": true 或 false, "unsupported": "找不到依据的说法,没有就写空字符串"}}
资料:
{context}
回答:{answer}""")
Quelques choix de conception :
- Le juge et le jugé ne sont pas le même modèle. Un modèle qui se note lui-même ferme facilement les yeux sur ses propres erreurs.
- Exiger une justification. Pas seulement true ou false, mais une phrase qui explique pourquoi. Vous verrez plus loin que la justification est le seul indice pour repérer les erreurs du juge.
- Des critères écrits clairement. La phrase « en dire plus n'est pas grave, tant que ce qui est en plus n'est pas faux » évite que le juge considère une réponse comme fausse parce qu'elle est plus détaillée que la réponse de référence.
La fonction judge appelle le juge en mode JSON, comme à la leçon 4 du module 02. Code complet dans code/04-rag/rag_eval.py ; une exécution fait environ 80 appels, pour environ 0,1 dollar.
Les verdicts du juge
不查资料:答对 15/20
RAG: 答对 19/20,忠实于资料 19/20
[不查资料答错] 响应是 404 或 500 时,怎么让它直接抛异常?
评委:回答中“3xx不会抛”与参考答案“状态码不是2xx时会抛出”矛盾
[不查资料答错] httpx 和 requests 在处理重定向上有什么不一样?
评委:回答错误地声称httpx默认跟随重定向,与参考答案中“httpx默认不跟随”相矛盾。
[不查资料答错] 怎么限制连接池里最多同时有多少个连接?
评委:回答遗漏了参考答案中默认 max_connections=100 这一要点,未完整包含参考答案的默认值信息。
[不查资料答错] 怎么显示下载进度?
评委:回答未使用参考答案中的 response.num_bytes_downloaded 属性,而是手动累计长度
[不查资料答错] 网页返回的中文是乱码,怎么指定解码用的字符集?
评委:回答未提及参考答案中的 default_encoding 参数指定字符集的方法
[RAG 答错] httpx 和 requests 在处理重定向上有什么不一样?
评委:回答中关于 requests 暴露的属性 response.next 的描述有误,requests 并没有该属性。
[RAG 不忠实] 怎么显示下载进度?
找不到依据:显示下载进度需要用流式响应(streaming),并检查 `response.num_bytes_downloaded` 属性
La conclusion semble claire : le RAG fait passer l'exactitude de 15/20 à 19/20. Mais ne concluons pas trop vite. Pour chaque « réponse fausse », j'ai regardé la réponse brute et vérifié dans la documentation et le code source de httpx.
Vérifier le juge, verdict par verdict
« Les 3xx ne lèvent pas d'exception » : le juge a raison. La réponse sans documents dit que raise_for_status() ne lève pas d'exception pour un 3xx. Dans le code source de httpx, _models.py, raise_for_status lève une HTTPStatusError dès que ce n'est pas un 2xx (is_success faux), et le type d'erreur d'un 3xx s'appelle « Redirect response ». La réponse est donc bien fausse.
Redirections : la réponse sans documents est fausse, le juge a raison. Elle affirme encore que httpx suit les redirections par défaut, et même « par défaut depuis la 0.20+ », exactement l'erreur de RepoBot v1.
Pool de connexions : le juge est trop sévère. La réponse sans documents indique correctement d'utiliser httpx.Limits(max_connections=..., max_keepalive_connections=...), sans préciser que la valeur par défaut est 100. L'utilisateur demandait « comment limiter », pas la valeur par défaut. Le problème vient de ma réponse de référence, où j'avais écrit au passage « 100 connexions au plus par défaut », et le juge en a fait un point obligatoire.
Progression du téléchargement : le juge a de bonnes raisons. La réponse sans documents additionne à la main les octets téléchargés avec len(chunk). La documentation de httpx précise que, avec la compression activée, la longueur du contenu décompressé ne correspond pas aux octets réellement téléchargés, et qu'il faut utiliser response.num_bytes_downloaded. La méthode de la réponse fonctionne sans compression, mais ce n'est pas la bonne.
Encodage : le juge se trompe. La réponse sans documents dit : avant d'accéder à response.text, définir response.encoding = "gbk". J'ai vérifié dans le code source de httpx : Response.encoding a un setter qui permet de définir l'encodage avant de lire text (le définir après lève une ValueError). C'est une autre méthode parfaitement correcte. Le juge la déclare fausse parce qu'elle « ne mentionne pas le default_encoding de la réponse de référence » : il a pris la réponse de référence pour la seule bonne réponse.
Réponse RAG sur les redirections : le juge se trompe. Le juge affirme que « requests n'a pas d'attribut response.next ». Or la ligne 50 de compatibility.md, dans la documentation de httpx, dit textuellement : « The requests library exposes an attribute response.next, which can be used to obtain the next redirect request. » La réponse RAG suit la documentation et est juste. Le juge n'a pas regardé les documents et a jugé de mémoire, une mémoire erronée.
Progression du téléchargement en RAG : le « non fidèle » est faux. J'ai relancé la recherche pour cette question : les deux premiers morceaux viennent de advanced/clients.md et contiennent tous deux num_bytes_downloaded, le texte disant justement d'utiliser une réponse en streaming et de consulter cet attribut. La réponse est entièrement fidèle aux documents ; le juge n'a pas lu attentivement.
Le résultat après vérification
| Selon le juge | Après ma vérification | |
|---|---|---|
| Sans documents | 15/20 justes | 17/20 justes |
| RAG | 19/20 justes | 20/20 justes |
| Fidélité du RAG | 19/20 | 20/20 |
Le sens de la conclusion ne change pas : le RAG est nettement meilleur que la réponse sans documents, qui commet deux vraies erreurs. Mais les chiffres exacts changent, et sur 60 verdicts, le juge s'est trompé 3 fois et a été trop sévère une fois.
Ces 4 problèmes se rangent en deux catégories :
- Le juge n'utilise pas le matériau fourni, mais ses propres connaissances. C'est le cas de
response.next. Le juge est lui aussi un grand modèle, et il peut se souvenir de travers. - La réponse de référence est prise pour la seule réponse. Les questions sur l'encodage et le pool de connexions. Quand il existe plusieurs méthodes correctes et que la référence n'en donne qu'une, le juge déclare fausses les autres méthodes correctes.
Rendre le juge plus fiable
- Toujours vérifier par sondage. Les verdicts du juge ne sont pas une conclusion en soi. Vérifiez au moins à la main toutes les « erreurs », puis quelques « justes » tirés au hasard.
- Exiger une justification du juge. C'est grâce aux justifications qu'on a trouvé les problèmes. « requests n'a pas cet attribut » paraît suspect d'emblée, et une vérification montre que le juge se trompe.
- Écrire les points clés dans la référence, et accepter d'autres méthodes correctes. Préciser dans le prompt que « d'autres méthodes correctes que la réponse de référence comptent aussi comme justes ». Ne mettre dans la référence que ce que la question demande vraiment.
- Le juge de fidélité doit regarder les documents. Insister dans le prompt : « juge uniquement d'après les documents, n'utilise pas tes propres connaissances ».
- Calibrer le juge avec des annotations humaines. Annotez à la main quelques dizaines de cas, mesurez l'accord entre le juge et l'humain, et si l'accord est trop faible, modifiez le prompt du juge. La leçon 2 du module 06 traite cela de façon systématique.
Conclusions de cette leçon
- L'évaluation d'un RAG se sépare en recherche et réponse ; c'est en les séparant qu'on sait où est le problème.
- Pour les réponses, on regarde surtout l'exactitude et la fidélité.
- Un modèle juge fait gagner énormément de travail, mais il se trompe, et avec assurance. La sortie du juge est une donnée à vérifier, pas une conclusion finale.
Exercices
- Modifiez dans
eval_qa.jsonlles réponses de référence des questions sur le pool de connexions et l'encodage, en retirant ce que la question ne demande pas, et ajoutez au prompt du juge « d'autres méthodes correctes que la réponse de référence comptent aussi comme justes ». Relancezrag_eval.py. Les verdicts du juge changent-ils ? - Ajoutez au prompt du juge de fidélité « juge uniquement d'après les documents, n'utilise pas tes propres connaissances », relancez, et voyez si le verdict sur la progression du téléchargement change.
- Choisissez 5 questions et soyez vous-même juge : les réponses sans documents sont-elles justes ? Comparé au modèle juge, sur combien de questions n'êtes-vous pas d'accord ?
Auto-test
1. Pourquoi l'évaluation d'un RAG doit-elle séparer la recherche et la réponse ?
En ne regardant que la réponse finale, on ne sait pas à quelle étape se situe l'erreur : les bons documents n'ont pas été trouvés, ou ils ont été fournis mais mal utilisés par le modèle. En évaluant séparément, on sait s'il faut modifier la recherche (découpage, réécriture, méthode de recherche) ou la génération (prompt, modèle).
2. Une réponse RAG est juste, mais l'évaluation de fidélité la juge « non fidèle ». Qu'est-ce que cela signifie ?
Qu'une partie de la réponse ne trouve pas d'appui dans les documents récupérés et vient probablement de la mémoire du modèle. Elle est juste par hasard cette fois, mais pourrait être fausse pour une autre question, sans qu'on puisse en retracer l'origine. Bien sûr, le juge peut aussi s'être trompé : il faut vérifier à la main.
3. Le modèle juge déclare une réponse « fausse » parce qu'elle « ne mentionne pas une méthode de la réponse de référence ». Que faire ?
Vérifier d'abord si la méthode utilisée par la réponse est elle aussi correcte. La référence ne donne souvent qu'une méthode, et le juge peut déclarer fausses d'autres méthodes correctes. Si, vérification faite, la réponse est juste, modifier le prompt du juge (en acceptant d'autres méthodes correctes) ou la réponse de référence.
Questions et discussion
Bloqué sur cette leçon ? Posez votre question ici. Et si vous pouvez répondre à quelqu'un, n'hésitez pas.
Une question rapporte 3 points, une réponse 6. Les messages paraissent après vérification.
Chargement de la discussion…