0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIのコード生成「Agentless」を試す

Last updated at Posted at 2025-01-07

概要

AgentlessSWEBenchで好成績を出したというのがちょっと前にでていたので中身を確認してみた。

Screenshot 2025-01-08 at 8.13.34.png

「Agentless」という最新手法。LLMの新しい使い方。 がとてもわかり易いのでこれを見ると中身の理解にとても役立ちます。

全体像

image.png

  1. Localization: LLMとEmbeddingを使って関連するファイルと位置を特定する (File-level→Element-level→Line-level)
  2. Repair: ラインの位置と変更DiffからなるPatchをissueごとに複数生成する
  3. Validation and Selection: Regression test (既存のテスト)の実行とissueに対応するReproduction testを生成(複数)し、これらの結果から最終的なpatchを決定する

ステップ

1. 準備

Repo setup

gh repo clone OpenAutoCoder/agentless
pip install -r requirements.txt

repo structure

ダウンロードしてないと各レポのStructureを生成するプログラムが走り時間がかかるので、https://github.com/OpenAutoCoder/Agentless/releases/tag/v1.5.0 からダウンロードする

各issueに対してrepo内の情報が格納されている。

Env var設定

export OPENAI_API_KEY=xxxxxx
export PROJECT_FILE_LOC=~/Downloads/repo_structure/repo_structures
export PYTHONPATH=$PYTHONPATH:$(pwd)

~/Downloads/repo_structure/repo_structures は上でダウンロードしてunzipしたもののPath

2. Localization

今回は、一つだけ --target_id=django__django-10914 を例に実行してみる

ファイルレベル 関連ファイルを取得

python agentless/fl/localize.py --file_level --output_folder results/swe-bench-lite/file_level --num_threads 10 --skip_existing --target_id=django__django-10914

ファイルレベル 関係ないファイルの特定

python agentless/fl/localize.py --file_level --output_folder results/swe-bench-lite/file_level_irrelevant --num_threads 10 --skip_existing --target_id=django__django-10914 --irrelevant

embeddingから関係のあるファイルを取得

python agentless/fl/retrieve.py --index_type simple \
                                --filter_type given_files \
                                --filter_file results/swe-bench-lite/file_level_irrelevant/loc_outputs.jsonl \
                                --output_folder results/swe-bench-lite/retrievel_embedding \
                                --persist_dir embedding/swe-bench_simple \
                                --num_threads 10 \
                                --target_id=django__django-10914

combine

LLMとEmebddingで取得した関連ファイルをそれぞれtop Nを取ってきてマージする

python agentless/fl/combine.py  --retrieval_loc_file results/swe-bench-lite/retrievel_embedding/retrieve_locs.jsonl \
                                --model_loc_file results/swe-bench-lite/file_level/loc_outputs.jsonl \
                                --top_n 3 \
                                --output_folder results/swe-bench-lite/file_level_combined

関連Elementレベル

combined locationsを対象に element levelの関連を取得

python agentless/fl/localize.py --related_level \
                                --output_folder results/swe-bench-lite/related_elements \
                                --top_n 3 \
                                --compress_assign \
                                --compress \
                                --start_file results/swe-bench-lite/file_level_combined/combined_locs.jsonl \
                                --num_threads 10 \
                                --skip_existing \
                                --target_id=django__django-10914

promptは

Please provide the complete set of locations as either a class name, a function name, or a variable name.
Note that if you include a class, you do not need to list its specific methods.
You can include either the entire class or don't include the class name and instead include specific methods in the class.
### Examples:
```
full_path1/file1.py
function: my_function_1
class: MyClass1
function: MyClass2.my_method

full_path2/file2.py
variable: my_var
function: MyClass3.my_method
full_path3/file3.py
function: my_function_2
function: my_function_3
function: MyClass4.my_method_1
class: MyClass5
```

Return just the locations wrapped with ```.

実際に見つかった変更箇所のElementsの例:

{"django/core/files/storage.py": ["class: FileSystemStorage"], "django/conf/global_settings.py": ["variable: FILE_UPLOAD_PERMISSIONS"], "django/core/files/uploadhandler.py": [""]}

関連行レベル

related elementを対象に 行レベルの変更位置サンプルの生成 (この例ではsampleを4つ作る)

python agentless/fl/localize.py --fine_grain_line_level \
                                --output_folder results/swe-bench-lite/edit_location_samples \
                                --top_n 3 \
                                --compress \
                                --temperature 0.8 \
                                --num_samples 4 \
                                --start_file results/swe-bench-lite/related_elements/loc_outputs.jsonl \
                                --num_threads 10 \
                                --skip_existing \
                                --target_id=django__django-10914

prompt (一部):

Please provide the class name, function or method name, or the exact line numbers that need to be edited.
The possible location outputs should be either \"class\", \"function\" or \"line\".

### Examples:
```
full_path1/file1.py
line: 10
class: MyClass1
line: 51

