코딩 에이전트를 구축하는 데 필요한 모든 요소를 다룹니다. 즉, 하네스 구축, 에이전트 루프, 계획, 하위 에이전트, 샌드박싱, 메모리, 체크포인팅을 단계별로 살펴봅니다.
직접 코딩 에이전트를 만들어 본 적이 있다면, 이 과정이 어떻게 진행되는지 아실 겁니다. 모델을 파일 도구와 셸에 연결하고 실제 코드베이스를 가리키면, 수십 번의 도구 호출 안에 작동이 중단됩니다.
잘못된 파일을 읽고, 중간에 목표를 잃어버리며, 더 이상 필요 없는 출력으로 컨텍스트를 채웁니다.
그러다 같은 작업을 Claude Code에 넣으면 깔끔하게 끝납니다. 쉽게 내리는 결론은 Anthropic이 단순히 더 나은 모델을 가지고 있다는 것이지만, 그 결론은 실제 작업이 어디서 이루어지는지를 놓칩니다.
차이는 하네스에 있습니다. 하네스는 모델을 감싸는 일반 코드로, 계획, 도구 실행, 메모리, 안전을 처리하는 반면, 모델은 다음 단계만 결정합니다.
완전히 하네스된 에이전트를 그림으로 그리면 이렇게 보입니다.

GIF
그림이 복잡해 보이지만, 네 가지 그룹으로 나뉩니다.
- 메모리는 모델에 작업 컨텍스트와 세션 간에 학습한 사실을 제공합니다.
- 스킬은 에이전트가 어떻게 작동해야 하는지, 즉 따라야 할 절차, 제약 조건, 휴리스틱을 인코딩합니다.
- 프로토콜은 에이전트를 사용자, 도구, 다른 에이전트와 연결합니다.
- 하네스 코어는 하위 에이전트 오케스트레이션, 샌드박스, 평가자, 승인 루프, 관찰 가능성, 컨텍스트 압축으로 모든 것을 통합합니다.
Anthropic은 이 분할을 두뇌와 손에 비유합니다. 모델은 각 동작을 선택하는 두뇌이고, 하네스는 그 동작을 실행하고 실행을 정상적으로 유지하는 손입니다.
따라서 여러분의 에이전트와 Claude Code의 차이는 모델이 아니라 모델 주변의 메커니즘입니다.
Claude Code는 현재 프로덕션에서 가장 강력한 하네스 중 하나이며, 놀랍게도 그 그림 속 레이어 중 적은 수로 구성되어 있습니다. 그 메커니즘 중 얼마나 많은 부분을 직접 구축해야 하는지 확인하기 위해, 에이전트 오케스트레이션을 위한 오픈소스 프레임워크인 CrewAI로 재구축했습니다.
예상보다 더 많은 부분이 내장 기능에 매핑되었고, 그렇지 않은 부분이 실제 엔지니어링이 필요한 곳입니다.
레이어별로 구축해 보겠습니다. 핵심 루프부터 시작하여 계획, 하위 에이전트, 샌드박싱, 메모리를 그 위에 쌓아 올립니다. 각 단계에서 프레임워크의 경계와 여러분의 작업이 시작되는 지점을 표시하겠습니다.
Claude Code 하네스의 작동 방식
Claude Code의 중심에는 단순한 에이전트 루프가 있습니다. 메시지를 보내면 모델이 다음에 무엇을 할지 결정하고, 직접 응답하거나 도구를 요청합니다. 도구를 요청하면 해당 도구가 실행되고, 결과가 대화에 다시 추가되며, 모델이 다시 결정합니다.
이 과정은 모델이 더 이상 도구 호출 없이 최종 답변을 반환할 때까지 반복됩니다.
그 루프 안에서 모델은 파일을 읽고, 코드를 편집하고, 셸 명령을 실행하고, 테스트를 수행합니다. 이들은 별도의 모드가 아니라 동일한 루프 안에서의 서로 다른 도구 호출일 뿐입니다.
하지만 루프만으로는 안정적인 코딩 에이전트에 충분하지 않습니다. Claude Code는 그 주위에 계획, 파일 도구, 하위 에이전트, 메모리, 권한 및 샌드박스 시스템을 추가합니다. 이러한 레이어는 루프를 대체하지 않고, 실제 작업에 안전하고 신뢰할 수 있도록 만듭니다.

