코딩 에이전트는 대규모 언어 모델(LLM)을 추론 코어로 사용하여 코드를 자율적으로 작성, 실행, 반복 개선하는 AI 시스템입니다. 편집기에서 코드 완성을 제안하는 코드 어시스턴트와 달리, 코딩 에이전트는 관찰-결정-실행의 전체 루프를 실행합니다. 즉, 파일을 읽고, 변경 사항을 작성하고, 명령을 실행하고, 출력을 확인한 후 작업이 완료될 때까지 수정합니다.
이 글에서는 해당 루프(플래너, LLM 추론 계층, 도구, 샌드박스 실행 환경)의 작동 방식을 설명한 다음, Novita의 LLM API와 에이전트 샌드박스를 사용하여 하나를 구축하는 방법을 보여줍니다.
코딩 에이전트의 정의
코드 어시스턴트와 코딩 에이전트의 차이는 실행에 있습니다. 코드 어시스턴트는 제안을 생성하고 멈춥니다. AI 코딩 에이전트는 코드를 생성하고, 실행하고, 결과를 읽고, 목표가 달성되거나 막힐 때까지 계속 진행합니다.
이러한 실행 능력에는 세 가지 구체적인 요구 사항이 있습니다.
- 도구 접근 — 파일 읽기, 파일 쓰기, 셸 명령 실행 능력
- 샌드박스 환경 — 문제가 발생해도 호스트 시스템을 손상시키지 않을 코드 실행 공간
- 지속적 컨텍스트 — 도구 출력이 모델의 컨텍스트로 다시 전달되어 발생한 일을 추론할 수 있도록 함
세 가지 모두 없으면 코드를 작성할 수 있는 챗봇에 불과합니다. 세 가지 모두 갖추면 에이전트가 됩니다.
"코드 에이전트"라는 용어는 IDE 인라인 제안부터 대략적으로 지정된 작업을 파악하고, 관련 파일을 찾아내고, 변경하고, 각 단계마다 인간의 개입 없이 제대로 작동하는지 확인할 수 있는 완전 자율 시스템까지 광범위하게 사용됩니다. 개발자가 “최고의 코드 에이전트” 옵션을 비교할 때는 일반적으로 후자, 즉 최소한의 도움으로 다단계 코딩 작업을 안정적으로 완료하는 시스템을 의미합니다.
코딩 에이전트의 네 가지 계층
프로덕션 등급의 AI 코딩 에이전트는 모두 네 가지 식별 가능한 구성 요소를 갖습니다. 구현 세부 사항(프레임워크, LLM, 샌드박스 제공자)은 다르지만 아키텍처는 일관됩니다.
1. 플래너
플래너는 작업 설명을 받아 에이전트가 실행할 단계로 나눕니다. 간단한 작업의 경우 이는 모델의 추론 내에서 암시적으로 발생합니다. 복잡한 작업(“이 서비스를 새 인증 라이브러리로 마이그레이션”)의 경우 명시적인 계획 단계를 통해 모델이 각 단계 후 상태를 업데이트하며 작업할 번호가 매겨진 작업 목록을 생성합니다.
계획은 또한 중단 시점을 결정합니다. 완료 기준이 없는 에이전트는 무한정 개선을 추가하거나, 더 나쁜 경우 실패한 단계에서 루프에 빠집니다. 대부분의 구현은 시스템 프롬프트에 작업 성공 조건을 인코딩하고 모델이 완료 시점을 결정하도록 합니다.
2. LLM 추론 계층
LLM은 모든 AI 코딩 에이전트의 추론 코어입니다. 다음에 호출할 도구, 전달할 인수, 결과를 해석하는 방법을 결정합니다. 이 결정은 구조화된 도구 호출(함수 이름과 매개변수가 포함된 JSON 객체)로 표현되며, 프레임워크는 이를 실제 실행 계층으로 전달합니다.
코드 에이전트의 경우 LLM은 다음을 안정적으로 처리해야 합니다. 긴 컨텍스트(도구 결과가 빠르게 누적됨), 일관된 형식의 도구 호출 반환(10단계 워크플로의 6단계에서 잘못 구성된 JSON은 전체 실행을 중단시킴), 여러 순차적 도구 호출에 걸친 상태 변경 추론.
여기서 추론 제공자가 중요합니다. OpenAI 호환 형식의 함수 호출을 지원하는 API, 모델 수준에서 유효한 JSON을 강제하는 구조화된 출력, 병렬 하위 작업을 생성하는 에이전트 워크로드에 충분한 동시성 제한이 필요합니다. Novita AI의 LLM API는 OpenAI 호환 엔드포인트로 이 세 가지를 모두 제공하므로 도구 호출 구문 분석 로직을 다시 작성하지 않고도 모델을 교체할 수 있습니다.
3. 도구 계층
도구는 에이전트와 세계 간의 인터페이스입니다. 최소 코딩 에이전트에는 네 가지가 필요합니다.
| 도구 | 기능 |
|---|---|
read_file |
주어진 경로의 파일 내용 반환 |
write_file |
파일 경로에 문자열 쓰기 |
run_command |
셸 명령을 실행하고 stdout + stderr 반환 |
list_directory |
경로의 파일 및 디렉터리 나열 |
각 도구는 완전한 출력을 반환해야 합니다. 잘린 결과나 묵시적 실패는 에이전트의 코드베이스 모델을 손상시키고 이후에 복합 오류를 유발합니다. 특히 run_command 도구는 stdout과 stderr를 모두 캡처해야 합니다. 에이전트는 성공 출력보다 오류 출력에서 더 많은 것을 배우는 경우가 많기 때문입니다.
일부 에이전트는 코드베이스 전체에서 grep 스타일 조회를 위한 search_files 도구나 외부 문서 읽기를 위한 fetch_url 도구를 추가합니다. 적절한 도구 세트는 작업 영역에 따라 달라집니다. 순수 코드 작업의 경우 위의 네 가지로 대부분의 경우를 처리할 수 있습니다.
4. 샌드박스
샌드박스는 에이전트의 명령이 실제로 실행되는 완전히 격리된 Linux 환경입니다. 이는 두 가지 이유로 중요합니다.
첫째, 보안입니다. 에이전트는 사용자 프롬프트, 검색된 문서, 추론된 패턴에서 코드를 생성합니다. 선의의 에이전트라도 파일을 삭제하거나, 네트워크 연결을 열거나, 무제한 리소스를 소비하는 코드를 생성할 수 있습니다. 샌드박스는 모든 손상을 격리된 환경 내에 유지합니다.
둘째, 상태 유지입니다. 좋은 샌드박스는 세션 내에서 도구 호출 간에 파일 시스템 상태를 보존합니다. 에이전트가 2단계에서 파일을 생성했다면 8단계에서도 여전히 존재해야 합니다. 각 명령이 새로운 환경에서 실행되는 상태 비저장 컨테이너 방식은 실제 코딩 작업에 적합하지 않습니다.
Novita 에이전트 샌드박스는 Firecracker 마이크로VM을 기반으로 구축되어 표준 컨테이너보다 강력한 커널 수준 격리를 제공합니다. 세션은 최대 24시간 실행 가능하며, 명령 간에 파일 시스템 상태가 유지되고, 콜드 스타트는 200ms 미만입니다. 이는 샌드박스가 시작되기를 기다리는 시간이 대화형 워크플로를 방해하지 않을 정도로 빠릅니다.
실행 루프의 작동 방식
구체적인 예를 들면 루프를 더 쉽게 이해할 수 있습니다. 작업이 "/login 엔드포인트에 속도 제한 추가"라고 가정해 보겠습니다.
-
계획 — 모델이 작업을 읽고 필요한 것이 무엇인지 파악합니다. 로그인 경로 찾기, 현재 핸들러 이해, 속도 제한 미들웨어 추가, 테스트 실행으로 확인.
-
관찰 — 에이전트가
list_directory를 호출하여 경로 파일을 찾은 다음 로그인 핸들러에서read_file을 호출합니다. 파일 내용이 모델 컨텍스트에 추가됩니다. -
결정 — 모델이 현재 코드에 대해 추론하고 수행할 작업을 결정합니다. 속도 제한 라이브러리 설치, 핸들러 수정, 테스트 추가.
-
실행 — 에이전트가
run_command("pip install slowapi")를 호출한 다음 수정된 핸들러로write_file을 호출하고run_command("pytest tests/test_login.py")를 호출합니다. -
다시 관찰 — 테스트 출력이 컨텍스트로 다시 전달됩니다. 테스트가 실패하면 모델이 역추적을 읽고, 오류를 식별하고, 수정된 파일을 작성합니다.
-
완료 — 테스트를 통과하고 모델에 보류 중인 단계가 없으면 최종 요약을 반환합니다.
이 루프는 단일 세션 내에서 실행됩니다. 컨텍스트 창은 에이전트의 작업 기억입니다. 읽은 모든 파일, 모든 명령 출력, 모든 도구 호출이 여기에 누적됩니다. 이것이 코딩 에이전트에게 컨텍스트 길이가 매우 중요한 이유입니다. 실제 리팩토링 작업은 15단계까지 쉽게 100K 토큰을 채울 수 있습니다. 에이전트가 단일 턴 채팅과 다르게 추론 제공자에 부담을 주는 방법을 확인하세요.
Novita로 코딩 에이전트 구축
다음 예제는 Novita의 LLM API와 에이전트 샌드박스를 연결합니다. Novita의 엔드포인트를 가리키는 Python OpenAI SDK를 사용합니다. Novita의 모델은 OpenAI API와 동일한 함수 호출 인터페이스를 사용하므로 통합에 사용자 정의 파싱이 필요하지 않습니다.
import os
import json
from openai import OpenAI
from novita_sandbox.code_interpreter import Sandbox
client = OpenAI(
base_url="https://api.novita.ai/openai",
api_key=os.environ["NOVITA_API_KEY"],
)
sandbox = Sandbox.create(timeout=1800)
def read_file(path: str) -> str:
try:
return sandbox.files.read(path)
except Exception as e:
return f"Error: {e}"
def write_file(path: str, content: str) -> str:
try:
sandbox.files.write(path, content)
return f"Written to {path}"
except Exception as e:
return f"Error: {e}"
def run_command(cmd: str) -> str:
try:
result = sandbox.commands.run(cmd)
return str(result)
except Exception as e:
return f"Error: {e}"
tools = [
{
"type": "function",
"function": {
"name": "read_file",
"description": "Read the contents of a file",
"parameters": {
"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"],
},
},
},
{
"type": "function",
"function": {
"name": "write_file",
"description": "Write content to a file",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string"},
"content": {"type": "string"},
},
"required": ["path", "content"],
},
},
},
{
"type": "function",
"function": {
"name": "run_command",
"description": "Run a shell command in the sandbox and return output",
"parameters": {
"type": "object",
"properties": {"cmd": {"type": "string"}},
"required": ["cmd"],
},
},
},
]
dispatch = {
"read_file": read_file,
"write_file": write_file,
"run_command": run_command,
}
def run_agent(task: str, model: str) -> str:
messages = [
{
"role": "system",
"content": (
"You are a coding agent with access to a Linux sandbox. "
"Complete tasks by calling tools. When done, return a plain-text summary."
),
},
{"role": "user", "content": task},
]
while True:
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tools,
tool_choice="auto",
)
msg = response.choices[0].message
messages.append(msg)
if not msg.tool_calls:
return msg.content
for call in msg.tool_calls:
fn = dispatch[call.function.name]
args = json.loads(call.function.arguments)
result = fn(**args)
messages.append(
{
"role": "tool",
"tool_call_id": call.id,
"content": result,
}
)
# <model-id>를 novita.ai/docs의 함수 호출 모델로 교체하세요
result = run_agent(
task="Write a Python script that counts words in a text file and run it on a sample input",
model="<model-id>",
)
print(result)
sandbox.kill()
이 구현에 대한 몇 가지 참고 사항:
while True루프는 모델이 도구 호출 없이 메시지를 반환할 때까지 실행됩니다. 이는 에이전트가 작업을 완료했다고 간주하는 신호입니다.- 도구 결과는
role: tool항목으로messages에 추가됩니다. 이것이 단계 간에 공유 컨텍스트를 구축하는 방법입니다. sandbox.kill()은 컴퓨팅 리소스를 해제합니다. 세션이 종료되면 항상 호출하세요.
지원되는 함수 호출 모델 ID는 Novita 함수 호출 문서를 확인하세요. Gradio UI를 포함한 더 완전한 워크스루는 Novita의 에이전트 샌드박스로 코딩 에이전트 구축하기를 참조하세요.
코드 에이전트에 적합한 LLM 선택
HumanEval과 SWE-bench는 단일 턴 코드 생성을 측정합니다. 에이전트 워크로드는 다릅니다. 실제로 프로덕션 코드 에이전트를 중단시키는 것은 도구 호출 형식 지정 실패입니다. 벤치마크에서 좋은 점수를 받지만 복잡한 다중 턴 세션에서 가끔 잘못된 형식의 JSON을 반환하는 모델은 디버깅하기 어려운 방식으로 실패합니다.
AI 코딩 에이전트의 실용적인 평가 기준:
- 도구 호출 신뢰성 — 모델이 20+ 단계 세션에서 얼마나 일관되게 잘 구성된 도구 호출을 반환하는가?
- 컨텍스트 유지 — 모델이 40단계 전에 읽은 파일을 올바르게 참조하는가?
- 지시 따르기 — 에이전트가 작업에 집중하는가, 아니면 관련 없는 파일을 수정하기 시작하는가?
- 코드 정확성 — 생성된 코드가 실제로 실행되는가, 아니면 여러 번의 수정 루프가 필요한가?
대표적인 실제 코딩 작업 세트를 실행하고 작업 완료율을 측정하는 것이 공개 벤치마크보다 더 유용합니다. 자체 코드베이스에서 20~30개의 작업을 선택하고, 후보 모델에 대해 실행하고, 인간의 개입 없이 완료되는 작업 수를 계산하세요.
추론 가격은 에이전트 규모에서 빠르게 누적됩니다. 단일 세션이 모든 턴에서 200K~500K 토큰을 소비할 수 있습니다. 프롬프트 캐싱과 경쟁력 있는 토큰당 요금을 제공하는 제공자는 하루에 수백 개의 에이전트 세션을 실행할 때 경제성을 크게 변화시킵니다.
비용 효율적인 경로로서의 오픈소스 모델
폐쇄형 프런티어 모델은 코딩 벤치마크에서 선두를 유지해 왔지만, 최고 오픈소스 모델과의 격차는 상당히 좁혀졌습니다. DeepSeek V3 및 Qwen3와 같은 모델은 이제 코드 생성 및 도구 사용 작업에서 경쟁력 있는 성능을 보여줍니다. 또한 OpenAI 호환 API를 통해 제공되므로 model 매개변수 한 줄만 변경하면 전환할 수 있습니다.
두 모델 모두 Novita의 LLM API를 통해 사용할 수 있습니다. 동일한 엔드포인트, 동일한 함수 호출 인터페이스, 동일한 에이전트 샌드박스 통합을 제공하며 GPU 인프라를 직접 관리할 필요가 없습니다. 이는 GPU 오케스트레이션, 배치 처리, 안정성 엔지니어링이 사소하지 않기 때문에 중요합니다. 이를 관리형 API에 위임하면 에이전트 로직에 집중할 수 있습니다.
코딩 에이전트에게 이것이 중요한 이유: 세션당 토큰 비용은 라이선스 비용보다 에이전트 워크로드의 경제성을 좌우합니다. 하루에 200개의 코딩 에이전트 세션을 실행하는 팀이 오픈소스 모델로 비슷한 작업 완료율을 달성하면 통합 코드를 전혀 변경하지 않고도 추론 비용을 크게 줄일 수 있습니다.
실질적인 테스트: 대상 모델로 50개의 대표적인 코딩 작업을 실행하고, 도구 호출 성공률과 작업 완료율을 측정한 다음 세션당 비용과 비교하세요. 벤치마크 수치는 이 질문에 답하지 않습니다. 실제 워크로드가 답할 것입니다.
FAQ
코딩 에이전트와 코드 어시스턴트의 차이는 무엇인가요?
코드 어시스턴트(GitHub Copilot의 인라인 제안 등)는 완성을 생성하고 멈춥니다. 코딩 에이전트는 코드를 실행하고, 출력을 읽고, 반복합니다. 정의적 특징은 실행 루프(읽기, 결정, 실행, 관찰, 반복)입니다. 다양한 에이전트 폼 팩터가 이 루프를 사용하는 방식에 대한 비교는 CLI vs IDE 코딩 에이전트를 참조하세요.
코딩 에이전트를 구축하려면 반드시 샌드박스가 필요한가요?
네, 에이전트가 사용자 입력이나 외부 소스에서 생성된 코드를 실행할 예정이라면 필요합니다. 격리 없이 버그가 있는 코드 생성이 호스트 파일 시스템을 손상시키거나 무제한 리소스를 소비할 수 있습니다. 내부 전용 사용 사례의 경우에도 샌드박스는 실행 중인 프로세스가 호스트에 영향을 미치는 것을 방지합니다. 컨테이너는 기본 격리를 제공하고, Novita와 같은 마이크로VM 기반 샌드박스는 멀티 테넌트 또는 보안에 민감한 워크로드를 위한 더 강력한 커널 수준 분리를 제공합니다.
코딩 에이전트는 인터넷 접속 없이 작동할 수 있나요?
대부분의 순수 코딩 작업의 경우 네, 가능합니다. 파일 읽기/쓰기 및 로컬 명령 실행이 대부분의 워크플로를 처리합니다. 실제로 샌드박스 내부의 외부 접속을 제한하는 것은 좋은 기본값입니다. 생성된 코드가 예기치 않은 외부 요청을 하는 것을 방지하고 위협 모델을 단순화합니다.
주어진 작업에 가장 적합한 코드 에이전트는 무엇이 결정하나요?
실제 워크로드에 대한 도구 호출 신뢰성과 작업 완료율입니다. 공개 벤치마크 순위는 모델을 단기 목록에 포함시키기 위한 시작점일 뿐 최종 답이 아닙니다. 대표적인 작업을 실행하고, 완료율을 측정하고, 세션당 토큰 비용을 고려하세요. 가벼운 리팩토링을 수행하는 소규모 스타트업에 가장 적합한 코드 에이전트는 대규모로 자동화된 PR 검토를 실행하는 엔터프라이즈 팀에 가장 적합한 옵션과 매우 다를 수 있습니다.
코딩 에이전트 세션은 얼마나 오래 실행될 수 있나요?
이는 샌드박스 제공자에 따라 다릅니다. Novita 에이전트 샌드박스는 명령 간에 파일 시스템 상태가 유지되는 최대 24시간 세션을 지원하므로 에이전트 코드에 체크포인트/복원 로직 없이도 확장된 리팩토링 또는 마이그레이션 작업을 처리할 수 있습니다.
