Benchmark pour évaluer la capacité d’un GraphRAG à localiser les classes Java impactées à partir de descriptions d’issues GitHub.
Le workflow est en 2 étapes:
- Miner un repository GitHub pour construire un dataset
Issue -> MRs merged -> impacted files. - Exécuter GraphRAG sur chaque issue retenue et calculer
precision,recall,F1.
À partir d’une issue (titre + description), retrouver les classes Java effectivement modifiées dans les merge requests associées à cette issue.
La vérité terrain est dérivée des fichiers modifiés dans les PR mergées liées à l’issue.
benchmark-graphRag/
├── scripts/
│ ├── mine_github_issues.py
│ ├── evaluator_core.py
│ ├── evaluate_graphrag_benchmark.py
│ ├── evaluate_llm_api_benchmark.py
│ ├── evaluate_manual_input_benchmark.py
│ └── export_benchmark_queries.py
├── mined_projects/ # sorties JSON (ignoré par git)
├── evaluation_results/ # rapports evaluator (ignoré par git)
├── queries/ # queries LLM exportées (ignoré par git)
├── .env.github # token GitHub local (ignoré par git)
└── README.md
- Python 3.10+
uv(pour lancer GraphRAG)- Un projet GraphRAG déjà indexé, avec un dossier
outputexploitable. - Optionnel mais fortement recommandé: un token GitHub (sinon rate limits API très bas).
Les évaluateurs reposent sur une base commune:
BaseBenchmarkEvaluatordansscripts/evaluator_core.pygère le pipeline séquentiel complet (chargement benchmark, filtrage, prompts, métriques, rapport).evaluate_graphrag_benchmark.pyest une spécialisation GraphRAG (appeluv run ... graphrag query).evaluate_llm_api_benchmark.pyest une spécialisation API LLM (Ollama/OpenAI/Mistral).
Créer/éditer .env.github à la racine:
GITHUB_TOKEN=ghp_xxxLe script de mining résout le token dans cet ordre:
--token- variable d’environnement
GITHUB_TOKEN - fichier
.env.github(répertoire courant puis racine du projet)
Script: scripts/mine_github_issues.py
Une issue est conservée si:
- elle est
closed, - au moins une PR mentionnée dans sa conversation est
merged, - la fermeture de l’issue est postérieure (ou égale) au merge d’au moins une de ces PR.
Les PR liées sont détectées dans:
- le body de l’issue,
- les commentaires de l’issue,
- la timeline de l’issue.
Si plusieurs PR mergées sont liées à une même issue, elles sont toutes conservées.
Mining simple (sortie par défaut dans mined_projects/):
python3 scripts/mine_github_issues.py "https://github.com/stleary/JSON-java"Plusieurs repos:
python3 scripts/mine_github_issues.py \
"https://github.com/mybatis/jpetstore-6" \
"https://github.com/NanoHttpd/nanohttpd"Limiter le nombre d’issues scannées:
python3 scripts/mine_github_issues.py "https://github.com/stleary/JSON-java" --issue-limit 300--issue-limit (alias --max-issues) vaut 200 par défaut.
Un fichier JSON par projet, par exemple:
mined_projects/stleary__json-java__YYYYMMDDTHHMMSSZ.json
Structure simplifiée:
{
"project_name": "stleary/json-java",
"github_url": "https://github.com/stleary/JSON-java",
"issues": [
{
"number": 296,
"title": "...",
"description_message": "...",
"linked_merged_pull_requests": [
{
"number": 646,
"url": "...",
"merged_at": "...",
"impacted_files": [
"src/main/java/org/json/JSONObject.java"
]
}
]
}
]
}Script: scripts/evaluate_graphrag_benchmark.py
Le script:
- lit un fichier de mining,
- construit une requête par issue avec
title + description + prompt,- ajoute systématiquement un pré-prompt obligatoire aligné sur le
response_typepar défaut du script,
- ajoute systématiquement un pré-prompt obligatoire aligné sur le
- exécute GraphRAG:
uv run python -m graphrag query "<query>" --root . --method <method> --data ./output --response-type "<valeur par défaut interne du script>"
- extrait les classes prédites,
- compare aux fichiers Java attendus,
- calcule les métriques par issue et globales.
Le response_type n’est pas paramétrable en ligne de commande: il est fixé dans le script pour garantir un format de sortie stable.
python3 scripts/evaluate_graphrag_benchmark.py \
mined_projects/stleary__json-java__20260420T090843Z.json \
--graphrag-dir /path/to/graphrag \
--method local--method accepte uniquement:
localdriftglobal
Exemples:
python3 scripts/evaluate_graphrag_benchmark.py <mined.json> --graphrag-dir /path/to/graphrag --method drift
python3 scripts/evaluate_graphrag_benchmark.py <mined.json> --graphrag-dir /path/to/graphrag --method global--issue-limit N: limite le nombre d’issues évaluées.--output-dir /path/folder: dossier de sortie des rapports (par défaut:evaluation_results/).--output-file /path/report.json: chemin de sortie du rapport.--timeout-seconds 300: timeout par requête GraphRAG.--extra-prompt "...": suffixe de prompt custom.--keep-raw-response: inclut la réponse brute GraphRAG dans le rapport.--include-empty-java: inclut aussi les issues sans cible Java.--dry-run: n’exécute pas GraphRAG (test pipeline uniquement).
Par issue:
TP: classes Java attendues retrouvées.FP: classes prédites non matchées.FN: classes attendues non retrouvées.precision = TP / (TP + FP)recall = TP / (TP + FN)f1 = 2 * precision * recall / (precision + recall)
Global:
micro(agrégation globale TP/FP/FN)macro(moyenne des scores par issue)
Le matching accepte plusieurs formats côté prédiction:
- chemin
.java, - nom pleinement qualifié (FQCN),
- nom de classe simple.
Si un nom simple est ambigu (plusieurs classes possibles), il n’est pas matché automatiquement.
Chaque requête envoyée à GraphRAG inclut automatiquement un pré-prompt obligatoire qui impose:
- un format strict conforme au
response_typepar défaut du script, - aucune explication hors format attendu.
Sortie par défaut: dans evaluation_results/, avec suffixe __graphrag_eval__<timestamp>.json.
Le rapport contient:
- les paramètres d’exécution,
- un résumé global,
- les métriques par issue,
- les classes attendues / prédites.
- Préparer le token GitHub (
.env.github). - Miner un projet:
python3 scripts/mine_github_issues.py "<repo-url>"
- Lancer l’évaluation GraphRAG:
python3 scripts/evaluate_graphrag_benchmark.py <mined-file.json> --graphrag-dir <path> --method local
- Comparer les résultats entre
local,drift,global.
Script: scripts/export_benchmark_queries.py
Objectif:
- générer un JSON contenant uniquement les queries à envoyer au LLM,
- en réutilisant la même construction de prompt que l’evaluator,
- inclure le contexte d’issue et les chemins de classes attendues.
Sortie:
- par défaut dans
queries/, - un fichier nommé selon le projet benchmark, par exemple:
queries/mybatis__jpetstore-6__queries.json
Commande type:
python3 scripts/export_benchmark_queries.py \
mined_projects/mybatis__jpetstore-6__20260420T093019Z.jsonOptions utiles:
--output-dir /path/folder--output-file /path/file.json--issue-limit N--include-empty-java--extra-prompt "..."
Script: scripts/evaluate_llm_api_benchmark.py
Objectif:
- évaluer le benchmark sans passer par
graphrag query, - interroger directement une API LLM (Ollama local, OpenAI, Mistral),
- calculer les mêmes métriques (
precision,recall,f1).
Exemples:
Ollama (local):
python3 scripts/evaluate_llm_api_benchmark.py \
mined_projects/mybatis__jpetstore-6__20260420T093019Z.json \
--provider ollama \
--model gemma2 \
--keep-raw-responseOpenAI:
export OPENAI_API_KEY="..."
python3 scripts/evaluate_llm_api_benchmark.py \
mined_projects/mybatis__jpetstore-6__20260420T093019Z.json \
--provider openai \
--model gpt-4.1-miniMistral:
export MISTRAL_API_KEY="..."
python3 scripts/evaluate_llm_api_benchmark.py \
mined_projects/mybatis__jpetstore-6__20260420T093019Z.json \
--provider mistral \
--model mistral-small-latestOptions utiles:
--base-urlpour un endpoint custom,--api-keypour surcharger la clé env,--temperature,--max-tokens,--issue-limit,--keep-raw-response,--dry-run.
Script: scripts/evaluate_manual_input_benchmark.py
Objectif:
- lire un benchmark,
- construire la query pour chaque issue,
- afficher cette query à l’utilisateur,
- attendre la réponse manuelle (copier/coller depuis un LLM/GraphRAG),
- calculer automatiquement les métriques.
Commande type:
python3 scripts/evaluate_manual_input_benchmark.py \
mined_projects/mybatis__jpetstore-6__20260420T093019Z.json \
--keep-raw-responseMode de saisie:
- le script affiche la query,
- la query est automatiquement copiée dans le presse-papier (si supporté par l’environnement),
- tu colles la réponse multi-ligne,
- tu termines en faisant simplement
Entréesur une ligne vide, - les lignes vides internes dans un gros collage multi-ligne sont désormais tolérées (le script évite de passer involontairement à l’issue suivante),
- optionnellement, tu peux aussi terminer avec
EOF(ou un token custom via--end-token), - si tu tapes
STOPsur une ligne, l’évaluation s’arrête immédiatement et un fichier de résultats partiels est généré avec les données déjà collectées.
Options utiles:
--issue-limit N--include-empty-java--keep-raw-response--end-token DONE--no-copy-query-to-clipboard
Format de sortie (par entrée):
issue_numberqueryexpected_classes_paths
- Erreur
API rate limit exceeded:- vérifier
GITHUB_TOKEN(.env.githubou env var).
- vérifier
- Erreur
GraphRAG directory not found:- passer
--graphrag-dirvers le bon dossier.
- passer
- Beaucoup de
FP:- réduire le prompt à une sortie plus contrainte,
- ajuster le
DEFAULT_RESPONSE_TYPEdirectement dans le script, - vérifier l’ambiguïté des noms de classes simples.
- Pas d’issues pertinentes:
- le repository n’a peut-être pas d’issues fermées reliées à des PR mergées selon les règles du miner.
mined_projects/est ignoré par git.evaluation_results/est ignoré par git.queries/est ignoré par git..env.githubest ignoré par git.- Le projet privilégie des outputs JSON pour faciliter l’analyse offline et les comparaisons de runs.