0Pricing
AI Engineering Academy · レッスン

コード実行ループ

エージェントがコードを生成し、サンドボックス化された実行環境が実行し、stdoutとstderrを取得して観測結果として返し、エージェントがエラーを修正するwrite-execute-observeループを設計します。

「コード実行ループ」はCoddyKit上の無料AI Engineering Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Engineering Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Engineering Academyコースには全4レッスンが含まれています。

コードエージェント:コードの記述と実行

コード実行エージェントは、コードを書いて実行し、出力を確認し、タスクが完了するまで反復することで問題を解決する特殊なAIエージェントです。あらかじめ定義されたツールだけを使うエージェントとは異なり、コードエージェントはその場で新しい計算ツールを作成します。そのため非常に柔軟で、プログラムとして実装できるタスクであれば、コードエージェントで試行できます。

記述・実行・観察ループ

コード実行エージェントの中核は、次の3つのステップからなるループです。記述 — LLMがタスクの現在のステップを解決するPythonコードを生成します。実行 — コードをサンドボックス環境で実行し、stdout/stderrを取得します。観察 — 実行結果を新しい観察結果としてLLMに返し、LLMはそれをもとに次に記述する内容を判断します。タスクが完了するか、反復回数の上限に達するまで、このループを続けます。

def code_execution_loop(task: str, max_iterations=10):
    messages = [
        {'role': 'system', 'content': 'You are a Python coding agent. Write code to solve tasks step by step.'},
        {'role': 'user', 'content': task}
    ]
    
    for i in range(max_iterations):
        # WRITE: LLM generates code
        response = llm.complete(messages)
        code = extract_code_block(response)
        
        if not code:
            return response  # LLM gave a final answer without code
        
        # EXECUTE: run the code
        output, error = execute_safely(code)
        
        # OBSERVE: feed output back
        observation = f'Output:\n{output}' if not error else f'Error:\n{error}'
        messages.append({'role': 'assistant', 'content': response})
        messages.append({'role': 'user', 'content': observation})
    
    return 'Max iterations reached'

LLM出力からのコードブロックの抽出

LLMは通常、生成したコードをMarkdownのフェンス付きコードブロックで囲みます。```python ... ```。実行ループでは、実行前にこれらのブロックからコードを確実に抽出する必要があります。正規表現または単純なパーサーを使ってフェンス付きブロックを検索し、ネストしたバッククォート、1つの応答内に複数のコードブロックがある場合、言語指定子がないコードなどのエッジケースにも対応してください。

import re

def extract_code_block(response: str) -> str | None:
    # Match ```python ... ``` or ``` ... ```
    pattern = r'```(?:python)?\n(.*?)```'
    matches = re.findall(pattern, response, re.DOTALL)
    if not matches:
        return None
    # Return the LAST code block (often the most complete version)
    return matches[-1].strip()

# Test
sample_response = '''I will calculate the sum:\n\n```python\nnumbers = [1, 2, 3, 4, 5]\nprint(sum(numbers))\n```'''
code = extract_code_block(sample_response)
print(repr(code))  # 'numbers = [1, 2, 3, 4, 5]\nprint(sum(numbers))'

stdoutとstderrの取得

エージェントが生成したコードを実行するときは、LLMに返すためにstdout(通常の出力)とstderr(エラーメッセージやトレースバック)の両方を取得する必要があります。Pythonのsubprocessモジュールを使うのが最も簡単です。コードを別プロセスとして実行し、両方のストリームを取得します。コードがハングしてエージェントを停止させないよう、タイムアウトを設定してください。

import subprocess
import tempfile
import os

def execute_code(code: str, timeout_seconds=30) -> tuple[str, str]:
    # Write code to a temp file
    with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
        f.write(code)
        tmp_path = f.name
    
    try:
        result = subprocess.run(
            ['python', tmp_path],
            capture_output=True,
            text=True,
            timeout=timeout_seconds
        )
        stdout = result.stdout[:5000]  # cap output length
        stderr = result.stderr[:2000]  # cap error length
        return stdout, stderr
    except subprocess.TimeoutExpired:
        return '', f'TimeoutError: code exceeded {timeout_seconds}s limit'
    finally:
        os.unlink(tmp_path)  # always clean up temp file

