Home 論文解説: SWE-agent — エージェント・コンピュータインターフェースによる自動バグ修正
投稿
キャンセル

📄 論文解説: SWE-agent — エージェント・コンピュータインターフェースによる自動バグ修正

論文概要(Abstract)

SWE-agentは、LLMエージェントがソフトウェアエンジニアリングタスク(バグ修正・機能追加)を効率的に実行するためのAgent-Computer Interface(ACI)を提案した論文である。従来のbashシェルを直接使う方式ではなく、エージェント専用に設計されたコマンド群(search、view、edit等)を提供することで、GPT-4ベースでSWE-bench 12.47%、SWE-bench Lite 18.00%を達成した。単純なbash使用(3.97%)と比較して3倍以上の改善を実現している。

この記事は Zenn記事: Gemini 3.1 Proで構築するマルチエージェント協調コーディングの実践手法 の深掘りです。

情報源

背景と動機(Background & Motivation)

LLMをソフトウェアエンジニアリングに適用する研究は急速に進展しているが、エージェントがどのようにコンピュータと対話するか(インターフェース設計)についての研究は不十分だった。人間のエンジニアがIDEやCLIツールを使ってコードを扱うように、LLMエージェントにも適切なインターフェースが必要である。

従来のアプローチではLLMにbashコマンドを直接生成させていたが、これには以下の問題があった:

  1. 出力の氾濫: catfind の出力が大量で、LLMのコンテキストを圧迫する
  2. エラーの不明瞭さ: bashのエラーメッセージはLLMにとって解釈が困難
  3. ガードレールの不在: 誤った編集操作を防ぐ仕組みがない(ファイル全体の上書きなど)
  4. 状態管理の欠如: 現在開いているファイルや位置の概念がない

SWE-agentはこれらを解決するため、LLMエージェント専用のインターフェース(ACI)を設計した。これは、Zenn記事でGemini 3.1 Proが提供する並列ツール呼び出しやthought signaturesの「ツール設計」面での知見を提供する。

主要な貢献(Key Contributions)

  • Agent-Computer Interface(ACI)の概念定義: LLMエージェントのためのインターフェース設計原則を3つ定式化し、実装として示した
  • 専用コマンドセットの設計: ファイルビューア、行単位エディタ、コード検索ツールを統合した12個のカスタムコマンド
  • SWE-benchでのSOTA達成: GPT-4ベースでSWE-bench 12.47%(2024年2月時点のSOTA)、SWE-bench Lite 18.00%
  • ACI設計の体系的評価: 各コマンドの寄与を定量的に分析し、インターフェース設計の指針を提示

技術的詳細(Technical Details)

ACI設計の3原則

SWE-agentが定式化したACI設計原則は以下の3つである:

原則1: 簡潔で情報密度の高いフィードバック

コマンドの出力は、LLMが1回のAPI呼び出しで理解できる量に収めるべきである。例えば、catコマンドは数千行を出力しうるが、ACI版のopenコマンドは常に100行のウィンドウで表示する。

\[\text{InfoDensity}(output) = \frac{\text{Useful tokens}}{\text{Total tokens}} \rightarrow \max\]

原則2: ガードレール付きの操作

エディタは構文チェック付きで、lintエラーのある変更を拒否する。これにより壊れたコードが保存されることを防ぐ。

\[\text{edit}(file, line_{start}, line_{end}, new\_code) = \begin{cases} \text{success} & \text{if } \text{lint}(new\_code) = \text{OK} \\ \text{reject} & \text{otherwise} \end{cases}\]

原則3: コンテキスト保持

現在のファイル、表示位置(ウィンドウ)、作業ディレクトリを暗黙的に管理し、エージェントが毎回これらを指定する必要をなくす。

カスタムコマンド一覧

SWE-agentは以下の12個のカスタムコマンドを提供する:

コマンド機能bash相当ACI改善点
open <file>ファイルを開く(100行ウィンドウ)cat出力量を制限
scroll_down次の100行を表示ウィンドウ管理
scroll_up前の100行を表示ウィンドウ管理
goto <line>指定行に移動位置管理
search_file <term>現在のファイル内検索grepファイルコンテキスト保持
search_dir <term>ディレクトリ内検索grep -r結果を要約表示
find_file <name>ファイル名検索find結果を要約表示
edit <start>:<end>行範囲を編集sedlint検証付き
create <file>新規ファイル作成touchテンプレート付き
submitパッチを提出git diff自動diff生成

