0Pricing
AI Engineering Academy · 강의

코드 실행 루프

에이전트가 코드를 생성하고 샌드박스 실행기가 실행하며 stdout과 stderr를 캡처해 관찰 결과로 전달하고, 에이전트가 오류를 수정하는 작성-실행-관찰 루프를 설계합니다.

코드 실행 루프은(는) CoddyKit의 무료 AI Engineering Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Engineering Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

코드 에이전트: 코드 작성 및 실행

코드 실행 에이전트는 코드를 작성하고 실행한 뒤 출력을 관찰하며 작업이 완료될 때까지 반복하는 방식으로 문제를 해결하는 특수한 유형의 AI 에이전트입니다. 미리 정의된 도구만 사용하는 에이전트와 달리 코드 에이전트는 즉석에서 새로운 계산 도구를 만듭니다. 따라서 프로그래밍할 수 있는 모든 작업을 시도할 수 있을 만큼 매우 유연합니다.

작성-실행-관찰 루프

코드 실행 에이전트의 핵심은 세 단계로 이루어진 루프입니다. 작성 — 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은 일반적으로 생성한 코드를 마크다운 펜스 코드 블록으로 감쌉니다: ```python ... ```. 실행 루프는 코드를 실행하기 전에 이러한 블록에서 코드를 안정적으로 추출해야 합니다. 정규 표현식이나 간단한 구문 분석기를 사용하여 펜스 블록을 찾고, 중첩된 백틱, 한 응답에 여러 코드 블록이 있는 경우, 언어 지정자가 없는 코드와 같은 예외 상황을 처리하십시오.

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')

반복 간 데이터 전달

코드 실행 루프의 한 가지 과제는 반복 간 상태 지속성입니다. 각 코드 블록이 새 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에 다시 전달하면 토큰을 낭비하고 문맥 창을 초과할 수 있습니다. 대화에 추가하기 전에 항상 실행 출력을 잘라내십시오. 일반적인 기본값으로 2000~5000자를 사용하고, 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/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Engineering Academy 강의 전체를 잠금 해제할 수 있습니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“코드 실행 루프”에서 뭘 배우나요?

에이전트가 코드를 생성하고 샌드박스 실행기가 실행하며 stdout과 stderr를 캡처해 관찰 결과로 전달하고, 에이전트가 오류를 수정하는 작성-실행-관찰 루프를 설계합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Engineering Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

AI Engineering Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 AI Engineering Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“코드 실행 루프” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 AI Engineering Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 AI Engineering Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 코드 실행 루프
  2. Docker와 RestrictedPython을 활용한 샌드박싱
  3. 실행 단계 간 상태 관리
  4. 데이터 분석 에이전트 구축
← AI Engineering Academy(으)로 돌아가기