エラーへの適切な対応

コードでエラーが発生すると、エラーメッセージ(トレースバック、例外の種類、行番号)が観察結果としてLLMに返されます。LLMはそのエラーを分析し、修正したコードを記述します。LLMが効果的にデバッグできるように、観察結果には正確なエラーテキストとエラーの原因となったコード行を含め、再試行する前に修正するようLLMに明示的に指示してください。

def format_error_observation(code: str, error: str) -> str:
    lines = code.split('\n')
    
    # Extract line number from traceback if available
    line_match = re.search(r'line (\d+)', error)
    error_context = ''
    if line_match:
        line_num = int(line_match.group(1))
        if 1 <= line_num <= len(lines):
            error_context = f'\nFailing line: {lines[line_num - 1].strip()}'
    
    return f'''Execution failed with error:{error_context}\n\n{error}\n\nPlease analyze the error and write corrected code.'''

# Usage in loop
output, err = execute_code(code)
if err:
    observation = format_error_observation(code, err)
else:
    observation = f'Output:\n{output}\n\nContinue with the next step or provide the final answer.'

タスク完了の検出

コード実行ループは、いつ停止すべきかを判断できなければなりません。一般的な完了シグナルには、LLMがコードブロックを含まない応答(自然言語の回答のみ)を返すこと、LLMが# TASK_COMPLETEのような特殊なマーカーを記述すること、エージェントが作成するよう指示された出力ファイルがコードによって生成されること、検証関数が出力が成功条件を満たしていると確認することなどがあります。必ずフォールバックとして反復回数の上限も実装してください。

COMPLETION_MARKERS = ['TASK COMPLETE', 'FINAL ANSWER:', 'DONE:']

def is_task_complete(response: str, code: str | None, output: str, success_fn=None) -> bool:
    # Check for explicit completion markers
    for marker in COMPLETION_MARKERS:
        if marker in response.upper():
            return True
    
    # No code generated - LLM is done
    if code is None:
        return True
    
    # Custom success function (e.g., check output file exists)
    if success_fn and success_fn(output):
        return True
    
    return False

# Example success function
def report_was_generated(output: str) -> bool:
    import os
    return os.path.exists('analysis_report.pdf')

反復間でのデータ受け渡し

コード実行ループにおける課題の1つが、反復間の状態の永続化です。各コードブロックは新しいPythonプロセスで実行されるため、ある反復で定義した変数は次の反復では利用できません。解決策としては、中間データをファイルに書き込む、exec()でコードを注入する永続プロセスを使う、各コードブロックの冒頭で必要な変数を再定義するようLLMに明示的に指示する、といった方法があります。

# Strategy 1: Save to files between iterations
# Iteration 1: LLM writes
'''
import pandas as pd
df = pd.read_csv('data.csv')
df_cleaned = df.dropna()
df_cleaned.to_parquet('cleaned.parquet')  # save for next iteration
print('Cleaned rows:', len(df_cleaned))
'''

# Iteration 2: LLM reads previous output
'''
import pandas as pd
df = pd.read_parquet('cleaned.parquet')  # reload from file
result = df.groupby('category').sum()
result.to_csv('result.csv')
print(result.head())
'''

システムプロンプトの構成

コード実行エージェントのシステムプロンプトでは、LLMがループを効果的に使う方法を教える必要があります。含めるべき主な要素は、実行可能なPythonコードブロックの書き方、先に進む前に中間出力を確認する方法、タスク完了の通知方法、サンドボックスで利用できるライブラリ、エージェントが読み書きできるファイルパスです。