ReAct実行ループ

SWE-agentはReAct(Reasoning + Acting)パターンで動作する:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
class SWEAgent:
    """SWE-agent の実行エンジン"""

    def __init__(self, model: str = "gpt-4", max_steps: int = 30):
        self.model = model
        self.max_steps = max_steps
        self.history: list[dict] = []

    def solve_issue(self, issue: str, repo_path: str) -> str:
        """GitHub Issueを解決するパッチを生成

        Args:
            issue: Issueの本文
            repo_path: リポジトリのパス

        Returns:
            unified diff形式のパッチ
        """
        system_prompt = self._build_system_prompt()
        self.history.append({"role": "system", "content": system_prompt})
        self.history.append({"role": "user", "content": issue})

        for step in range(self.max_steps):
            # Thought: LLMが推論
            response = self._call_llm(self.history)
            thought, action = self._parse_response(response)

            # Act: コマンドを実行
            observation = self._execute_action(action, repo_path)

            # 履歴に追加
            self.history.append({
                "role": "assistant",
                "content": f"Thought: {thought}\nAction: {action}"
            })
            self.history.append({
                "role": "user",
                "content": f"Observation: {observation}"
            })

            if action == "submit":
                return self._generate_patch(repo_path)

        return ""  # max_steps到達で空パッチ

    def _execute_action(self, action: str, repo_path: str) -> str:
        """ACIコマンドを実行し、整形された結果を返す

        Args:
            action: 実行するコマンド文字列
            repo_path: リポジトリパス

        Returns:
            コマンドの出力(最大100行に制限)
        """
        cmd, *args = action.split()

        if cmd == "open":
            return self._open_file(args[0])
        elif cmd == "edit":
            lines, content = self._parse_edit(args)
            result = self._apply_edit(lines, content)
            # ガードレール: lintチェック
            lint_result = self._run_lint()
            if lint_result != "OK":
                self._revert_edit()
                return f"Edit rejected: {lint_result}"
            return result
        elif cmd == "search_file":
            return self._search_in_file(" ".join(args))
        # ... 他のコマンド

エディタのガードレール機構

SWE-agentのエディタは以下の安全機構を持つ:

  1. lint検証: 編集後のファイルをflake8で検証し、構文エラーがあればロールバック
  2. 行範囲指定: ファイル全体の上書きを防ぎ、影響範囲を限定
  3. 前後コンテキスト表示: 編集後に変更箇所の前後5行を表示し、エージェントが変更を確認可能
  4. undo機能: 最後の編集を元に戻す機能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def apply_edit_with_guard(
    file_path: str,
    start_line: int,
    end_line: int,
    new_content: str,
) -> tuple[bool, str]:
    """ガードレール付きの編集操作

    Args:
        file_path: 編集対象ファイル
        start_line: 開始行(1-indexed)
        end_line: 終了行(1-indexed、inclusive)
        new_content: 新しい内容

    Returns:
        (成功フラグ, メッセージ)
    """
    # バックアップ作成
    backup = read_file(file_path)

    # 編集適用
    lines = backup.split('\n')
    new_lines = (
        lines[:start_line - 1]
        + new_content.split('\n')
        + lines[end_line:]
    )
    write_file(file_path, '\n'.join(new_lines))

    # lint検証
    lint_output = run_command(f"flake8 --select=E9,F821,F822,F823 {file_path}")
    if lint_output:
        # ロールバック
        write_file(file_path, backup)
        return False, f"Lint errors detected:\n{lint_output}"

    # 成功:前後コンテキストを表示
    context = get_context(file_path, start_line, end_line + len(new_content.split('\n')) - (end_line - start_line + 1))
    return True, f"Edit applied successfully:\n{context}"

実装のポイント(Implementation)

Dockerによるサンドボックス実行

SWE-agentの全コマンドはDockerコンテナ内で実行される。これにより:

  • ホストシステムへの影響を完全に隔離
  • 各タスクごとにクリーンな環境を提供
  • 任意のPythonバージョン・依存関係をインストール可能

コスト最適化

GPT-4での実行コストは約$4/タスク。主なコスト要因:

  • コンテキスト長: 30ステップ × 各ステップ2,000-4,000トークン ≈ 60,000-120,000トークン
  • 出力トークン: 各ステップ200-500トークン ≈ 6,000-15,000トークン