이것이 우리가 재구축할 아키텍처입니다. 먼저 핵심 루프, 그 다음 각 레이어를 위에 쌓고, 각 레이어를 처리하는 CrewAI 기능에 매핑합니다.
핵심 에이전트 루프
루프는 작업이 완료될 때까지 동일한 순서를 실행합니다.
- 모델에게 작업을 수행하도록 요청합니다.
- 모델이 직접 응답하거나 하나 이상의 도구를 요청합니다.
- 도구가 요청되면 실행하고 결과를 모델에 반환합니다.
- 업데이트된 대화로 반복합니다.
- 모델이 도구 요청 없이 응답하면 작업이 완료됩니다.

1while True:2 reply = model(messages, tools)3 calls = [b for b in reply if b.type == "tool_use"]4 if not calls: # 일반 텍스트, 도구 호출 없음: 작업 완료5 return reply.text6 messages += [reply, run_all(calls)]
각 도구 호출은 한 단계를 완료하고, 모델에 새 정보를 제공하며, 다음 결정에 영향을 줍니다. 간단한 질문은 한 번의 반복으로 끝날 수 있지만, 복잡한 버그를 수정하거나 대규모 코드베이스를 리팩토링하는 경우 모델이 최종 답변을 생성할 충분한 정보를 얻을 때까지 수십 번의 반복이 필요할 수 있습니다.
CrewAI는 에이전트를 생성하는 즉시 이 실행 루프를 자동으로 제공합니다. while 루프를 직접 구현할 필요 없이 에이전트를 정의하고 작업을 할당하기만 하면 됩니다.
첫 번째 에이전트 구축
간단한 Bug Fixer 에이전트를 만들어 보겠습니다.
1from crewai import LLM, Agent, Crew, Task23bug_fixer = Agent(4 role="Bug Fixer",5 goal="Find and describe the fix for the reported bug in the codebase.",6 backstory="You read directories and files to build an accurate picture of the code.",7 llm="claude-sonnet-4-6",8)910task = Task(11 description="Find the fix for {objective}.",12 expected_output="A short description of the fix and which file it belongs in.",13)1415result = Crew(agents=[bug_fixer], tasks=[task]).kickoff(16 inputs={"objective": "the overdraft bug in account.py"}17)
여기서 이해해야 할 세 가지 개념이 있습니다.
- Agent는 역할, 목표, LLM, 도구를 통해 작업을 수행하는 주체를 정의합니다.
- Task는 할당된 작업을 설명합니다.
- Crew는 에이전트와 작업을 함께 묶습니다. kickoff()를 호출하면 기본 모델이 Anthropic, OpenAI, Google 또는 다른 것이든 관계없이 위에서 설명한 동일한 실행 루프가 실행됩니다.
에이전트에 도구 부여하기
도구는 텍스트만 생성하는 모델이 실제로 코드베이스에서 작업할 수 있게 해줍니다. 파일을 읽고, 쓰고, 셸 명령을 실행하고, 외부 API를 호출합니다.
CrewAI는 파일 시스템 도구를 기본으로 제공합니다.
- FileReadTool은 파일을 읽습니다.
- DirectoryReadTool은 디렉터리를 나열합니다.
- FileWriterTool은 파일을 씁니다.
1from crewai_tools import DirectoryReadTool, FileReadTool, FileWriterTool23read_file = FileReadTool()4write_file = FileWriterTool()5list_dir = DirectoryReadTool()67filesystem_tools = [read_file, write_file, list_dir]
이 도구들은 외부 메모리 역할도 합니다. 큰 검색 결과를 모델의 컨텍스트 창에 유지하는 대신, 에이전트가 파일에 쓰고 파일 이름만 유지한 후 필요할 때 다시 읽을 수 있습니다.
이렇게 하면 컨텍스트 창이 더 작아지고 모델이 더 집중할 수 있으며, 이것이 Anthropic이 컨텍스트 엔지니어링이라고 부르는 것입니다.

