원문: Sreejith Sreejayan, “Build Your Own Claude Code Using Langchin: A Deepdive Into LangChain’s Deep Agents”, Towards AI, 2026-06-10.
이 노트는 원문의 핵심 설명을 한국어로 옮긴 번역/정리본이다. 핵심 관점은 harness와 langchain-deep-agents를 함께 봐야 한다.
핵심 주장
Claude Code를 써 보면 “모델이 코딩을 정말 잘한다”라고 느끼기 쉽다. 하지만 원문이 강조하는 올바른 mental model은 다르다. 코딩 에이전트는 더 똑똑한 챗봇이 아니라, 모델을 둘러싼 에이전틱 하네스(agentic harness) 덕분에 작동한다.
하네스는 제어 평면이다. 모델에게 파일을 읽는 도구, 코드를 실행하는 환경, 방금 한 일을 기억하는 메모리, 계속 길을 잃지 않게 하는 체크리스트를 제공한다. 하네스가 없으면 LLM은 텍스트 생성기에 가깝지만, 하네스가 있으면 자율 소프트웨어 엔지니어처럼 움직일 수 있다. 이 글은 Claude Code의 블랙박스를 열어 보고, 각 구성요소를 LangChain의 langchain-deep-agents 라이브러리로 재구성한다.
코딩 에이전트의 기본 아키텍처
전체 엔진은 “사용자 요청 → 모델 판단 → 도구 호출 또는 답변 → 도구 결과 재투입 → 반복”이라는 루프다. 사용자가 “이 폴더에 어떤 파일이 있어?”라고 묻든, “로그인 시스템을 리팩터링하고 테스트도 고쳐”라고 요청하든 시작점은 같다. 모델은 다음 단계를 결정하고, 실제 행동이 필요하면 도구를 호출한다. 도구 결과가 다시 모델에게 전달되고, 모델이 더 이상 도구를 요청하지 않고 일반 텍스트로 답하면 루프가 끝난다.
이 루프 안에서 모델은 계속 세 가지 일을 섞어서 수행한다.
- 컨텍스트 수집: 파일 읽기, 검색, 코드 구조 파악
- 행동: 파일 수정, 명령 실행, 네트워크 호출
- 검증: 테스트 실행, 결과 확인, 오류 수정
별도의 “읽기 모드/실행 모드/검증 모드”가 있다기보다, 모두 같은 루프 안에서 다른 도구 호출로 표현된다.
Plan mode: 루프 앞의 안전 게이트
일반적으로 에이전트는 계획과 실행을 한 흐름 안에서 같이 한다. 하지만 큰 작업이나 위험한 작업에서는 plan mode가 필요하다. plan mode는 “아직 수정하지 말고 조사와 계획만 하라”는 게이트다. 에이전트는 파일을 읽고 생각하지만, 사용자가 승인하기 전까지 편집이나 명령 실행을 하지 않는다. 승인 후에야 일반 루프가 이어진다.
이는 에이전트가 스스로 유지하는 자동 todo list와 다르다. 자동 todo는 작업 수행 중 자기 관리를 위한 내부 체크리스트이고, plan mode는 사용자가 명시적으로 멈춤과 승인을 거는 안전장치다.
하네스의 네 가지 핵심 능력
원문은 루프를 안정적으로 만드는 하네스 구성요소를 네 가지로 정리한다.
- Planning — 행동하기 전에 먼저 생각하고 작업을 쪼갠다.
- Tools — 모델에게 파일 읽기, 편집, 명령 실행 같은 “손”을 준다.
- Context management — 긴 작업에서 모델이 자기 메모리에 익사하지 않게 한다.
- Subagents — 부수 작업을 별도 컨텍스트의 헬퍼에게 넘겨 메인 대화를 깨끗하게 유지한다.
이 요소들은 루프 자체를 바꾸지 않는다. 루프에 연료와 안전장치를 공급한다.
가장 중요한 하단 레이어: 권한과 샌드박스
에이전트가 파일을 수정하거나 셸 명령을 실행하거나 네트워크에 접근하려 할 때, 그 행동은 곧장 사용자 시스템으로 가지 않는다. 반드시 권한/샌드박스 레이어를 통과해야 한다. 원문은 이것이 전체 시스템에서 가장 중요한 안전 개념이라고 본다.
“중요한 파일은 지우지 마” 같은 프롬프트는 벽이 아니라 포스트잇에 가깝다. 모델이 무시하거나 오해하거나 프롬프트 인젝션에 밀릴 수 있다. 진짜 안전은 모델 바깥에 있어야 한다. 권한 규칙은 도구 호출을 차단할 수 있어야 하고, 샌드박스는 OS 레벨에서 위험한 명령을 막아야 한다.
Part 0 — 프레임워크 없는 최소 에이전트 루프
원문이 제시하는 최소 루프는 약 30줄짜리 의사코드다.
def run_agent_loop(client, user_message, tools, tool_functions, max_turns=20):
messages = [{"role": "user", "content": user_message}]
for _ in range(max_turns):
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
tools=tools,
messages=messages,
)
messages = [*messages, {"role": "assistant", "content": response.content}]
tool_uses = [b for b in response.content if b.type == "tool_use"]
if not tool_uses:
return "".join(b.text for b in response.content if b.type == "text")
results = [
{
"type": "tool_result",
"tool_use_id": call.id,
"content": tool_functions[call.name](**call.input),
}
for call in tool_uses
]
messages = [*messages, {"role": "user", "content": results}]
raise RuntimeError(f"agent loop did not finish within {max_turns} turns")나머지 기능은 이 루프에 배터리를 붙인 것이다. 더 나은 도구는 tool_functions에 꽂히고, planner는 messages 안에 체크리스트를 남기며, compactor는 messages가 비대해질 때 요약한다. subagent는 같은 함수를 새 messages 리스트로 재귀 호출하는 것과 비슷하다. permission check는 모델이 도구를 요청한 뒤 실제 함수 호출 전 사이에 들어간다. max_turns는 무한 루프와 비용 폭주를 막는 필수 안전장치다.
Part 1 — 루프: 모든 행동의 엔진
에이전트 루프는 “대화”를 “행동”으로 바꾸는 심장이다.
- 모델에게 다음에 무엇을 할지 묻는다.
- 모델은 일반 텍스트로 답하거나 도구 사용을 요청한다.
- 도구를 요청했다면 시스템이 도구를 실행하고 결과를 모델에게 돌려준다.
- 다시 1번으로 돌아간다.
- 도구 요청 없이 텍스트만 나오면 작업을 끝내고 사용자에게 답한다.
빠른 질문은 한 턴에 끝날 수 있고, 대규모 리팩터링은 수십 번의 도구 호출을 이어갈 수 있다. 작업 단계 수를 미리 하드코딩할 필요가 없다는 점이 루프의 장점이다.
langchain-deep-agents에서는 create_deep_agent()가 이 루프를 이미 구현해 준다.
from deepagents import create_deep_agent
def get_weather(city: str) -> str:
"""Get the weather for a given city."""
return f"It's always sunny in {city}!"
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
tools=[get_weather],
system_prompt="You are a helpful assistant.",
)
result = agent.invoke({
"messages": [{"role": "user", "content": "What's the weather in San Francisco?"}]
})Part 2 — 도구: 모델에게 손을 달아주기
루프가 엔진이라면 도구는 손이다. 도구 없는 모델은 말만 할 수 있지만, 좋은 도구를 가진 모델은 코드베이스를 읽고, 고치고, 검증한다.
코딩 도구는 보통 네 종류로 나뉜다.
- 읽기 도구:
read_file,glob,grep처럼 변경 없이 살펴보는 도구 - 편집 도구: 새 파일을 쓰는
write_file, 기존 파일 일부를 바꾸는edit_file - 실행 도구: 터미널에서 치는 명령을 실행하는 shell/execute 도구
- 위임 도구:
task처럼 하위 작업을 helper agent에게 넘기는 도구
원문은 “그냥 모델에게 아무 명령이나 실행하게 하면 안 되나?”라는 질문에 두 가지 이유로 반대한다.
- 토큰 예산: 전용 읽기 도구는 파일 크기를 측정하고 필요한 만큼만 잘라 넣을 수 있다. 반면
cat은 전체 파일을 밀어 넣어 컨텍스트를 터뜨릴 수 있다. - 명확한 권한:
edit_file같은 알려진 도구는 하네스가 의도를 이해하고 안전 규칙을 적용할 수 있다. 자유형 shell은 위험한 블랙박스다.
모델은 인터넷의 cat, sed, Stack Overflow 예제를 많이 학습했기 때문에 고급 모델도 습관적으로 raw shell을 쓰려 한다. 그래서 시스템 프롬프트는 “shell shortcut이 아니라 전용 도구를 써라”라고 강하게 안내해야 한다.
Deep Agents에서는 기본 도구 위에 커스텀 도구를 데코레이터로 추가한다.
import subprocess
from langchain_core.tools import tool
MAX_OUTPUT_CHARS = 20_000
@tool
def run_tests(path: str = ".") -> str:
"""Run the project's pytest suite and return its output."""
try:
result = subprocess.run(
["pytest", path],
capture_output=True,
text=True,
check=False,
timeout=300,
)
except subprocess.TimeoutExpired:
return "pytest timed out after 300s"
output = result.stdout + result.stderr
if len(output) > MAX_OUTPUT_CHARS:
return "[... output truncated ...]
" + output[-MAX_OUTPUT_CHARS:]
return output@tool은 평범한 함수를 모델이 호출할 수 있는 도구로 바꾼다. docstring은 모델이 읽는 사용 설명서이므로 매우 중요하다.
Part 3 — Planning: 행동하기 전에 생각하기
복잡한 요청을 bare model에 던지면 모델은 전체 계획 없이 도구를 하나씩 호출하다가 빙빙 돌기 쉽다. 좋은 코딩 에이전트는 먼저 구조화된 todo list를 쓴다. 작업을 단계로 나누고, 진행 중/완료 상태를 갱신하며 움직인다.
긴 세션에서는 원래 목표가 도구 출력 더미 아래 묻힌다. 하네스는 이를 막기 위해 현재 todo list를 도구 호출 이후 대화에 다시 주입한다. 동료가 계속 체크리스트를 책상 위에 밀어 놓아 “우리가 왜 이 일을 하고 있었는지”를 상기시키는 것과 같다.
Deep Agents에서는 이 기능이 write_todos 도구로 내장되어 있다. 기본 시스템 프롬프트가 에이전트에게 먼저 계획하고 todo를 갱신하라고 가르친다.
Part 4 — Context management: 메모리 한계 이기기
가장 어려운 엔지니어링은 컨텍스트 관리다. 파일 몇 개를 읽고 명령 결과를 몇 번 넣으면 모델의 단기 기억인 context window가 금방 찬다. 넘치면 원래 지시까지 잊는다.
코딩 에이전트는 두 가지 전략을 쓴다.
- 파일을 외부 메모리로 사용: 거대한 검색 결과를 대화에 모두 넣지 않고 파일로 저장한 뒤 파일명만 기억한다.
- Compaction: 컨텍스트가 위험 수준에 가까워지면 루프를 잠시 멈추고, 오래된 대화에서 중요한 사실을 요약해 장기 저장소에 넣은 뒤 비대한 단기 기억을 비운다.
Deep Agents는 virtual filesystem과 automatic summarization middleware를 제공하므로, 에이전트를 만들면 이 메모리 관리가 기본으로 따라온다.
Part 5 — Subagents: 나눠서 정복하기
큰 코드베이스 검색처럼 메인 대화에 파일 50개를 밀어 넣고 싶지 않은 작업은 subagent에게 넘긴다. 메인 에이전트는 “auth 로직이 어디 있는지 찾아서 요약해 와” 같은 명확한 임무를 주고, helper는 별도의 빈 컨텍스트에서 조사한 뒤 짧은 요약만 반환한다.
안전장치도 있다. subagent가 다시 subagent를 무한히 만들 수 있으면 runaway process가 되어 API 비용을 태울 수 있다. 그래서 depth limit이 필요하다.
Deep Agents에서는 task 도구와 subagents 설정으로 specialist를 붙인다.
code_searcher = {
"name": "code-searcher",
"description": "Searches the codebase to find where specific logic lives.",
"system_prompt": "You are an expert at navigating codebases. Use grep and glob, report concise findings, and do not edit.",
}
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
tools=[run_tests],
system_prompt="You are a coding assistant.",
subagents=[code_searcher],
)Part 6 — Safety and human-in-the-loop: 브레이크
파일을 편집하고 셸 명령을 실행하는 에이전트는 강력하지만 위험하다. 원문은 통제를 두 계층으로 설명한다.
- Allowlist / deny rule: 읽기 같은 안전한 도구는 자동 실행하고, 삭제 같은 위험한 행동은 승인이 필요하다.
- Approval prompt: 위험한 행동 전에는 에이전트가 멈추고 사용자에게 승인·수정·거절·응답을 요청한다.
원문이 반복해서 강조하는 보안 원칙은 다음이다.
프롬프트는 보안 경계가 아니다.
Deep Agents는 하네스 레벨에서 제한을 강제한다. 셸 접근에는 backend가 필요하고, 위험한 작업 전에는 LangGraph의 interrupt 기능으로 멈춘다.
from deepagents import create_deep_agent
from deepagents.backends import LocalShellBackend
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
system_prompt="You are a coding assistant working inside this project.",
backend=LocalShellBackend(),
)도구 호출이 gate에 걸리면 결과에 __interrupt__ payload가 들어 있고, 사용자는 approve, edit, reject, respond 같은 결정을 내려 루프를 재개한다. 실제 한계는 prompt가 아니라 harness에 설정해야 한다.
Part 7 — Memory and persistence: 세션을 넘어 기억하기
기본 에이전트는 대화가 끝나면 모든 것을 잊는다. 하지만 실제 assistant는 프로젝트 코딩 규칙, 사용자 선호, 어제 하던 일을 기억해야 한다.
- Checkpointing: 에이전트의 정확한 상태를 저장해 긴 작업이 중단되어도 이어서 실행한다.
- Long-term memory: “이 프로젝트는 4-space indentation을 쓴다” 같은 사실을 별도 대화 사이에서도 유지한다.
Deep Agents는 LangGraph 위에서 돌아가기 때문에 checkpointer를 꽂아 persistence를 얻는다.
from langgraph.checkpoint.memory import InMemorySaver
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
tools=[run_tests],
system_prompt="You are a coding assistant.",
checkpointer=InMemorySaver(),
)
config = {"configurable": {"thread_id": "project-alpha"}}InMemorySaver는 프로그램 생명주기 동안만 유지된다. 재부팅 후에도 유지하려면 DB-backed checkpointer로 바꿔야 한다.
전체 조립 예시
원문은 일곱 요소를 모두 합친 에이전트를 100줄 미만으로 조립한다.
from deepagents import create_deep_agent
from deepagents.backends import LocalShellBackend
from langchain_core.tools import tool
from langgraph.checkpoint.memory import InMemorySaver
@tool
def run_tests(path: str = ".") -> str:
"""Run the project's pytest suite and return its truncated output."""
import subprocess
try:
result = subprocess.run(["pytest", path], capture_output=True, text=True, check=False, timeout=300)
except subprocess.TimeoutExpired:
return "pytest timed out after 300s"
output = result.stdout + result.stderr
return output if len(output) <= 20_000 else "[... truncated ...]
" + output[-20_000:]
code_searcher = {
"name": "code-searcher",
"description": "Finds where specific logic lives in the codebase.",
"system_prompt": "Navigate codebases using grep and glob, report concise findings, never edit.",
}
SYSTEM_PROMPT = """You are a careful coding assistant.
Workflow:
1. Plan the task as a to-do list before doing anything.
2. Use built-in read, grep, and glob tools; avoid raw shell equivalents.
3. Make focused edits.
4. Always run tests after editing and fix failures.
5. Delegate broad codebase searches to the code-searcher subagent.
"""
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
tools=[run_tests],
system_prompt=SYSTEM_PROMPT,
subagents=[code_searcher],
backend=LocalShellBackend(root_dir=".", virtual_mode=False),
interrupt_on={"execute": True, "write_file": True, "edit_file": True},
checkpointer=InMemorySaver(),
)이 구성은 계획, 탐색, 편집, 테스트 실행, helper 위임, sandbox 존중, context 기억을 모두 갖춘 작은 Claude Code형 코딩 에이전트다.
쉬운 80%와 어려운 20%
원문은 “이게 전부다”로 끝내지 않는다. Deep Agents 같은 하네스가 많은 부분을 공짜로 주지만, 여전히 어려운 부분이 남는다.
하네스가 제공하는 쉬운 80%
- 루프
- 기본 도구 세트
- planning
- context management
- delegation
- persistence
- streaming
직접 책임져야 하는 어려운 20%
- 시스템 프롬프트: 어떤 도구를 언제 쓰고, 실수에서 어떻게 회복할지 반복 튜닝해야 한다.
- 샌드박스: 안전한 셸 실행은 선택이 아니라 필수다. OS 레벨 격리를 신중히 설계해야 한다.
- 올바른 도구: 검색기나 테스트 러너가 부실하면 에이전트도 부실해진다.
한계
- planning, subagent, loop는 API 호출을 많이 만들기 때문에 비용이 든다.
- 좋은 하네스도 약한 모델의 추론 능력을 대신할 수 없다.
- 에이전트는 지시를 오해하고 나쁜 편집을 할 수 있다.
- 간단한 질문에는 일반 챗봇이 더 빠르고 싸다. 에이전트는 실제 행동이 필요한 작업에 써야 한다.
정리
큰 결론은 처음과 같다. 마법은 모델 하나에 있지 않다. 유능한 코딩 에이전트는 평범한 언어 모델을 강력한 하네스 안에 넣은 시스템이다. 말하기를 행동으로 바꾸는 루프, 손이 되는 도구, 집중을 유지하는 planning, 메모리 한계를 이기는 context management, 일을 나누는 subagents, 안전을 지키는 브레이크, 지속성을 만드는 memory가 합쳐질 때 Claude Code 같은 도구가 된다.
원문 마지막의 조언도 실용적이다. Claude Code가 어떻게 움직이는지 진짜로 이해하려면 작은 버전을 직접 만들어 보고 실행해 보라. 예제 저장소: https://github.com/the-Sreejith/langclaude
llm-wiki 관점 메모
이 글은 harness를 “성능의 숨은 원천”으로 보는 기존 위키 관점과 강하게 일치한다. 특히 moc-ai-agents-harness에 정리된 하네스 엔지니어링 논점—루프, 도구, 컨텍스트, 검증, 권한 경계—를 Claude Code 재구현 관점에서 실습형으로 보여준다. moc-ai-coding에서는 Claude Code류 제품을 단일 모델이 아니라 “도구+권한+메모리+위임”의 운영 시스템으로 분해해서 봐야 한다.