Zenn記事のGemini 3.1 Proにおけるthinking_level制御は、このコスト問題の直接的な解決策となる。探索フェーズ(search, open)ではthinking_level=lowを、編集フェーズ(edit)ではthinking_level=highを使うことで、品質を維持しつつコストを削減できる。

Gemini 3.1 Proとの接続点

SWE-agentのACI設計原則は、Zenn記事のGemini 3.1 Pro構成に以下のように適用可能:

  1. 並列ツール呼び出し + ACI: Gemini 3.1 Proの並列ツール呼び出しにSWE-agentのACIコマンドを登録すれば、search_filesearch_dirを同時実行してコード探索を高速化できる

  2. thought signatures + 状態管理: SWE-agentの「現在開いているファイル」「ウィンドウ位置」の状態管理は、thought signaturesの暗号化トークンで自然に実現される

  3. ADKツール登録: Google ADKのFunctionToolとしてACIコマンドを登録し、マルチエージェント間で共有可能

Production Deployment Guide

AWS実装パターン(コスト最適化重視)

規模月間リクエスト推奨構成月額コスト主要サービス
Small~3,000 (100/日)Serverless$60-180Lambda + Bedrock + S3
Medium~30,000 (1,000/日)Hybrid$500-1,200ECS Fargate + Bedrock + ECR
Large300,000+ (10,000/日)Container$3,000-7,000EKS + Karpenter + EC2 Spot

Small構成の詳細 (月額$60-180):

  • Lambda: 1GB RAM, 120秒タイムアウト、ACIコマンド実行 ($30/月)
  • Bedrock: Claude 3.5 Haiku、Prompt Caching有効 ($100/月)
  • S3: リポジトリスナップショット保存 ($5/月)
  • CloudWatch: 基本監視 + ステップ追跡 ($5/月)

コスト削減テクニック:

  • Bedrock Batch API: 非リアルタイムのバグ修正タスクで50%割引
  • thinking_level制御: 探索フェーズにlow、編集フェーズにhighを適用
  • Prompt Caching: ACIコマンド定義のシステムプロンプト部分で30-90%削減
  • ステップ数制限: max_steps=15で十分なケースが多い(コスト50%削減)

コスト試算の注意事項:

  • 上記は2026年2月時点のAWS ap-northeast-1(東京)リージョン料金に基づく概算値です
  • SWE-agentのDocker実行環境はECS/EKS上に構築する必要があります
  • 最新料金は AWS料金計算ツール で確認してください

Terraformインフラコード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# --- IAMロール ---
resource "aws_iam_role" "swe_agent" {
  name = "swe-agent-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Principal = { Service = "ecs-tasks.amazonaws.com" }
    }]
  })
}

resource "aws_iam_role_policy" "bedrock_and_s3" {
  role = aws_iam_role.swe_agent.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Action   = ["bedrock:InvokeModel"]
        Resource = "arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-*"
      },
      {
        Effect   = "Allow"
        Action   = ["s3:GetObject", "s3:PutObject"]
        Resource = "${aws_s3_bucket.repo_snapshots.arn}/*"
      }
    ]
  })
}

# --- ECS Fargate: SWE-agent実行環境 ---
resource "aws_ecs_task_definition" "swe_agent" {
  family                   = "swe-agent"
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  cpu                      = "1024"
  memory                   = "4096"
  execution_role_arn       = aws_iam_role.swe_agent.arn
  task_role_arn            = aws_iam_role.swe_agent.arn

  container_definitions = jsonencode([{
    name  = "swe-agent"
    image = "${aws_ecr_repository.swe_agent.repository_url}:latest"
    logConfiguration = {
      logDriver = "awslogs"
      options = {
        "awslogs-group"  = "/ecs/swe-agent"
        "awslogs-region" = "ap-northeast-1"
      }
    }
  }])
}

# --- S3: リポジトリスナップショット ---
resource "aws_s3_bucket" "repo_snapshots" {
  bucket = "swe-agent-repo-snapshots"
}

resource "aws_s3_bucket_lifecycle_configuration" "cleanup" {
  bucket = aws_s3_bucket.repo_snapshots.id
  rule {
    id     = "delete-old-snapshots"
    status = "Enabled"
    expiration { days = 7 }
  }
}

運用・監視設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import boto3

cloudwatch = boto3.client('cloudwatch')