내장 도구는 일반적인 워크플로우만 다룹니다. 더 구체적인 작업이 필요한 경우 @tool 데코레이터를 사용하여 Python 함수를 도구로 노출합니다.
독스트링은 명령 설명서 역할을 하며, 모델에게 도구가 무엇을 하는지, 언제 사용해야 하는지, 어떤 입력을 기대하는지 알려줍니다.
1from crewai.tools import tool2import subprocess34@tool("run_tests")5def run_tests(path: str = "tests/") -> str:6 """Run the pytest suite at the given path and return the result."""7 result = subprocess.run(8 ["pytest", path, "-q"], capture_output=True, text=True, timeout=1209 )10 output = result.stdout + result.stderr11 return output[-4000:] if len(output) > 4000 else output
장기 실행 작업 계획하기
작업이 복잡해질수록 단순한 실행 루프는 원래 목표를 놓치기 시작합니다. 충분한 도구 호출, 파일 읽기, 중간 결과 후에 컨텍스트가 가득 차고 목표는 그 뒤에 오는 모든 것에 밀려납니다.
이런 느린 성능 저하를 사람들은 컨텍스트 부패라고 부릅니다.
계획은 이를 직접 해결합니다. 에이전트는 작업을 수행하기 전에 단계별 계획을 세우고 실행 내내 그 계획을 컨텍스트에 유지합니다.
계획은 작업을 수행하지 않습니다. 모델을 원래 목표에 연결하는 로드맵이며, 이는 Claude Code의 할 일 목록과 동일한 역할을 합니다.