full_path2/file2.py
function: MyClass2.my_method
line: 12

full_path3/file3.py
function: my_function
line: 24
line: 156
```

Return just the location(s) wrapped with ```.

example result:

["```\ndjango/core/files/storage.py\nline: 260\nline: 217\n\ndjango/conf/global_settings.py\nline: 307\n```", "```\nfull_path1/django/core/files/storage.py\nline: 260\nline: 284\n\nfull_path2/django/conf/global_settings.py\nline: 307\n```", "```\ndjango/core/files/storage.py\nline: 260\n\ndjango/conf/global_settings.py\nline: 307\n```", "```\ndjango/conf/global_settings.py\nline: 307\n\ndjango/core/files/storage.py\nline: 260\n```"]

loc_output.jsonl の形式

  1. instance_id: task ID of the issue
  2. found_files: list of files localized by the model
  3. additional_artifact_loc_file: raw output of the model during file-level localization
  4. file_traj: trajectory of the model during file-level localization (e.g., # of tokens)
  5. found_related_locs: dict of relevant code elements localized by the model
  6. additional_artifact_loc_related: raw output of the model during relevant-code-level localization
  7. related_loc_traj: trajectory of the model during relevant-code-level localization
  8. found_edit_locs: dict of edit locations localized by the model
  9. additional_artifact_loc_edit_location: raw output of the model during edit-location-level localization
  10. edit_loc_traj: trajectory of the model during edit-location-level localization

edit locationごとに分ける

行レベル変更位置サンプル edit_location_samplesをそれぞれにわける。

python agentless/fl/localize.py --merge \
                                --output_folder results/swe-bench-lite/edit_location_individual \
                                --top_n 3 \
                                --num_samples 4 \
                                --start_file results/swe-bench-lite/edit_location_samples/loc_outputs.jsonl \
                                --target_id=django__django-10914 

上の例で生成したsampleは4つが、それぞれのdirに分けられる。

tree results/swe-bench-lite/edit_location_individual                                                                       
results/swe-bench-lite/edit_location_individual
├── args.json
├── loc_merged_0-0_outputs.jsonl
├── loc_merged_1-1_outputs.jsonl
├── loc_merged_2-2_outputs.jsonl
├── loc_merged_3-3_outputs.jsonl
└── localization_logs

2 directories, 5 files

3. Repair

patchの生成

issueごとに複数のpatchを生成してvotingで最終的なpatchを決める (この例ではresults/swe-bench-lite/repair_sample_1)

python agentless/repair/repair.py --loc_file results/swe-bench-lite/edit_location_individual/loc_merged_0-0_outputs.jsonl \
                                  --output_folder results/swe-bench-lite/repair_sample_1 \
                                  --loc_interval \
                                  --top_n=3 \
                                  --context_window=10 \
                                  --max_samples 10  \
                                  --cot \
                                  --diff_format \
                                  --gen_and_process \
                                  --num_threads 2 \
                                --target_id=django__django-10914 

↓以下のような感じで複数のpatchが生成される

Screenshot 2025-01-08 at 7.44.17.png

4サンプル分残りの3つも回す

for i in {1..3}; do
    python agentless/repair/repair.py --loc_file results/swe-bench-lite/edit_location_individual/loc_merged_${i}-${i}_outputs.jsonl \
                                    --output_folder results/swe-bench-lite/repair_sample_$((i+1)) \
                                    --loc_interval \
                                    --top_n=3 \
                                    --context_window=10 \
                                    --max_samples 10  \
                                    --cot \
                                    --diff_format \
                                    --gen_and_process \
                                    --num_threads 2 \
                                    --target_id=django__django-10914
done

repair_sample_1, repair_sample_2, repair_sample_3, repair_sample_4にそれぞれ生成されたPatchが出力される

4. Patch Validation and Selection

以下では --instance_ids=django__django-10914 を指定することで今回対象としているissueのみにを実行する

Regression Test Selection

Regression testを実行するために関連のRegression test (レポ内既存の)を選択する

python agentless/test/run_regression_tests.py --run_id generate_regression_tests \
                                              --output_file results/swe-bench-lite/passing_tests.jsonl \
                                              --instance_ids=django__django-10914

MacOSで実行したが、このステップでBuilding environment 失敗してしまった。

    raise BuildImageError(image_name, str(e), logger) from e
swebench.harness.docker_build.BuildImageError: Error building image sweb.env.arm64.2baaea72acc974f6c02079:latest: The command '/bin/sh -c /bin/bash -c "source ~/.bashrc && /root/setup_env.sh"' returned a non-zero code: 1
Check (logs/build_images/env/sweb.env.arm64.2baaea72acc974f6c02079__latest/build_image.log) for more information.
Building environment images: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:27<00:00, 27.58s/it]
1 environment images failed to build.
Found 0 existing instance images. Will reuse them.
  0%|                                                                                                                                                                                                                                    | 0/1 [00:00<?, ?it/s]Error building image django__django-10914: Environment image sweb.env.arm64.2baaea72acc974f6c02079:latest not found for django__django-10914