# SWE-agentステップ数アラート
cloudwatch.put_metric_alarm(
    AlarmName='swe-agent-steps-exceeded',
    ComparisonOperator='GreaterThanThreshold',
    EvaluationPeriods=1,
    MetricName='StepCount',
    Namespace='Custom/SWEAgent',
    Period=3600,
    Statistic='Average',
    Threshold=25,
    AlarmDescription='SWE-agentのステップ数が閾値を超過'
)

コスト最適化チェックリスト

  • Docker実行環境: ECS Fargate使用(EC2管理不要)
  • Bedrock Batch API: 50%割引(非リアルタイム処理)
  • ステップ数制限: max_steps=15-20で十分な精度
  • thinking_level制御: 探索=low, 編集=high
  • Prompt Caching: ACIコマンド定義で30-90%削減
  • S3ライフサイクル: 7日でスナップショット自動削除
  • ECS Auto Scaling: 夜間はタスク数0に
  • CloudWatch Logs: 保持期間14日(コスト削減)
  • ECR: 古いイメージ自動削除
  • AWS Budgets: 月額予算設定(80%で警告)

実験結果(Results)

システムSWE-benchSWE-bench Lite手法
SWE-agent (GPT-4)12.47%18.00%ACI + ReAct
bash直接使用 (GPT-4)3.97%Raw bash
SWE-agent (Claude 3 Opus)10.55%ACI + ReAct
RAG baseline2.34%BM25検索のみ

ACI設計の効果分析:

設計要素ありなし効果
lint付きエディタ18.00%13.67%+4.33%
ファイルビューア(100行ウィンドウ)18.00%15.00%+3.00%
search_file/search_dir18.00%14.33%+3.67%

各ACI要素が独立に性能向上に寄与しており、特にlint付きエディタの効果が最も大きい。

実運用への応用(Practical Applications)

SWE-agentのACI設計原則は、Zenn記事のGemini 3.1 Proマルチエージェント構成で直接活用できる。

具体的な統合パターン:

  1. ADKのFunctionToolとしてACIコマンドを登録: search_fileedit等をGemini 3.1 ProのツールとしてADKに登録。thought signaturesにより、ファイルの閲覧状態が自動的に保持される

  2. マルチエージェント分業: MetaGPTの役割分担にSWE-agentのACIを組み合わせ、EngineerエージェントにはACIコマンドセットを、ReviewerエージェントにはACIの検索コマンドのみを付与する

  3. thinking_level × ACIフェーズ: 探索フェーズ(search, find, open)ではthinking_level=lowまたはmediumを、編集フェーズ(edit)ではthinking_level=highを使用し、コストを最適化

関連研究(Related Work)

  • SWE-bench (Jimenez et al., 2023): SWE-agentが評価に使用したベンチマーク。GitHubの実Issue 2294件を収集
  • AutoCodeRover (Zhang et al., 2024): AST解析によるコード探索を採用。SWE-agentのgrep/find方式と対照的
  • Agentless (Xia et al., 2024): エージェントなしの固定パイプラインアプローチ。シンプルだが24%を達成
  • OpenHands (Wang et al., 2024): SWE-agentの後継的プラットフォーム。CodeActアクション設計を採用

まとめと今後の展望

SWE-agentの最大の貢献は、LLMエージェントにとってインターフェース設計が性能に決定的な影響を与えることを実証した点にある。bash直接使用(3.97%)からACI設計(18.00%)への改善は、同じLLM(GPT-4)でもインターフェースの工夫だけで4.5倍の性能差が生まれることを示している。

Zenn記事のGemini 3.1 Proの文脈では、以下が特に重要である:

  • 並列ツール呼び出し機能にACIコマンドを登録することで、コード探索の効率が大幅に向上
  • thought signaturesがACIの「状態保持」原則を自然に実現
  • thinking_level制御がACIのフェーズ別コスト最適化を可能にする

今後は、ACIの設計原則をLLM自身が学習・最適化する方向(Meta-ACI)や、マルチモーダル対応(GUIの視覚的理解を含む)への発展が期待される。

参考文献

この投稿は CC BY 4.0 でライセンスされています。

論文解説: RAG-Fusion — マルチクエリ生成×RRFでRAG検索の網羅性を向上させる手法

NeurIPS 2024論文解説: Found in the Middle — Ms-PoEでLost in the Middle問題を解決する