
에이전트 하네스(Agent Harness)의 구조 분석
요약
LLM을 유능한 에이전트로 변모시키는 소프트웨어 인프라인 '에이전트 하네스(Agent Harness)'의 개념과 구조를 분석합니다. 오케스트레이션, 메모리, 도구 관리 등 모델 외부의 인프라가 에이전트의 성능을 결정짓는 핵심 요소임을 설명합니다.
핵심 포인트
- 에이전트 하네스는 LLM을 감싸는 오케스트레이션, 메모리, 도구, 가드레일 등의 인프라를 의미함
- 모델 자체보다 모델 주변의 인프라 최적화가 에이전트 성능 향상에 결정적임
- 에이전트는 창발적 행동을 하는 개체이며, 하네스는 그 행동을 만드는 기계 장치임
- LangChain 사례를 통해 인프라 개선만으로 벤치마크 성능이 급상승함을 증명함
Anthropic, OpenAI, Perplexity, 그리고 LangChain이 실제로 무엇을 구축하고 있는지 깊이 있게 살펴봅니다. 오케스트레이션 루프(orchestration loop), 도구(tools), 메모리(memory), 컨텍스트 관리(context management), 그리고 상태가 없는(stateless) LLM을 유능한 에이전트로 변모시키는 그 외 모든 요소를 다룹니다.
당신은 챗봇을 만들어 보았습니다. 아마 몇 가지 도구와 함께 ReAct 루프를 연결했을 수도 있습니다. 데모용으로는 작동합니다. 하지만 프로덕션급(production-grade) 결과물을 만들려고 시도하면 문제가 발생합니다. 모델은 세 단계 전의 일을 잊어버리고, 도구 호출(tool calls)은 소리 없이 실패하며, 컨텍스트 윈도우(context windows)는 쓰레기 데이터로 가득 찹니다.
문제는 당신의 모델이 아닙니다. 모델 주변의 모든 것입니다.
LangChain은 LLM을 감싸는 인프라만 변경했을 때(동일한 모델, 동일한 가중치), TerminalBench 2.0에서 상위 30위권 밖에서 5위로 급상승하며 이를 증명했습니다. 별도의 연구 프로젝트에서는 LLM이 인프라 자체를 최적화하도록 하여, 수작업으로 설계된 시스템을 능가하는 76.4%의 통과율을 기록했습니다.
이제 그 인프라에는 이름이 생겼습니다. 바로 에이전트 하네스(agent harness)입니다.
에이전트 하네스란 무엇인가?
이 용어는 2026년 초에 공식화되었지만, 개념은 그 훨씬 전부터 존재했습니다. 하네스는 LLM을 감싸는 완전한 소프트웨어 인프라를 의미합니다: 오케스트레이션 루프(orchestration loop), 도구(tools), 메모리(memory), 컨텍스트 관리(context management), 상태 지속성(state persistence), 오류 처리(error handling), 그리고 가드레일(guardrails)이 그것입니다. Anthropic의 Claude Code 문서에서는 이를 간단하게 설명합니다: SDK는 "Claude Code를 구동하는 에이전트 하네스"입니다. OpenAI의 Codex 팀도 동일한 프레임을 사용하여, LLM을 유용하게 만드는 비모델(non-model) 인프라를 지칭할 때 "에이전트(agent)"와 "하네스(harness)"라는 용어를 명시적으로 동일시합니다.
LangChain의 Vivek Trivedy가 제시한 정석적인 공식은 다음과 같습니다: "당신이 모델이 아니라면, 당신은 하네스입니다."
사람들이 혼동하는 지점은 바로 이 차이점입니다. "에이전트(agent)"는 창발적 행동(emergent behavior), 즉 사용자가 상호작용하는 목표 지향적이고, 도구를 사용하며, 스스로 수정하는 개체를 의미합니다. 하네스(harness)는 그러한 행동을 만들어내는 기계 장치입니다. 누군가가 "나는 에이전트를 만들었다"라고 말할 때, 그것은 하네스를 구축하고 이를 모델에 연결했다는 의미입니다.
Beren Millidge는 2023년 에세이 《Scaffolded LLMs as Natural Language Computers》에서 이 비유를 명확하게 했습니다. 순수한 LLM은 RAM도, 디스크도, I/O도 없는 CPU와 같습니다. 컨텍스트 창(context window)은 RAM 역할을 합니다 (빠르지만 제한적). 외부 데이터베이스는 디스크 저장소 역할을 합니다 (크지만 느림). 도구 통합(tool integrations)은 장치 드라이버(device drivers) 역할을 합니다. 그리고 하네스(harness)가 운영체제(operating system)입니다. Millidge가 쓴 것처럼,
기계적으로 보면, 이는 종종 단순한 while 루프(while loop)에 불과합니다. 복잡성은 루프 자체가 아니라 루프가 관리하는 모든 요소에 존재합니다. Anthropic은 자신들의 런타임(runtime)을 모든 지능이 모델에 존재하는 "멍청한 루프(dumb loop)"라고 설명합니다. 하네스(harness)는 단지 턴(turn)을 관리할 뿐입니다.
2. 도구 (Tools)
도구는 에이전트의 손입니다. 도구는 스키마(schema, 이름, 설명, 파라미터 타입)로 정의되어 LLM의 컨텍스트(context)에 주입되며, 이를 통해 모델은 무엇을 사용할 수 있는지 알게 됩니다. 도구 계층(tool layer)은 등록, 스키마 검증(schema validation), 인자 추출(argument extraction), 샌드박스 실행(sandboxed execution), 결과 캡처, 그리고 결과를 LLM이 읽을 수 있는 관찰(observation) 형태로 다시 포맷팅하는 작업을 처리합니다.
Claude Code는 파일 작업, 검색, 실행, 웹 접속, 코드 인텔리전스(code intelligence), 서브 에이전트 생성(subagent spawning)의 6가지 카테고리에 걸쳐 도구를 제공합니다. OpenAI의 Agents SDK는 함수 도구(@function_tool을 통해), 호스팅된 도구(WebSearch, CodeInterpreter, FileSearch), 그리고 MCP 서버 도구를 지원합니다.
3. 메모리 (Memory)
메모리는 여러 시간 척도(timescale)에서 작동합니다. 단기 메모리(Short-term memory)는 단일 세션 내의 대화 기록입니다. 장기 메모리(Long-term memory)는 세션 간에 지속됩니다. Anthropic은 CLAUDE.md 프로젝트 파일과 자동 생성된 MEMORY.md 파일을 사용하며, LangGraph는 네임스페이스(namespace)로 정리된 JSON 저장소(JSON Stores)를 사용합니다. OpenAI는 SQLite 또는 Redis를 기반으로 하는 세션(Sessions)을 지원합니다.
Claude Code는 3단계 계층 구조를 구현합니다: 항상 로드되는 가벼운 인덱스(항목당 약 150자), 필요할 때 불러오는 상세 주제 파일(topic files), 그리고 검색을 통해서만 접근 가능한 원시 트랜스크립트(raw transcripts)입니다. 중요한 설계 원칙은 에이전트가 자신의 메모리를 "힌트(hint)"로 취급하며, 행동하기 전에 실제 상태(actual state)와 대조하여 검증한다는 것입니다.
4. 컨텍스트 관리 (Context Management)
이 부분은 많은 에이전트가 조용히 실패하는 지점입니다. 핵심 문제는 컨텍스트 부패(context rot)입니다. 핵심 콘텐츠가 윈도우(window) 중간 위치에 놓이게 되면 모델 성능이 30% 이상 저하됩니다. 심지어 백만 토큰 규모의 윈도우조차 컨텍스트가 커짐에 따라 지시 이행(instruction-following) 능력이 저하되는 문제를 겪습니다.
프로덕션 전략에는 다음이 포함됩니다:
✧ 압축 (Compaction): 한계치에 도달할 때 대화 기록을 요약합니다.
✧ 관찰 마스킹 (Observation masking): 도구 호출 (tool calls)은 보이게 유지하면서 오래된 도구 출력값은 숨깁니다.
✧ 적시 검색 (Just-in-time retrieval): 가벼운 식별자 (identifiers)를 유지하고 데이터를 동적으로 로드합니다.
✧ 서브 에이전트 위임 (Sub-agent delegation): 각 서브 에이전트 (subagent)가 광범위하게 탐색하되 응축된 요약본을 반환합니다.
Anthropic의 컨텍스트 엔지니어링 (context engineering) 가이드에 명시된 목표는 다음과 같습니다: 원하는 결과의 가능성을 극대화하는, 가능한 한 가장 작은 고신호 토큰 (high-signal tokens) 세트를 찾는 것입니다.
5. 프롬프트 구성 (Prompt Construction)
이는 모델이 각 단계에서 실제로 보게 되는 것들을 조립합니다. 이는 계층적입니다: 시스템 프롬프트 (system prompt), 도구 정의 (tool definitions), 메모리 파일 (memory files), 대화 기록 (conversation history), 그리고 현재 사용자 메시지 (current user message).
OpenAI의 Codex는 엄격한 우선순위 스택 (priority stack)을 사용합니다: 서버 제어 시스템 메시지 (server-controlled system message), 도구 정의 (tool definitions), 개발자 지침 (developer instructions), 사용자 지침 (user instructions), 그 다음 대화 기록 (conversation history) 순입니다.
6. 출력 파싱 (Output Parsing)
현대적인 하네스 (harnesses)는 네이티브 도구 호출 (native tool calling)에 의존하며, 여기서 모델은 파싱해야 하는 자유 형식의 텍스트 대신 구조화된 tool_calls 객체를 반환합니다. 하네스는 다음을 확인합니다: 도구 호출이 있는가? 있다면 실행하고 루프를 돕니다. 도구 호출이 없다면? 그것이 최종 답변입니다.
구조화된 출력 (structured outputs)을 위해, OpenAI와 LangChain 모두 Pydantic 모델을 통한 스키마 제약 응답 (schema-constrained responses)을 지원합니다. RetryWithErrorOutputParser와 같은 레거시 (legacy) 방식은 예외적인 상황 (edge cases)을 위해 여전히 사용 가능합니다.
7. 상태 관리 (State Management)
LangGraph는 상태를 그래프 노드 (graph nodes)를 통해 흐르는 타입 지정 딕셔너리 (typed dictionaries)로 모델링하며, 리듀서 (reducers)가 업데이트를 병합합니다. 체크포인팅 (Checkpointing)은 슈퍼 스텝 (super-step) 경계에서 발생하여, 중단 후 재개 및 타임 트래블 디버깅 (time-travel debugging)을 가능하게 합니다. OpenAI는 서로 배타적인 네 가지 전략을 제공합니다: 애플리케이션 메모리 (application memory), SDK 세션 (SDK sessions), 서버 측 Conversations API, 또는 가벼운 previous_response_id 체이닝 (chaining)입니다. Claude Code는 다른 접근 방식을 취합니다: git 커밋 (git commits)을 체크포인트로 사용하고 진행 파일 (progress files)을 구조화된 스크래치패드 (scratchpads)로 사용합니다.
8. 에러 핸들링 (Error Handling)
단계당 성공률이 99%인 10단계 프로세스라 할지라도, 엔드 투 엔드 (end-to-end) 성공률은 약 90.4%에 불과합니다. 에러는 빠르게 누적됩니다.
LangGraph는 에러 유형을 일시적(transient), LLM 복구 가능(LLM-recoverable), 사용자 수정 가능(user-fixable), 그리고 예기치 않은(unexpected) 에러의 네 가지로 구분합니다. Anthropic은 도구 핸들러(tool handlers) 내에서 발생하는 실패를 포착하여 이를 에러 결과로 반환함으로써 루프가 계속 유지되도록 합니다. Stripe의 프로덕션 하네스(production harness)는 재시도 횟수를 최대 2회로 제한합니다.
9. 가드레일(Guardrails) 및 안전성
OpenAI의 SDK는 입력 가드레일(input guardrails), 출력 가드레일(output guardrails), 그리고 도구 가드레일(tool guardrails)의 세 가지 수준을 구현합니다. "트립와이어(tripwire)" 메커니즘은 트리거가 발생하면 에이전트를 즉시 중단시킵니다.
Anthropic은 권한 집행(permission enforcement)을 모델의 추론(reasoning)과 아키텍처적으로 분리합니다. 모델은 무엇을 시도할지 결정하고, 도구 시스템은 무엇이 허용되는지를 결정합니다. Claude Code는 약 40개의 개별적인 도구 기능(tool capabilities)을 독립적으로 제어하며, 다음의 세 단계를 거칩니다: 프로젝트 로드 시 신뢰 구축(trust establishment), 각 도구 호출 전 권한 확인(permission check), 그리고 고위험 작업에 대한 명시적인 사용자 확인(explicit user confirmation).
10. 검증 루프(Verification Loops)
이것이 바로 단순한 데모용 프로젝트와 프로덕션 에이전트를 구분 짓는 요소입니다. Anthropic은 규칙 기반 피드백(rules-based feedback), 시각적 피드백(visual feedback), 그리고 LLM-as-judge(판사로서의 LLM)의 세 가지 접근 방식을 권장합니다.
Claude Code의 제작자인 Boris Cherny는 모델에게 자신의 작업을 검증할 수 있는 방법을 제공하면 품질이 2~3배 향상된다고 언급했습니다.
11. 서브에이전트 오케스트레이션(Subagent Orchestration)
Claude Code는 Fork, Teammate, Worktree의 세 가지 실행 모델을 지원합니다. OpenAI의 SDK는 에이전트-애즈-툴(agents-as-tools)과 핸드오프(handoffs)를 지원합니다. LangGraph는 서브에이전트를 중첩된 상태 그래프(nested state graphs)로 구현합니다.
작동하는 루프
이제 구성 요소들을 알았으니, 단일 사이클 내에서 이들이 어떻게 함께 작동하는지 추적해 보겠습니다.
1단계: 프롬프트 조립(Prompt Assembly) — 하네스는 시스템 프롬프트(system prompt), 도구 스키마(tool schemas), 메모리 파일(memory files), 대화 기록(conversation history), 그리고 현재 사용자 메시지를 포함한 전체 입력을 구성합니다.
2단계: LLM 추론(LLM Inference) — 조립된 프롬프트가 모델 API로 전달됩니다. 모델은 텍스트, 도구 호출 요청(tool call requests), 또는 이 둘 모두를 포함한 출력 토큰을 생성합니다.
Step 3: 출력 분류(Output Classification) — 모델이 도구 호출 요청이 없는 텍스트를 생성한 경우 루프가 종료됩니다. 도구 호출을 요청한 경우 실행 단계로 진행합니다. 핸드오프(handoff)가 요청된 경우 현재 에이전트를 업데이트하고 재시작합니다.
Step 4: 도구 실행(Tool Execution) — 각 도구 호출에 대해, 하네스(harness)는 인수를 검증하고, 권한을 확인하며, 격리된 환경(sandboxed environment)에서 실행하고, 결과를 포착합니다.
Step 5: 결과 패키징(Result Packaging) — 도구 결과는 LLM이 읽기 쉬운 메시지 형태로 형식화됩니다. 오류가 발생하면 에러 결과로 잡혀 반환되어 모델이 자체적으로 수정할 수 있게 합니다.
Step 6: 컨텍스트 업데이트(Context Update) — 결과는 대화 기록에 추가됩니다. 컨텍스트 창 한계에 접근하게 되면, 하네스는 압축(compaction)을 트리거합니다.
Step 7: 루프(Loop) — Step 1로 돌아가 종료될 때까지 반복합니다.
종료 조건은 여러 단계로 구성되어 있습니다. 모델이 도구 호출 없이 응답을 생성하는 경우, 최대 턴 제한 초과, 토큰 예산 소진, 가드레일 트립와이어(guardrail tripwire) 작동, 사용자 중단, 또는 안전 거부(safety refusal)가 반환되는 경우입니다.
여러 컨텍스트 창에 걸쳐 실행되는 장기 작업의 경우, Anthropic은 두 단계의 "Ralph Loop" 패턴을 개발했습니다. 초기화 에이전트(Initializer Agent)가 환경을 설정하고, 이후 모든 세션에서 코딩 에이전트(Coding Agent)는 git 로그와 진행 파일들을 읽어 자신을 정렬하며, 가장 우선순위가 높은 미완료 기능을 선택하여 작업하고, 커밋하며, 요약문을 작성합니다.
실제 프레임워크 구현 방식
Anthropic의 Claude Agent SDK는 단일 query() 함수를 통해 하네스를 노출하며, 이 함수가 에이전트 루프를 생성하고 메시지를 스트리밍하는 비동기 반복자(async iterator)를 반환합니다. Claude Code는 수집-행동-검증(Gather-Act-Verify) 사이클을 사용합니다: 컨텍스트를 수집하고, 행동을 취하며, 결과를 검증하고, 이를 반복합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