Check (logs/run_evaluation/generate_regression_tests/test/django__django-10914/run_instance.log) for more information.

logの中身を見ると "No such image: sweb.env.arm64.2baaea72acc974f6c02079:latest" となっていた

https://github.com/swe-bench/SWE-bench これの設定をすると良さそうなので別途対応。以下は2025/01/08時点では実行出来てない。(TODO)

実行しなくていいテストをLLMで除外する

python agentless/test/select_regression_tests.py --passing_tests results/swe-bench-lite/passing_tests.jsonl \
                                                 --output_folder results/swe-bench-lite/select_regression 

選択されたテストをpatchesに対して実行する

folder=results/swe-bench-lite/repair_sample_1
for num in {0..9..1}; do
    run_id_prefix=$(basename $folder); 
    python agentless/test/run_regression_tests.py --regression_tests results/swe-bench-lite/select_regression/output.jsonl \
                                                  --predictions_path="${folder}/output_${num}_processed.jsonl" \
                                                  --run_id="${run_id_prefix}_regression_${num}" --num_workers 10;
done

Reproduction test generation

reproduction testを生成して、patchが問題を解決できたかを確認する。patch生成と同様に reproduction testsも複数生成する

python agentless/test/generate_reproduction_tests.py --max_samples 40 \
                                                     --output_folder results/swe-bench-lite/reproduction_test_samples \
                                                     --num_threads 10 

Execute

for st in {0..36..4}; do   en=$((st + 3));   
        echo "Processing ${st} to ${en}";   
        for num in $(seq $st $en); do     
            echo "Processing ${num}";     
            python agentless/test/run_reproduction_tests.py --run_id="reproduction_test_generation_filter_sample_${num}" \
                                                            --test_jsonl="results/swe-bench-lite/reproduction_test_samples/output_${num}_processed_reproduction_test.jsonl" \
                                                            --num_workers 6 \
                                                            --testing;
done & done

多数決をしてissueに対してReproduction testを一つを決める

for st in {0..36..4}; do   en=$((st + 3));   
        echo "Processing ${st} to ${en}";   
        for num in $(seq $st $en); do     
            echo "Processing ${num}";     
            python agentless/test/run_reproduction_tests.py --run_id="reproduction_test_generation_filter_sample_${num}" \
                                                            --test_jsonl="results/swe-bench-lite/reproduction_test_samples/output_${num}_processed_reproduction_test.jsonl" \
                                                            --num_workers 6 \
                                                            --testing;
done & done

最後に選択されたreproduction testを用いてpatchを評価する

folder=results/swe-bench-lite/repair_sample_1
for num in {0..9..1}; do
    run_id_prefix=$(basename $folder); 
    python agentless/test/run_reproduction_tests.py --test_jsonl results/swe-bench-lite/reproduction_test_samples/reproduction_tests.jsonl \
                                                    --predictions_path="${folder}/output_${num}_processed.jsonl" \
                                                    --run_id="${run_id_prefix}_reproduction_${num}" --num_workers 10;
done

Reranking and patch selection

Regression testとreproduction testの結果からpatchをrerankして選択する

python agentless/repair/rerank.py --patch_folder results/swe-bench-lite/repair_sample_1/,results/swe-bench-lite/repair_sample_2/,results/swe-bench-lite/repair_sample_3/,results/swe-bench-lite/repair_sample_4/ \
                                  --num_samples 40 \
                                  --deduplicate \
                                  --regression \
                                  --reproduction

まとめ

  1. Agentlessの中身をコマンドベースで追いかけることで、実装までの理解にはまだほど遠いが全体像が理解できるようになる
    1. Localization:
      1. LLMによる候補ファイルの特定
      2. Embeddingを使った候補ファイルの特定
      3. 上記2つのマージ
      4. 関連するファイルからElement levelの関連部分の取得
      5. 関連エレメントから行レベルの関連部分を生成(サンプル数を指定可)
    2. Repair: ラインの位置と変更DiffからなるPatchをissueごとに複数生成する
      1. Localizationで取得した関連部分のサンプルに対してpatchsを複数生成
    3. Validation and Selection:
      1. Regression test (既存のテスト)の実行
      2. issueに対応するReproduction testを生成(複数)及び実行
      3. これらの結果から最終的なpatchを決定する

TODO

  1. https://github.com/swe-bench/SWE-bench の設定ができてないためregression testができてないので設定して更新
  2. 現状はSWEBench以外のレポに使う方法は載ってないので、任意のレポで試せるようにする
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?