CODE_AGENT_SYSTEM_PROMPT = '''
You are a Python code execution agent. Solve tasks by writing and running code.

Rules:
1. Write ALL code inside ```python ... ``` blocks.
2. Write small, testable code blocks - do not try to do everything in one block.
3. When you see execution output, analyze it and decide whether to continue or fix errors.
4. Available libraries: pandas, numpy, matplotlib, requests, json, os, pathlib.
5. You can read/write files only in /workspace/ directory.
6. When the task is fully complete, say TASK COMPLETE and summarize the result.
7. If you are stuck after 3 attempts at the same error, say ESCALATE and explain the problem.
'''

出力の切り詰めとトークン管理

エージェントが生成したコードは、DataFrameの表示、大量のリスト、詳細なログなど、非常に大きな出力を生成することがあります。出力全体をLLMに返すとトークンを無駄に消費し、コンテキストウィンドウを超える可能性があります。会話に追加する前に、必ず実行出力を切り詰めてください。適切な初期値は2,000~5,000文字で、出力が切り詰められたことを示す注記も追加します。これにより、LLMはさらに確認すべき出力が存在する可能性を把握できます。

MAX_OUTPUT_CHARS = 3000

def format_observation(stdout: str, stderr: str) -> str:
    if stderr:
        # Errors take priority - show full error
        return f'Error:\n{stderr[:MAX_OUTPUT_CHARS]}'
    
    if len(stdout) > MAX_OUTPUT_CHARS:
        truncated = stdout[:MAX_OUTPUT_CHARS]
        remaining = len(stdout) - MAX_OUTPUT_CHARS
        return f'{truncated}\n... [output truncated, {remaining} more characters]'
    
    return f'Output:\n{stdout}' if stdout else 'Code executed successfully (no output)'

実際のコードループ

データ分析用の実際のコード実行エージェントでは、CSVの読み込み、構造の確認、データのクリーニング、統計量の計算、グラフの生成、概要レポートの作成を行うために、5~15回の反復を実行することがあります。各反復は前の反復を基盤とし、LLMは実行時に見つかった実際のデータの値や形状に応じてアプローチを調整します。この動的な適応こそが、探索的なタスクでコードエージェントを非常に強力なものにします。

コードループにおけるセキュリティ上の考慮事項

LLMが生成したコードを自分のインフラストラクチャ上で実行することは、重大なセキュリティリスクになります。サンドボックス化せずにエージェントのコードを実行してはいけません。LLMは、意図せず(またはプロンプトインジェクションによって)ファイルを削除する、データを外部へ流出させる、外部サービスへのネットワーク要求を行う、システムリソースを使い果たすコードを生成する可能性があります。必ず、厳格なリソース制限、ネットワーク制限、ファイルシステム境界を設けた分離環境で実行してください。

理解度チェック

このレッスンで学んだコード実行ループについて、理解度を確認しましょう。

レッスンのまとめ

このレッスンでは、記述・実行・観察ループがコード実行エージェントの中核パターンであること、実行時のstdoutとstderrが観察結果として返され、LLMによる次のコード生成を導くこと、そして出力の切り詰めと反復回数の上限が不可欠な安全対策であることを学びました。次は、DockerとRestrictedPythonを使ったコード実行のサンドボックス化について学びます。

よくある質問

「コード実行ループ」レッスンは無料ですか?

はい。「コード実行ループ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Engineering Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Engineering Academyコースには全4レッスンが含まれています。

「コード実行ループ」で何を学びますか?

エージェントがコードを生成し、サンドボックス化された実行環境が実行し、stdoutとstderrを取得して観測結果として返し、エージェントがエラーを修正するwrite-execute-observeループを設計します。 ブラウザで直接実行するハンズオンコードでAI Engineering Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

AI Engineering Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAI Engineering Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「コード実行ループ」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAI Engineering Academyレッスンでコードを書いて実行できますか?

はい。すべてのAI Engineering Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. コード実行ループ
  2. DockerとRestrictedPythonによるサンドボックス化
  3. 実行ステップ間の状態管理
  4. データ分析エージェントを構築する
← AI Engineering Academyに戻る