Экспериментальный пайплайн для оценки генерации тела Java-метода через LLM (Qwen 2.5 Coder, FIM mode).
Гипотеза: помогает ли аугментация из сигнатур method invocations при генерации, и влияет ли порядок сигнатур на качество? Помогает ли retrieval-based аугментация (поиск похожих методов по проекту)?
Режимы:
| Режим | Описание |
|---|---|
no_augmentation |
Только замаскированный Java-файл, без подсказок |
ordered_augmentation |
+ блок с сигнатурами invocations в порядке появления в коде |
shuffled_augmentation |
+ те же сигнатуры, но в случайном порядке |
retrieval_augmentation |
+ похожие методы из проекта, найденные Lucene-ретривером |
- Java 17+ (для сборки и запуска extractor'а и retriever'а; JDK 25 поддерживается через Gradle 9.4.1)
- Python 3.11+
- Git
Проверить доступные JDK:
/usr/libexec/java_home -Vpip install -r requirements.txtПроект содержит три Gradle-подпроекта:
- shared — общие модели данных
- extractor-core — парсер Java-проектов через Eclipse JDT (извлечение методов, invocations, типов)
- retriever — Lucene-ретривер для поиска похожих методов
cd extractor
JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew :extractor-core:jar :retriever:shadowJar
cd ..Результат:
extractor/extractor-core/build/libs/method-extractor-0.2.0.jar(~18 MB, fat JAR)extractor/retriever/build/libs/method-retriever-0.2.0.jar(~11 MB, shadow JAR с Lucene)
Убедиться, что JAR'ы запускаются:
java -jar extractor/extractor-core/build/libs/method-extractor-0.2.0.jar --help
java -jar extractor/retriever/build/libs/method-retriever-0.2.0.jar --helpmkdir -p target-project
git clone --branch v0.8.2 \
https://github.com/Aelysium-Group/rustyconnector-minecraft.git \
target-project/rustyconnector-minecraftЕсли
v0.8.2не соберётся, попробоватьv0.9.1.
Внимание: В v0.8.2 Gradle-проект расположен в подпапке
plugin/, а не в корне репозитория. Extractor и config.yaml уже указывают наplugin/.
Target-проект нужно скомпилировать до запуска экстрактора — JDT-у нужны .class файлы для type resolution.
cd target-project/rustyconnector-minecraft/plugin
chmod +x gradlew
JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew compileJava
cd ../../..Важно: и сборка target-проекта, и запуск экстрактора должны использовать Java 17. Системная Java 25 не поддерживается Gradle 8.6, который используется в rustyconnector.
Extractor резолвит classpath через Gradle init script и извлекает методы с полным type resolution через JDT.
Занимает ~10 секунд (при уже скомпилированном проекте).
JAVA_HOME=$(/usr/libexec/java_home -v 17) \
$(/usr/libexec/java_home -v 17)/bin/java -jar extractor/extractor-core/build/libs/method-extractor-0.2.0.jar \
--project-path ./target-project/rustyconnector-minecraft/plugin \
--output ./results/extracted_methods.json \
--min-statements 3Почему Java 17? Extractor вызывает
./gradlewtarget-проекта для classpath resolution. С Java 25 Gradle 8.6 падает (Unsupported class file major version 69). С Java 17 резолвится ~100 classpath entries и ~95% invocations получают EXACT resolution.
После завершения: results/extracted_methods.json содержит все извлечённые методы с сигнатурами invocations.
Посмотреть статистику:
python -c "
import json
with open('results/extracted_methods.json') as f:
d = json.load(f)
m = d['meta']
print(f'Files: {m[\"totalFiles\"]}, Total methods: {m[\"totalMethods\"]}, Extracted: {m[\"extractedMethods\"]}')
print(f'Unresolved invocations: {m[\"unresolvedInvocations\"]}')
"По JSON-у экстрактора собирается взвешенная матрица смежности call-graph'а проекта (PyTorch sparse COO).
- Вершины — все методы проекта (primary + siblings, дедуплицированные по каноническому
vertex_id) - Рёбра — направленные invocation'ы метода → метода; вес = количество вызовов в теле
- Фильтрация — дропаются только
UNRESOLVEDinvocations и EXACT-инвокации во внешние библиотеки (их нет в множестве вершин — «тупики» графа). Self-loops (рекурсия) сохраняются
-
Собрать JSON без фильтров по категориям — для графа нужны все методы класса, включая геттеры/сеттеры/делегаторы:
JAVA_HOME=$(/usr/libexec/java_home -v 17) \ java -jar extractor/extractor-core/build/libs/method-extractor-0.2.0.jar \ --project-path ./target-project/<your-project> \ --output ./results/extracted_methods.json \ --all-methods \ --min-statements 0
Флаг
--all-methodsотключает фильтр поMethodCategory(по умолчанию остаются толькоNORMAL).--min-statements 0оставляет однострочные геттеры. Эти два флага нужны вместе — без них граф будет неполным. -
Построить матрицу:
python -m pipeline.call_graph_cli ./results/extracted_methods.json \ -o ./results/call-graph \ --verbose
На выходе — директория с двумя файлами:
Файл Что внутри adjacency.pttorch.sparse_coo_tensorформы(N, N),dtype=int64, после.coalesce().A[i, j]= количество инвокаций из методаiв методjvertices.json{"vertex_ids": [...], "vertex_meta": [...]}.vertex_ids[i]— канонический ID методаiформата<classFqn>::<methodName>(<paramFqn1>,...) -> <returnFqn>(для конструкторов —<init>+ returnType = classFqn).vertex_meta[i]— полные метаданные вершины (class_fqn, method_name, file_path, parameter_types, return_type, исходный список invocations) -
Использовать в Python:
from pipeline.call_graph import load_call_graph g = load_call_graph("results/call-graph") A = g.to_dense() # torch.int64, shape (N, N) — веса binary = (A > 0).to(torch.int64) # бинарная матрица смежности in_deg = A.sum(dim=0) # in-degree каждой вершины out_deg = A.sum(dim=1) # out-degree # Найти вершину по ID: idx = g.vertex_ids.index("com.example.Foo::bar(int) -> void")
На JGraphT-Builder (~100 классов):
- 477 вершин, 811 уникальных рёбер,
Σw = 1168инвокаций, 3 self-loop'а, density ≈ 0.0036 - Время построения матрицы — секунды; размер
adjacency.pt— десятки КБ
После сборки граф можно проверить и осмотреть глазами.
-
Формальный отчёт (статистика + 7 sanity-чеков):
python -m pipeline.call_graph_check ./results/call-graph
Печатает summary, sanity-чеки (shape / dtype / sparse / positive weights / in-bounds / meta length / unique IDs), топ-10 по out/in/total degree, распределение весов и степеней (гистограммы), self-loops, изолированные вершины и случайную выборку из 5 методов с их outgoing edges для ручной сверки. Exit-код
0, если все чеки прошли. -
Интерактивный HTML-вьювер (Google Material UI):
python -m pipeline.call_graph_viewer ./results/call-graph \ -o ./results/call_graph_viewer.html \ --extraction-json ./results/extracted_methods.json
Один самодостаточный HTML-файл (открывается без сервера). Вкладки:
- Graph — force-directed граф на Cytoscape.js; цвет узла = пакет, размер = суммарная степень, клик по узлу открывает панель деталей, рёбра инцидентные выделяются синим
- Matrix — канвас-хитмап матрицы смежности; сортировка по index / class / out-deg / in-deg, шкала log / linear / binary, размер ячейки 2–8px; клик по ячейке переходит к соответствующему ребру
- Vertices — таблица всех вершин с поиском и сортировкой по out/in degree
В панели деталей видны исходящие и входящие рёбра (кликабельны — сразу переход к целевой вершине) и тело метода с подсветкой синтаксиса Java (если передан
--extraction-json).
- Коллизии
vertex_idпри flattening (например, один и тот же метод встречается и как primary, и как sibling другого метода того же класса) логируются как warning и дедуплицируются по принципу «первый выигрывает» — это нормальное поведение, связанное с форматом JSON, а не баг. - Если хочется бинарный граф без весов — используйте
(A > 0).float()на загруженной матрице, специальный режим не нужен. - Модуль публикует console_scripts (после
pip install -e .):mgx-call-graph,mgx-call-graph-check,mgx-call-graph-viewer— эквивалентныеpython -m pipeline.call_graph_cli/call_graph_check/call_graph_viewer.
Перед запуском эксперимента можно посмотреть, как выглядят сэмплы: тело метода, найденные сигнатуры, промпты для каждого режима.
# 3 сэмпла подряд (по умолчанию)
python -m pipeline.inspect --config config.yaml
# Конкретный сэмпл по индексу
python -m pipeline.inspect --config config.yaml --index 5
# Больше сэмплов
python -m pipeline.inspect --config config.yaml --n 10
# Только один режим аугментации
python -m pipeline.inspect --config config.yaml --mode ordered_augmentation
# Показать raw JSON первого сэмпла
python -m pipeline.inspect --config config.yaml --n 1 --jsonЧто выводит каждый сэмпл:
── METHOD METADATA ──────────────────────────────────────────────
File: common/src/main/java/.../SomeClass.java
Class: group.aelysium.rustyconnector.common.SomeClass
Signature: public void handleConnection(Player player)
Statements: 7
── GROUND TRUTH BODY ────────────────────────────────────────────
{
String id = player.getUuid().toString();
this.registry.add(id, player);
...
}
── EXTRACTED INVOCATION SIGNATURES (5) ─────────────────────────
[ 0] EXACT java.util.UUID::toString() -> java.lang.String
[ 1] EXACT com.example.Registry::add(java.lang.String, ...) -> void
[ 2] UNRESOLVED UNRESOLVED<process>
...
── PROMPT (ordered_augmentation) ────────────────────────────────
Augmentation block:
/*
* Method invocations used in this method:
* 1. java.util.UUID::toString() -> java.lang.String [EXACT]
* 2. com.example.Registry::add(...) -> void [EXACT]
* 3. UNRESOLVED<process> [UNRESOLVED]
*/
── prefix (last 20 lines) ──────────────────────────────────────
... (код файла до тела метода) ...
── <|fim_middle|> ← model generates here ──────────────────────
── suffix (first 20 lines) ──────────────────────────────────────
... (код файла после тела метода) ...
Prompt token estimate: ~1840 tokens
Ретривер ищет по проекту методы, похожие на целевой, и добавляет их как контекст в FIM-промпт. Это позволяет LLM видеть паттерны использования API из реального проекта.
- Экстракция — для каждого метода извлекаются расширенные метаданные: imports, поля класса, supertypes, сигнатуры соседних методов, используемые типы
- Индексация — все методы индексируются в Lucene с полями:
typeProfile(простые имена типов),methodCard(структурная карточка),invocationProfile(сигнатуры вызовов с bigrams) - Поиск — для целевого метода строится query из его типов, сигнатуры, типов полей класса. Используется MultiSimilarity (BM25 + LM Jelinek-Mercer + LM Dirichlet)
- Аугментация — найденные методы вставляются как Java-код перед целевым методом в FIM-промпте
- Leakage prevention — исключается сам метод, методы из того же файла и near-duplicates
JAVA_HOME=$(/usr/libexec/java_home -v 17) \
java -jar extractor/retriever/build/libs/method-retriever-0.2.0.jar index \
--input ./results/extracted_methods.json \
--index-dir ./results/lucene-indexИндекс автоматически создаётся при запуске пайплайна с
retrieval_augmentation, если его нет.
Визуальная инспекция того, что находит ретривер и как выглядят промпты:
# HTML-инспектор с полной визуализацией
JAVA_HOME=$(/usr/libexec/java_home -v 17) \
python -m pipeline.inspect_retrieval --config config.yaml --n 15
# Открыть в браузере
open results/retrieval_inspection.htmlИнспектор показывает для каждого сэмпла:
- Full Prompt — полный FIM-промпт с подсвеченными FIM-токенами
- Retrieved Methods — каждый найденный метод с Lucene explain, overlap analysis (Type IoU, Oracle Recall, shared types/owners)
- Search Query — Lucene query + все поля search request (imports, field types, sibling owner types)
- Augmentation Block — блок как он вставлен в промпт
- Target Method — oracle invocations, поля класса, supertypes
- Compare Prompts — промпт без аугментации vs с аугментацией
# Терминальная инспекция (компактнее)
JAVA_HOME=$(/usr/libexec/java_home -v 17) \
python -m pipeline.inspect --config config.yaml --n 3 --mode retrieval_augmentationПомимо стандартных метрик генерации, для retrieval_augmentation считаются:
| Метрика | Описание |
|---|---|
| Recall@K | Доля oracle invocations, чьи owner+method name найдены в аугментации |
| API Coverage@K | Доля нужных (ownerType, methodName) пар, покрытых retrieved методами |
| MRR | Mean Reciprocal Rank для нахождения метода с высоким token overlap с ground truth |
В config.yaml указать адрес OpenAI-compatible endpoint с моделью Qwen 2.5 Coder:
llm:
endpoint_url: "http://localhost:8080/v1/completions"
model_name: "qwen2.5-coder-7b"
temperature: 0.0
max_tokens: 512Endpoint должен поддерживать /v1/completions (не /v1/chat/completions) и FIM-токены Qwen 2.5 Coder:
<|fim_prefix|>, <|fim_suffix|>, <|fim_middle|>.
JAVA_HOME=$(/usr/libexec/java_home -v 17) python -m pipeline.run --config config.yaml
JAVA_HOMEнужен для retrieval (Lucene) и compilability (javac). Еслиretrieval_augmentationне используется, можно опустить.
# Baseline + retrieval (основной эксперимент)
JAVA_HOME=$(/usr/libexec/java_home -v 17) \
python -m pipeline.run --config config.yaml --mode no_augmentation retrieval_augmentation
# Только oracle аугментация
python -m pipeline.run --config config.yaml --mode ordered_augmentation
# Без проверки компилируемости (быстрее)
python -m pipeline.run --config config.yaml --skip-compilability
# Пропустить экстракцию (если уже сделана)
python -m pipeline.run --config config.yaml --skip-extractionЕсть три уровня визуализации — до LLM, после LLM (общий), после LLM (retrieval-ориентированный).
Самый важный инструмент для отладки ретривера. Генерирует HTML без обращения к LLM — только экстракция, индексация, поиск, форматирование промптов.
JAVA_HOME=$(/usr/libexec/java_home -v 17) \
python -m pipeline.inspect_retrieval --config config.yaml --n 15
open results/retrieval_inspection.htmlДля каждого сэмпла доступны 6 табов:
| Tab | Что показывает |
|---|---|
| Full Prompt | Полный FIM-промпт с подсвеченными <|fim_prefix|> / <|fim_suffix|> / <|fim_middle|> токенами + ground truth |
| Retrieved Methods | Каждый retrieved метод раскрывается: Overlap Analysis (Type IoU, Owner IoU, Oracle Recall, shared types/owners — цветные тэги), Lucene Score Explain (декомпозиция score по термам и полям), Type Profile, Method Card, Invocation Profile, тело метода с подсветкой Java |
| Search Query | Lucene query string + все поля search request: imports, field types, sibling owner types, sibling signatures, FIM prefix/suffix (что ушло в query) |
| Augmentation Block | Блок Java-кода как он вставлен в промпт + ground truth рядом для сравнения |
| Target Method | Полная инфо о целевом методе: oracle invocations (таблица), поля класса, supertypes, imports |
| Compare Prompts | Промпт без аугментации vs с аугментацией бок о бок, с разницей в размере |
Навигация: стрелки вверх/вниз по сэмплам, цифры 1-6 по табам, поиск по имени метода. В заголовке каждого retrieved метода сразу видны badge: Type IoU, кол-во shared owners, Oracle Recall%.
# Все 100 сэмплов
JAVA_HOME=$(/usr/libexec/java_home -v 17) \
python -m pipeline.inspect_retrieval --config config.yaml
# Указать выходной файл
JAVA_HOME=$(/usr/libexec/java_home -v 17) \
python -m pipeline.inspect_retrieval --config config.yaml --n 20 --output ./my_inspection.htmlПосле прогона эксперимента (с LLM). Показывает все режимы одновременно — baseline, oracle, retrieval.
python -m pipeline.viewer --results-dir ./results
open results/viewer.htmlСамодостаточный HTML-файл. Табы:
- Code — подсветка Java для ground truth и сгенерированного кода всех режимов
- Diff — side-by-side и unified diff между generated vs ground truth, cross-mode
- Prompt — полный FIM-промпт с подсвеченными FIM-токенами, augmentation block
- Meta — latency, token usage, compilability, ошибки, таблица invocations
Навигация: поиск, фильтры (EM Only, Compilable, Has Errors), стрелки, цифры 1-4, тёмная/светлая тема.
python -m pipeline.viewer --results-dir ./results --no-prompts # без промптов (меньше файл)
python -m pipeline.viewer --results-dir ./results --output ./report.htmlПосле прогона эксперимента. Фокус на retrieval-метриках и сравнении baseline vs retrieval.
python -m pipeline.retrieval_viewer --results-dir ./results
open results/retrieval_viewer.htmlТабы:
- Overview — агрегированная таблица метрик (включая Recall@K, API Coverage, MRR) по всем режимам
- Sample — per-sample метрики всех режимов бок о бок (badge для каждого mode), oracle invocations
- Retrieval — retrieved методы с rank/score, Lucene query, retrieval metrics, augmentation block
- Code — ground truth + generated code каждого режима бок о бок
python -m pipeline.retrieval_viewer --results-dir ./results --output ./retrieval_report.htmlДля быстрого просмотра в терминале:
# Oracle режимы
python -m pipeline.inspect --config config.yaml --n 3
# Retrieval режим
JAVA_HOME=$(/usr/libexec/java_home -v 17) \
python -m pipeline.inspect --config config.yaml --n 3 --mode retrieval_augmentation
# Конкретный сэмпл
JAVA_HOME=$(/usr/libexec/java_home -v 17) \
python -m pipeline.inspect --config config.yaml --index 5 --mode retrieval_augmentationПосле прогона в results/ будет:
results/
├── extracted_methods.json # Все извлечённые методы (из экстрактора)
├── dataset.json # Индекс сэмплированных методов
├── lucene-index/ # Lucene-индекс для ретривера
├── no_augmentation/
│ ├── aggregate.json # Агрегированные метрики по режиму
│ └── samples/
│ ├── sample_000.json # Один сэмпл: промпт, ответ, метрики
│ └── ...
├── ordered_augmentation/
│ └── ...
├── retrieval_augmentation/ # + retrieval results, query debug
│ └── ...
├── summary.json # Сравнение всех режимов
├── comparison_table.txt # Таблица метрик
├── viewer.html # Интерактивный вьювер (oracle эксперименты)
├── retrieval_viewer.html # Вьювер для retrieval эксперимента
└── retrieval_inspection.html # Инспектор retrieval (без LLM)
+----------+--------------------+--------------------+--------------------+
| Metric | no_augmentation | ordered_augmentation | shuffled_augmentation |
+----------+--------------------+--------------------+--------------------+
| em | 0.0300 (std=...) | 0.0800 (std=...) | 0.0600 (std=...) |
| es | 0.4500 (std=...) | 0.6200 (std=...) | 0.5800 (std=...) |
| iou | 0.3800 (std=...) | 0.5500 (std=...) | 0.5100 (std=...) |
| lcs_ratio| 0.4100 (std=...) | 0.5800 (std=...) | 0.5400 (std=...) |
| compilable| 0.1200 (std=...) | 0.2500 (std=...) | 0.2100 (std=...) |
+----------+--------------------+--------------------+--------------------+
Все считаются на нормализованном коде (без комментариев, collapsed whitespace):
| Метрика | Описание |
|---|---|
| EM | Exact Match — бинарный, 1 если тела совпали после нормализации |
| ES | Edit Similarity — 1 - levenshtein(gen, ref) / max(len_a, len_b) |
| IoU | Jaccard на множестве токенов (multiset intersection / union) |
| LCS ratio | Длина LCS на токенах / max(len(gen_tokens), len(ref_tokens)) |
| Compilable | Успешная компиляция файла через javac после подстановки тела |
| Test Pass | Доля сэмплов, где все тесты прошли после подстановки сгенерированного тела (pass@1) |
| Recall@K | Доля oracle invocations, покрытых retrieved аугментацией (только retrieval_augmentation) |
| API Coverage@K | Доля нужных API (owner+method), найденных ретривером (только retrieval_augmentation) |
| MRR | Mean Reciprocal Rank похожего метода в retrieved результатах (только retrieval_augmentation) |
extractor/ # Gradle multi-project (Java 17)
settings.gradle.kts # include("shared", "extractor-core", "retriever")
shared/ # Общие модели данных
src/.../shared/model/
ExtractedMethod.java # Метод с расширенными метаданными
ClassField.java, SiblingMethod.java, ...
extractor-core/ # Парсер Java-проектов
src/.../extractor/
cli/ExtractorCli.java # CLI entry point (picocli)
analysis/MethodExtractor.java # JDT two-pass AST visitor
analysis/MethodClassifier.java # Фильтрация getter/setter/test/...
classpath/ClasspathResolver.java # Gradle init script → classpath
retriever/ # Lucene-ретривер
src/.../retriever/
cli/RetrieverCli.java # CLI: index + search-batch
index/IndexBuilder.java # Построение Lucene-индекса
index/MethodCardBuilder.java # Структурная карточка метода
index/TypeProfileBuilder.java # Профиль типов (simple names)
index/InvocationProfileBuilder.java # Invocation signatures + bigrams
search/QueryBuilder.java # Type query + Signature query + Invocation query
search/SearchExecutor.java # Поиск + leakage filter + class diversity
search/LeakageFilter.java # Исключение target/same-file/near-dup
similarity/CompositeSimilarity.java # MultiSimilarity: BM25 + LM Jelinek-Mercer + LM Dirichlet
pipeline/ # Python пайплайн
config.py # Dataclass-based YAML config (вкл. RetrievalConfig)
models.py # Python mirrors of Java model + RetrievalResult
dataset.py # Загрузка, фильтрация, сэмплирование
prompt.py # FIM prompt + augmentation block (oracle + retrieval)
llm.py # HTTP client для v1/completions
retrieval.py # Оркестрация retrieval: index, search, format augmentation
normalize.py # Нормализация кода + identifier unification
metrics.py # EM, ES, IoU, LCS, CodeBLEU + Recall@K, API Coverage, MRR
compilability.py # javac subprocess check
coverage.py # JaCoCo интеграция: запуск, парсинг XML, CoverageMap
test_runner.py # Замена тела метода → прогон тестов → pass@k
report.py # Агрегация + таблицы (вкл. retrieval и test_pass метрики)
run.py # Главный оркестратор (вкл. coverage map + test evaluation фаза)
inspect.py # Dry-run инспекция сэмплов (вкл. retrieval_augmentation)
inspect_retrieval.py # HTML-инспектор retrieval (Lucene explain, overlap analysis)
viewer.py # HTML-вьювер для oracle экспериментов
retrieval_viewer.py # HTML-вьювер для retrieval экспериментов
Pipeline поддерживает расширенную фильтрацию методов для оценки method generation через pass@k. Цель — отобрать методы с "богатой функциональной сигнатурой", покрытые тестами.
| Критерий | Параметр конфига | Описание |
|---|---|---|
| Non-void return type | extraction.require_non_void: true |
Исключает void-методы и конструкторы — оставляет методы, отражающие data flow через сигнатуру |
| Наличие параметров | extraction.require_parameters: true |
Данные должны поступать через параметры, а не через side effects |
| Покрытие тестами | extraction.require_test_coverage: true |
Метод должен быть покрыт хотя бы одним тестом (через JaCoCo) |
| ≥3 statement | extraction.min_statements: 3 |
Нетривиальное тело метода |
| Resolved invocations | (всегда) | Все invocations должны иметь EXACT resolution |
| Не getter/setter/... | extraction.exclude_categories |
Исключаются GETTER, SETTER, DELEGATOR, GENERATED, TEST |
Для определения покрытия тестами используется JaCoCo:
- Запускаются тесты с JaCoCo agent (Maven:
jacoco:prepare-agent test jacoco:report, Gradle: init script или встроенный плагин) - Парсится XML-отчёт — строится
CoverageMap:{class_fqn → [MethodCoverage]} - Для матчинга JVM-дескрипторов (из JaCoCo) с FQN-типами (из экстрактора) используется встроенный конвертер
Для multi-module Gradle-проектов (например, JUnit 5) можно объединить exec-файлы через JaCoCo CLI:
java -jar org.jacoco.cli-nodeps.jar merge */build/jacoco/*.exec --destfile merged.exec
java -jar org.jacoco.cli-nodeps.jar report merged.exec --classfiles */build/classes/java/main --xml report.xmlПосле генерации тела метода LLM pipeline может оценить корректность через прогон тестов:
- Тело метода заменяется в исходном файле (offset-based replacement)
- Запускается
./gradlew testилиmvn test - Парсятся XML-отчёты тестов (Surefire/JUnit format)
- Оригинальный файл восстанавливается из
file_content(+ fallback черезgit checkout)
Конфигурация:
test_evaluation:
enabled: true
timeout_seconds: 300
build_system: "gradle" # или "maven"Результат: метрика test_pass в агрегированном отчёте (доля сэмплов, где все тесты прошли после подстановки сгенерированного тела).
После прогона генерации, javac-проверки и test_evaluation можно собрать датасет методов, которые:
- компилируются (
metrics.compilable == true); - не совпадают с target-методом по Exact Match (
metrics.em == false); - ломают тесты проекта (
test_eval.success == false, при успешной сборке тестового запуска).
python -m pipeline.failure_dataset ./results \
-o ./results/failure_dataset.jsonl \
--dedupe method_generatedЕсли нужен более строгий срез, где упавший тест эвристически связан с методом
через direct_test_methods, test_file_paths или имя test-класса:
python -m pipeline.failure_dataset ./results \
-o ./results/related_failure_dataset.jsonl \
--require-related-failure \
--dedupe method_generatedCLI также доступен как mgx-failure-dataset после установки пакета. Рядом с датасетом создаётся summary-файл с количеством найденных кандидатов, распределением по режимам и причинами отбраковки.
Текущий target-проект: JUnit 5 (junit-team/junit5).
| Параметр | Значение |
|---|---|
| Билд | Gradle 9.4.1 |
| Тесты | ~6200, ~49 секунд |
| Извлечено методов | 1079 |
| После всех фильтров | 368 |
| JaCoCo coverage | 5414/6905 методов (78%) |
Критерии выбора проекта:
- Gradle (не Maven) — для совместимости с закрытым контуром
- Быстрые тесты (<2 минут) — для практичного pass@k
- Много functional-style методов — utility/library код с non-void return types
- Совместимость с JDK 25 — Gradle 9.x
Проверенные и отклонённые проекты:
| Проект | Причина отклонения |
|---|---|
| Apache Commons Lang | Maven (проблемы с прокси в закрытом контуре), 566 методов |
| Caffeine | Тесты 30+ минут (стресс-тестирование кэша) |
| PureFun | Слишком мало методов (61 после фильтров) |
| Picocli | Несовместим с Gradle 9 |
| Functional Java | Старый Gradle, не собирается на JDK 25 |
| Vavr | Maven (не Gradle) |
Pipeline полностью локальный — исходники target-проекта не отправляются в сеть:
- LLM endpoint (
llm.endpoint_url) — единственный сетевой вызов. По умолчаниюhttp://localhost:8080(локальный). Если LLM запущен локально, данные не покидают машину - CDN-ссылки в HTML-вьюверах — только загрузка JS-библиотек (highlight.js, diff2html) для подсветки синтаксиса в браузере. Исходный код туда не отправляется
- Экстрактор, ретривер, метрики, coverage, test runner — полностью офлайн
Все параметры, влияющие на результат, фиксируются в config.yaml и логируются в начале каждого прогона:
dataset.random_seed— выбор 100 сэмплов из датасетаexperiment.shuffle_seed— перемешивание invocation signatures вshuffled_augmentationllm.seed— seed для LLM (если endpoint поддерживает)llm.temperature,llm.max_tokens,llm.stop_sequences— параметры генерацииcompilability.mode— уровень проверки компилируемости (file)
Каждый sample_NNN.json содержит полный промпт и ответ модели, что позволяет воспроизвести и перепроверить любой сэмпл.