CrewAI는 crew 레벨에서 planning=True로 이를 추가합니다. 실행 전에 계획을 생성하고 작업이 진행되는 동안 계속 사용할 수 있게 합니다.
1from crewai import Crew, LLM23crew = Crew(4 agents=self.agents,5 tasks=self.tasks,6 planning=True,7 planning_llm=LLM(model="gpt-4o-mini"),8)
참고: 기본적으로 CrewAI는 계획에 gpt-4o-mini를 사용하며, 해당 단계에 원하는 LLM으로 교체할 수 있습니다.
개별 에이전트는 reasoning=True를 사용하여 자신의 작업에 대해 추론할 수도 있습니다.
1from crewai import Agent23bug_fixer = Agent(4 role="Bug Fixer",5 goal="Find and describe the fix for the reported bug in the codebase.",6 backstory="You read directories and files to build an accurate picture of the code.",7 tools=[FileReadTool()],8 reasoning=True,9 max_reasoning_attempts=3 # 선택사항: 최대 추론 시도 횟수 설정10)
계획과 추론은 서로 다른 문제를 해결합니다. 계획은 전체 작업에 대한 높은 수준의 로드맵을 구축하는 반면, 추론은 하나의 에이전트가 행동하기 전에 자신의 접근 방식에 대해 생각할 시간을 줍니다.
추론이 활성화되면 에이전트는 다음과 같이 작동합니다.
- 작업을 숙고하고 실행 계획을 초안으로 작성합니다.
- 계획이 준비되었는지 평가합니다.
- 필요하면 만족하거나 max_reasoning_attempts에 도달할 때까지 계획을 개선합니다.
- 최종 추론 계획을 실행 전에 작업에 주입합니다.

이 두 가지가 함께 작동하여 장기 실행 작업에서 에이전트가 고정되도록 하고 원래 목표에서 벗어나는 것을 줄입니다.
하위 에이전트로 위임하기
계획은 에이전트가 집중하도록 유지하지만, 모델이 보유해야 하는 정보의 양을 줄이지는 않습니다. 대규모 코드베이스에서는 잘 계획된 작업조차도 단일 컨텍스트 창을 초과할 수 있습니다.
하나의 버그를 찾는 데 수십 개의 파일을 읽어야 할 수 있으며, 메인 에이전트가 모든 파일을 메모리에 유지할 필요는 없습니다.
하위 에이전트는 위임을 통해 이 문제를 해결합니다. 메인 에이전트는 특정 작업을 도우미 에이전트에 넘기고, 도우미 에이전트는 자신의 컨텍스트에서 작업한 후 짧은 요약을 반환합니다. 메인 에이전트는 중간 단계가 아닌 결론만 봅니다.

CrewAI는 계층적 워크플로우를 통해 이를 지원합니다. 관리자 에이전트가 전문가 에이전트에게 위임하고 결과를 결합합니다.
앞서 설정에서는 하나의 Bug Fixer 에이전트가 모든 무거운 작업을 수행했습니다. 이제 작업을 관리자와 세 명의 전문가로 나누어 보겠습니다.
- Codebase Explorer는 코드를 탐색하고 리포지토리를 매핑합니다.
- Software Engineer는 요청된 변경을 구현합니다.
- Test Runner는 샌드박스에서 테스트를 실행하고 성공 또는 실패를 보고합니다.
- Engineering Lead는 세 명의 전문가를 감독합니다.

1from crewai import Crew, Agent, Task, Process23explorer = Agent(4 role="Codebase Explorer",5 goal="Map the repository and surface the files relevant to the task.",6 backstory="You read directories and files to build a picture of the code.",7 tools=[read_file, list_dir],8 llm=llm,9) # 다른 두 전문가 에이전트도 동일1011manager = Agent(12 role="Engineering Lead",13 goal="Break the request into steps and delegate each to the right specialist.",14 backstory="You decide who does what, review tests, finish once change is done.",15 llm=llm,16 allow_delegation=True,17)1819crew = Crew(20 agents=[explorer, coder, tester],21 tasks=[task],22 manager_agent=manager,23 process=Process.hierarchical,24)
한 가지 주의할 점은 allow_delegation이 기본적으로 비활성화되어 있으므로 관리자에서 명시적으로 활성화해야 한다는 것입니다.
샌드박싱: 에이전트 실행 보안
셸에 접근할 수 있는 에이전트는 파괴적인 명령을 실행할 수 있으며, 모델에게 하지 말라고 말하는 것은 안전 장치가 아닙니다.
실제 보호는 두 가지 레이어에서 제공됩니다.
- 권한 시스템은 민감한 작업에 대한 승인을 요구합니다.
- 샌드박스는 실행을 격리하여 승인된 명령도 호스트 머신에 영향을 미치지 못하게 합니다.
Anthropic도 동일한 접근 방식을 사용합니다. 코드 실행을 샌드박스로 이동하면 사용자가 작업을 승인해야 하는 빈도를 줄이면서도 호스트 시스템을 보호할 수 있습니다.

CrewAI에서의 샌드박싱
호스트 머신 대신 샌드박스 내에서 코드를 실행하는 것이 두 번째 레이어를 적용하는 방법입니다. 이 설정에서 코드는 E2B 내에서 실행되며, 세션당 새 VM을 생성하고 이후에 파괴합니다.
셸 명령과 Python은 완전히 격리된 환경 내에서 실행됩니다.

1from crewai_tools import E2BExecTool, E2BPythonTool2sandbox_tools = [E2BExecTool(), E2BPythonTool()] # 테스트 실행 / 코드 실행
인간参与的 승인 루프
Task에서 human_input=True를 설정하면 crew가 답변을 생성한 후 일시 중지됩니다. 출력을 검토한 다음 승인하거나 수정을 위해 다시 보낼 수 있습니다.
해당 작업에 도달하면 CrewAI는 표준 입력을 통해 여러분의 피드백을 기다립니다.
1from crewai import Task23task = Task(4 description=(5 "In the working directory ./workspace, {objective}. "6 "Explore the code first, make the change, then run the tests and report."7 ),8 expected_output="A summary of the files changed and the final test output.",9 human_input=True,10)
crew가 터미널 대신 웹 앱이나 채팅 인터페이스 뒤에서 실행되는 경우, CrewAI의 웹훅 기반 인간 참여 루프 시스템이 동일한 검토 단계를 처리합니다.
메모리와 체크포인팅
기본적으로 에이전트는 실행이 끝나면 모든 것을 잊어버립니다. 다음 날 같은 프로젝트의 다른 버그를 수정하기 위해 돌아오면 처음부터 시작합니다.
두 가지 메커니즘을 통해 에이전트가 실행 간에 정보를 전달할 수 있으며, 각각 다른 목적을 제공합니다.
- 체크포인팅은 실행 중 에이전트의 상태를 저장하여 중단 후 재개하거나 다른 경로를 따라 동일한 지점에서 계속할 수 있게 합니다.
- 영구 메모리는 별도의 대화 간에 사실을 저장하며, "최종 코드를 마치기 전에 항상 포맷하기"와 같은 프로젝트 선호도를 포함합니다.

CrewAI의 메모리
CrewAI는 별도의 단기, 장기, 엔터티, 외부 메모리 유형 대신 통합된 Memory 인터페이스를 제공합니다. 저장할 때 LLM을 사용하여 중요한 세부 사항을 식별하고 구성하고 나중에 검색할 수 있게 만듭니다.
crew에 memory=True를 설정하면 실행 간에 메모리가 생깁니다. 각 작업 후 CrewAI는 출력에서 유용한 사실을 추출하여 저장하고, 이후 실행에서는 관련 메모리를 검색하여 작업 프롬프트에 추가합니다.

1from crewai import Crew23crew = Crew(4 agents=[explorer, coder, tester],5 tasks=[task],6 memory=True,7)
crew의 모든 에이전트는 메모리를 공유합니다. 단, 에이전트가 자체 메모리를 가지고 있는 경우는 예외입니다.
CrewAI의 체크포인팅
체크포인트는 에이전트 진행 상황의 스냅샷입니다. 구성, 작업 상태, 메모리, 중간 결과, 입력, 실행 기록이 포함됩니다.
기본적으로 CrewAI는 작업이 완료될 때마다 체크포인트를 생성하여 중단된 경우 해당 지점에서 워크플로우를 재개할 수 있게 합니다.
체크포인트는 두 가지 내장 저장소 중 하나에 저장할 수 있습니다.
- JsonProvider는 각 체크포인트를 별도의 JSON 파일로 저장하며, 수동으로 읽고 검사하기 쉽습니다.
- SqliteProvider는 모든 체크포인트를 단일 SQLite 데이터베이스에 저장하며, 빈번한 체크포인팅과 더 큰 워크로드에서 더 잘 유지됩니다.

1from crewai import Crew23crew = Crew(4 agents=[explorer, coder, tester],5 tasks=[task],6 checkpoint=True,7)
Crew, Flow, Agent 모두 체크포인트 인수를 허용하며, 자식은 자체 값을 설정하지 않는 한 부모로부터 상속받습니다.
모든 것을 통합하기
다음은 실행 루프, 도구, 계획, 하위 에이전트, 샌드박싱, 메모리가 함께 작동하는 하나의 작업에 대한 전체 하네스입니다.
1from crewai import Agent, Crew, LLM, Process, Task2from crewai.tools import tool3from crewai_tools import (DirectoryReadTool, FileReadTool, FileWriterTool,4E2BExecTool, E2BPythonTool)56llm = LLM(model="anthropic/claude-sonnet-4.6")78list_dir = DirectoryReadTool(directory="./workspace")9filesystem_tools = [FileReadTool(), FileWriterTool(), list_dir]10sandbox_tools = [exec_tool, E2BPythonTool()]1112@tool("run_tests")13def run_tests(path: str = "tests/") -> str:14 """Sync ./workspace into the sandbox, then run pytest there."""15 return E2BExecTool().run(command=sync_and_test_command(path))1617explorer = Agent(role="Codebase Explorer", goal="Map repo, surface relevant files.",18 tools=[read_file, list_dir], llm=llm)19coder = Agent(role="Software Engineer", goal="Implement requested change.",20 tools=filesystem_tools, reasoning=True, llm=llm)21tester = Agent(role="Test Runner", goal="Run tests in sandbox, report pass/fail.",22 tools=sandbox_tools + [read_file] + [run_tests], llm=llm)23manager = Agent(role="Engineering Lead", goal="Delegate steps, finish once tests pass.",24 allow_delegation=True, llm=llm)2526task = Task(27 description="In ./workspace, {objective}. Explore, edit, test, report.",28 expected_output="Summary of changes and test output.", human_input=True,29)30crew = Crew(31 agents=[explorer, coder, tester], tasks=[task],32 manager_agent=manager, process=Process.hierarchical,33 planning=True, memory=True, checkpoint=True,34)35result = crew.kickoff(inputs={"objective": "fix failing tests in account.py"})
에이전트 하네스는 성공 여부를 자동으로 확인할 수 있을 때 가장 평가하기 쉽습니다. 테스트 스위트는 에이전트에 구체적인 목표를 제공하므로 계획, 편집, 테스트를 반복하여 모든 것이 통과할 때까지 진행할 수 있습니다.
따라서 이는 작은 코드베이스, 즉 두 개의 실제 버그와 다섯 개의 테스트(그중 세 개는 실패)가 있는 BankAccount 클래스에 대해 테스트되었습니다. 규칙은 테스트를 수정하지 않고 구현만 수정하는 것이었습니다.
이는 Anthropic이 내부적으로 코딩 에이전트를 평가하는 방식과 유사합니다. 공개된 예 중 하나는 Claude가 claude.ai 인터페이스의 클론을 대규모 실패 테스트 스위트에 대해 재구축하는 것입니다.
여기서 하네스는 프로젝트를 3개 실패, 2개 통과에서 5개 모두 통과로 이끌었으며, 구현 전용 규칙은 실패한 테스트를 편집하거나 제거하는 지름길을 차단했습니다.

여전히 여러분의 몫인 부분
시스템의 일부 부분은 프레임워크가 대신 구축해 주지 않습니다.
- 프롬프트. 각 에이전트의 동작은 역할, 목표, 배경 스토리에서 비롯됩니다. 이를 올바르게 설정하는 데는 테스트와 반복이 필요하며, 어떤 구성 플래그도 이를 대체할 수 없습니다.
- 실행 환경. 샌드박스(E2B 또는 자체 관리 VM)는 설정하고 연결해야 합니다.
- 도구 선택. 각 에이전트가 어떤 도구를 가져야 하는지, 어떤 에이전트가 무엇에 접근할 수 있어야 하는지는 프레임워크가 결정하지 않는 설계 결정입니다.
하네스 자체에도 비용이 따릅니다. 계획, 하위 에이전트, 루핑은 모두 API 호출을 추가하므로, 복잡한 에이전트 설정은 단일 모델 호출로 직접 해결할 수 있는 작업보다 더 비쌀 수 있습니다.
그리고 염두에 두어야 할 장기적인 한계도 있습니다. 모델이 개선됨에 따라 일부 스캐폴딩은 더 이상 필요하지 않게 됩니다. 오늘날 하네스에 구축되는 것 중 일부는 영구적인 요구 사항이 아니라 현재 모델의 한계에 대한 우회책이기 때문입니다.
Anthropic은 원래 컨텍스트 재설정을 사용하여 Claude Sonnet 4.5가 작업을 너무 일찍 종료하는 것을 방지했지만, 더 강력한 Claude Opus 4.5에서는 더 이상 필요하지 않았습니다.

마무리
이것이 전체 발견입니다. 코딩 에이전트의 능력은 대부분 하네스에 있으며, 오케스트레이션 프레임워크는 예상보다 더 많은 하네스를 제공합니다.
루프, 계획, 위임, 샌드박싱, 메모리는 모두 구성으로 제공되는 반면, 프롬프트, 실행 환경, 도구 선택은 여러분의 몫으로 남습니다.
이를 자신의 코드베이스에 대해 실행하고 싶다면, CrewAI 문서에 여기 사용된 모든 기능이 설명되어 있으며, 프레임워크는 완전히 오픈소스입니다.
읽어주셔서 감사합니다!
감사합니다! :)





