커맨드라인 코드 실행기(CodeExecutor)와 Docker
커맨드라인 코드 실행기(CodeExecutor)와 Docker
LLM이 만들어 낸 코드를 실제로 실행하는 일, 특히 에이전트가 생성한 코드를 안전하게 돌리는 일은 생각보다 번거로워요. AutoGen은 이 작업을 전담하는 **코드 실행기(Code Executor)**를 제공해서, 모델이 쓴 코드 블록을 파일로 저장하고 새 프로세스에서 실행해 주죠. 가장 단순한 형태인 커맨드라인 코드 실행기부터, 도커 컨테이너 안에서 실행하는 방법, 그리고 가상환경을 지정하는 방법까지 하나씩 살펴볼게요.
출처: 공식문서
커맨드라인 코드 실행이란
커맨드라인 코드 실행은 코드를 실행하는 가장 단순한 형태예요. 일반적으로 각 코드 블록을 파일에 저장한 뒤 그 파일을 실행하는 방식이죠. 즉 코드 블록 하나마다 새로운 프로세스에서 실행됩니다. 실행기에는 두 가지 형태가 있어요.
- Docker (
autogen_ext.code_executors.docker.DockerCommandLineCodeExecutor) — 모든 명령을 Docker 컨테이너 안에서 실행해요. - Local (
autogen_ext.code_executors.local.LocalCommandLineCodeExecutor) — 모든 명령을 호스트 머신에서 실행해요.
Docker
`DockerCommandLineCodeExecutor`를 쓰려면 `autogen-ext[docker]` 패키지가 설치돼 있어야 해요. 자세한 내용은 [Packages Documentation](https://microsoft.github.io/autogen/dev/packages/index.html)을 참고하세요.
DockerCommandLineCodeExecutor는 Docker 컨테이너를 하나 만들고, 그 컨테이너 안에서 모든 명령을 실행해요. 기본 이미지는 python:3-slim이고, 생성자에 image 파라미터를 넘기면 바꿀 수 있어요. 이미지가 로컬에 없으면 실행기가 알아서 풀(pull)을 시도하죠. 그래서 이미지를 로컬에 미리 만들어 두기만 하면 됩니다. 이 실행기와 호환되려면 이미지에 sh와 python만 설치돼 있으면 되기 때문에, 필요한 시스템 의존성을 갖춘 커스텀 이미지를 만드는 것이 간단하고 효과적인 방법이에요.
실행기를 컨텍스트 매니저로 사용하면 작업이 끝난 뒤 컨테이너가 자동으로 정리돼요. 그렇지 않으면 프로그램이 종료될 때 atexit 모듈이 컨테이너를 멈춰 줍니다.
컨테이너 살펴보기
어떤 이유로든(예: 컨테이너를 검사하려고) AutoGen 작업이 끝난 뒤에도 컨테이너를 유지하고 싶다면, 실행기를 만들 때 auto_remove 파라미터를 False로 설정하면 돼요. 그리고 stop_container를 False로 두면 실행이 끝나도 컨테이너가 멈추지 않게 할 수도 있어요.
예시
from pathlib import Path
from autogen_core import CancellationToken
from autogen_core.code_executor import CodeBlock
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor
work_dir = Path("coding")
work_dir.mkdir(exist_ok=True)
async with DockerCommandLineCodeExecutor(work_dir=work_dir) as executor: # type: ignore
print(
await executor.execute_code_blocks(
code_blocks=[
CodeBlock(language="python", code="print('Hello, World!')"),
],
cancellation_token=CancellationToken(),
)
)
도커 기반 애플리케이션과 도커 기반 실행기의 결합
애플리케이션을 도커 이미지로 묶는 게 좋을 때가 있어요. 그런데 컨테이너화된 애플리케이션이 어떻게 다른 컨테이너에서 코드를 실행할 수 있을까요? 여기서 권장하는 접근 방식은 **"Docker out of Docker"**예요. 메인 AutoGen 컨테이너에 Docker 소켓을 마운트해서, 호스트에서 "형제(sibling)" 컨테이너를 생성하고 제어할 수 있게 하는 방법이죠. 이 방식은 메인 컨테이너 안에 Docker 데몬을 실행해 그 안에 컨테이너를 만드는 "Docker in Docker"보다 더 좋아요. 더 자세한 내용은 여기에서 읽을 수 있어요.
이렇게 하려면 애플리케이션을 실행하는 컨테이너에 Docker 소켓을 마운트해야 해요. docker run 명령에 다음을 추가하면 됩니다.
-v /var/run/docker.sock:/var/run/docker.sock
이러면 애플리케이션 컨테이너가 호스트에서 형제 컨테이너를 생성하고 제어할 수 있게 돼요.
만약 애플리케이션 컨테이너에 작업 디렉토리를 바인딩해야 하는데 그 디렉토리가 호스트 머신에 있다면, bind_dir 파라미터를 사용하세요. 이 파라미터를 쓰면 애플리케이션 컨테이너가 호스트 디렉토리를 새로 만든 컨테이너에 바인딩해서 그 디렉토리의 파일에 접근할 수 있게 해줘요. bind_dir을 지정하지 않으면 work_dir로 폴백(fallback)됩니다.
Local
Local 버전은 코드를 로컬 시스템에서 실행해요. 주의해서 사용하세요.
애플리케이션을 실행하는 호스트 머신에서 바로 코드를 실행하고 싶다면 LocalCommandLineCodeExecutor를 사용할 수 있어요.
예시
from pathlib import Path
from autogen_core import CancellationToken
from autogen_core.code_executor import CodeBlock
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
work_dir = Path("coding")
work_dir.mkdir(exist_ok=True)
local_executor = LocalCommandLineCodeExecutor(work_dir=work_dir)
print(
await local_executor.execute_code_blocks(
code_blocks=[
CodeBlock(language="python", code="print('Hello, World!')"),
],
cancellation_token=CancellationToken(),
)
)
가상환경 안에서 Local 실행하기
애플리케이션 셋업 과정에서 만들어진 가상환경 안에서 코드가 실행되길 원한다면, 새로 만들 환경의 디렉토리를 지정하고 그 컨텍스트를 LocalCommandLineCodeExecutor에 넘겨주세요. 이렇게 하면 실행기가 애플리케이션이 살아있는 동안 그 가상환경을 일관되게 사용해서, 의존성을 격리하고 통제된 런타임 환경을 보장해요.
import venv
from pathlib import Path
from autogen_core import CancellationToken
from autogen_core.code_executor import CodeBlock
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
work_dir = Path("coding")
work_dir.mkdir(exist_ok=True)
venv_dir = work_dir / ".venv"
venv_builder = venv.EnvBuilder(with_pip=True)
venv_builder.create(venv_dir)
venv_context = venv_builder.ensure_directories(venv_dir)
local_executor = LocalCommandLineCodeExecutor(work_dir=work_dir, virtual_env_context=venv_context)
await local_executor.execute_code_blocks(
code_blocks=[
CodeBlock(language="bash", code="pip install matplotlib"),
],
cancellation_token=CancellationToken(),
)
보시다시피 코드가 성공적으로 실행됐고, 설치된 패키지는 새로 만든 가상환경 안에만 격리돼서 전역 환경에는 영향을 주지 않아요.