내가 에이전틱 코딩 CLI를 처음부터 만든 방법
I’m happy to translate the article for you, but I’ll need the full text of the post (the paragraphs, headings, etc.) in order to do the translation. Could you please paste the content you’d like translated? Once I have that, I’ll keep the source line at the top unchanged and translate the rest into Korean while preserving the original formatting.
핵심 인사이트: 단순히 루프일 뿐
모든 에이전시 코딩 도구—얼마나 다듬어졌든—는 동일한 기본 패턴을 따릅니다:
while needs_follow_up:
# 1️⃣ Send conversation + tools → LLM
# 2️⃣ If LLM returns tool calls → execute them, append results, loop
# 3️⃣ If LLM returns plain text → finish
이것이 바로 “마법”이며, 함수 호출이 포함된 while‑loop입니다.
나머지 95 %는 다음으로 구성됩니다:
- 컨텍스트 관리
- 도구 실행
- 오류 처리
- 권한 검사
간소화된 에이전트 루프
def run_agent_loop(user_input, conversation, config):
conversation.add_user(user_input)
for iteration in range(config.max_iterations):
stream = completion(
model=routed_model,
messages=conversation.messages,
tools=TOOL_DEFINITIONS,
stream=True,
)
text, tool_calls, usage = process_stream(stream)
if not tool_calls:
# No tools called — model is done
conversation.add_assistant(content=text)
break
# Execute each tool, feed results back, loop
for tc in tool_calls:
result = execute_tool(tc.name, tc.args)
conversation.add_tool_result(tc.id, result)
사용자가 “app.py의 버그를 고쳐줘” 라고 말하면, LLM은 파일을 직접 수정하지 않습니다. 대신 다음과 같이 동작합니다:
read_file("app.py")호출 → 소스 코드를 받아옴.edit_file(...)호출 → 수정 내용을 적용.run_command("pytest")호출 → 검증 수행.
각 단계는 도구 호출이며, 루프가 이를 실행하고 다음 반복에 결과를 다시 전달합니다.
아키텍처
┌─────────────────────────────────────────────────┐
│ cli.py (UI) │
│ REPL loop · slash commands · Rich terminal UI │
└──────────────────────┬──────────────────────────┘
│
┌──────────────────────▼──────────────────────────┐
│ agent.py (Brain) │
│ Agentic loop · context management · permissions│
│ │
│ LiteLLM ──→ Claude / GPT / Gemini / Ollama │
└──────────────────────┬──────────────────────────┘
│
┌──────────────────────▼──────────────────────────┐
│ tools.py (Hands) │
│ read_file · write_file · edit_file │
│ run_command · git_commit · search_text │
└─────────────────────────────────────────────────┘
| 파일 | 책임 |
|---|---|
| cli.py | 터미널 UI (REPL, 슬래시 명령, 세션 관리) |
| agent.py | 두뇌 (에이전트 루프, 스트리밍, 권한, 컨텍스트 압축) |
| tools.py | 손 (파일 I/O, bash 실행, git, 검색) |
제가 가장 자랑스러워하는 기능: 비용‑인식 라우팅
대부분의 AI 코딩 도구는 단일 모델에 고정시켜, 간단한 설명에 대해 전체 규모 리팩터링과 같은 가격을 지불하게 합니다. AgentCode는 각 요청을 복잡도에 따라 분류하고, 이를 처리할 수 있는 가장 저렴한 모델을 자동으로 선택합니다.
라우팅 테이블
| 단계 | 예시 프롬프트 | 모델 | 이유 |
|---|---|---|---|
| Light | “what does this function do” | Haiku | 빠르고 저렴함 — 단순히 읽고 설명 |
| Medium | “write unit tests for app.py” | Sonnet | 코드를 이해하고 새로운 코드를 생성해야 함 |
| Heavy | “refactor the entire auth system” | Opus | 다중 파일, 다중 단계, 아키텍처적 사고 필요 |
분류는 간단한 패턴 매칭을 사용합니다:
def classify_complexity(user_input):
text = user_input.lower()
heavy_score = sum(1 for p in HEAVY_PATTERNS if re.search(p, text))
medium_score = sum(1 for p in MEDIUM_PATTERNS if re.search(p, text))
if heavy_score >= 2:
return "heavy"
elif medium_score >= 1:
return "medium"
else:
return "light"
투명하고, 쉽게 조정할 수 있으며, 실제 비용을 절감합니다.
자동 선택은 언제든지 /model 명령으로 재정의할 수 있습니다.
스트리밍: UX 차이
첫 번째 버전은 전체 LLM 응답을 기다렸다가 아무것도 표시하지 않아 터미널이 5–10 초 동안 비어 있었습니다. 스트리밍을 추가하면 경험이 실시간 대화로 바뀝니다.
도전 과제
에이전트 루프에서 LLM은 텍스트와 도구 호출 두 가지를 같은 응답에 반환할 수 있습니다. 텍스트 토큰은 하나씩 도착하고, 도구 호출 인자는 조각으로 도착해 실행 전에 조합해야 합니다.
스트리밍 프로세서
def process_stream(stream):
full_text = ""
tool_calls_acc = {}
for chunk in stream:
delta = chunk.choices[0].delta
# Text tokens — print immediately
if delta.content:
print(delta.content, end="", flush=True)
full_text += delta.content
# Tool call fragments — accumulate silently
if delta.tool_calls:
for tc_delta in delta.tool_calls:
idx = tc_delta.index
if idx not in tool_calls_acc:
tool_calls_acc[idx] = {"id": "", "name": "", "arguments": ""}
if tc_delta.function.arguments:
tool_calls_acc[idx]["arguments"] += tc_delta.function.arguments
return full_text, tool_calls_acc
- 텍스트는 실시간으로 화면에 스트리밍됩니다.
- 도구 호출은 백그라운드에서 조용히 조합됩니다.
사용자는 에이전트가 다음에 무엇을 할지 결정하는 동안 단어가 즉시 나타나는 것을 보게 됩니다.
다중 모델 지원
AgentCode는 LiteLLM을 추상화 레이어로 사용합니다. 이는 제가 OpenAI 형식으로 도구 정의를 한 번 작성하면, LiteLLM이 이를 제공자가 기대하는 형태로 변환한다는 의미입니다.
대화 중 모델 전환
❯ /model gpt-4o
✓ Switched to gpt-4o
❯ /model claude-opus-4-6
✓ Switched to claude-opus-4-6
❯ /model ollama/qwen2.5-coder
✓ Switched to ollama/qwen2.5-coder
같은 도구, 같은 루프, 다른 두뇌. 로컬 Ollama 옵션을 사용하면 전체를 zero API cost 없이 실행할 수 있습니다.
권한 시스템
파일을 쓰거나 명령을 실행하는 모든 도구는 실행 전에 확인을 요청합니다:
🔒 Permission Required
Tool: write_file
Args: {"path": "src/handler.py", "content": "..."}
Allow this action? [y/n] (y):
읽기 전용 도구(read_file, list_directory, search)는 자동 승인됩니다. 이는 흐름을 빠르게 유지하면서 에이전트가 사용자 동의 없이 파괴적인 작업을 수행하지 못하도록 방지합니다.
내가 배운 것
-
컨텍스트 관리가 어려운 문제다.
에이전트 루프 자체는 사소합니다. 컨텍스트 창에 무엇이 들어있는지를 관리하는 것—이전 메시지를 압축하고, 요약하고, 올바른 정보를 유지하는 것—이 실제 엔지니어링 노력이 필요한 부분입니다. -
도구 정의가 프롬프트보다 더 중요하다.
명확한 매개변수 설명이 포함된 잘 정의된 도구가 영리한 시스템 프롬프트보다 뛰어납니다. LLM은 도구 스키마를 문서처럼 읽습니다. -
스트리밍이 모든 것을 바꾼다.
“응답을 8초 동안 기다린다”와 “단어가 즉시 나타나는 것을 본다”의 차이는 짜증나는 도구와 사용하기 즐거운 도구의 차이입니다. -
멀티 모델 유연성은 과소평가된다.
모델마다 다른 작업에 특화되어 있습니다. 모델 간에 즉시 전환하거나 라우터가 결정하도록 하면 언제나 작업에 맞는 올바른 도구를 사용할 수 있습니다.
시도해 보기
pip install agentcode-cli
export ANTHROPIC_API_KEY="your-key"
agentcode
코드베이스는 읽기 쉬운 파이썬으로 구성되어 있습니다 — 프레임워크도 없고, 추상화도 없습니다. 에이전트 코딩 도구가 어떻게 작동하는지 궁금하다면 복제해서 agent.py를 살펴보세요. 전체 루프는 50줄 정도입니다.
- GitHub:
- PyPI:
MIT 라이선스. 피드백 및 기여를 환영합니다.
Tags: python, ai, opensource, tutorial