sLLM 모델을 활용해 실제 어플리케이션을 만드는 조직이라면 한 번쯤 반드시 고민하게 되는 지점이 있다.
"우리가 할 일은 모델을 더 똑똑하게 만드는 것이 아니라, 모델이 잘 작동할 수 있는 환경을 만드는 것이다."
이 질문은 단순한 선택의 문제가 아니라 역할의 구분에 대한 문제다. 모델은 이미 학습된 상태로 주어지고, 우리가 실제로 다루는 것은 그 모델이 동작하는 환경이다.
물론 sLLM을 SFT(supervised fine-tuning)하거나 ORPO(odds ratio-based optimization)와 같은 방식으로 모델을 직접 개선하는 접근도 존재한다. 그러나 실제 서비스 환경에서는 이러한 방식이 비용과 시간 측면에서 매우 큰 부담이 된다. 결국 AI 엔지니어인 우리가 반복적으로 설계하고 개선할 수 있는 영역은 모델 자체가 아니라, 모델이 놓이는 실행 환경이다.
Hanress라는 단어 의미만을 봤을 때, 마차를 끌거나 무거운 짐을 운반할 때 말의 몸에 채우는 마구(馬具)의 일종이다. 결국 모델(LLM)이라는 말을 잘 이끌기 위한 컨텍스트와 환경을 잘 구현하기 위한 엔지니어링 기법이 하네스 엔지니어링(Harness Engineering)이라는 것이다.
이 관점은 단순한 철학이 아니라, 시스템 아키텍처를 설계할 때의 중요한 기준이 된다. 예를 들어 RAG(Retrieval-Augmented Generation)는 흔히 모델을 더 똑똑하게 만드는 방법으로 이해되지만, 사실은 모델의 파라미터를 바꾸는 접근이 아니다. 이는 모델에 제공되는 입력, 즉 컨텍스트의 품질과 구조를 개선하는 방식이며, 하네스를 구성하는 하나의 전략이라고 보는 것이 더 정확하다.
이렇게 보면 LLM 기반 시스템은 “모델 + 하네스”의 결합으로 정의할 수 있다. 모델은 Claude나 GPT와 같은 autoregressive LLM으로, 실제로 판단을 수행하는 주체이며 곧 에이전트 그 자체다. 반면 하네스는 모델이 현실 세계와 상호작용할 수 있도록 만드는 실행 환경이다. 중요한 점은 하네스가 단순한 wrapper가 아니라는 것이다. 이는 모델이 접근할 수 있는 전체 운영 환경이며, 시스템의 성능을 결정짓는 핵심 요소다.
- 모델: Claude, GPT와 같은 autoregressive LLM (즉, 에이전트 그 자체)
- 하네스: 모델이 현실 세계와 상호작용할 수 있도록 만드는 실행 환경
하네스를 구성하는 요소를 보면 그 역할이 더 명확해진다. 파일 읽기/쓰기나 쉘 실행, API 호출과 같은 도구는 모델의 행동 수단이 되고, 문서나 가이드라인, 도메인 정보는 외부 지식으로 작동한다. 여기에 메모리 압축이나 세션 분리, 상태 유지와 같은 컨텍스트 관리가 더해지고, 위험한 명령을 제한하거나 sandbox를 적용하는 권한 제어까지 포함된다. 결국 하네스는 모델이 접근 가능한 “세계”를 정의하는 구조이며, 모델의 실제 성능은 이 환경이 어떻게 설계되었는지에 크게 의존하게 된다.
- 도구: 파일 읽기/쓰기, 쉘 실행, API 호출
- 지식: 문서, 가이드라인, 도메인 정보
- 컨텍스트 관리: 메모리 압축, 세션 분리, 상태 유지
- 권한 제어: 위험 명령 제한, sandbox, 승인 흐름
- Observability, Evaluation 등..
즉, 하네스는 모델이 접근 가능한 “운영 환경”이며, 모델의 실제 성능은 이 환경 설계에 의해 크게 좌우된다.
이 관점에서 예전에 하입을 잠깐 받았던 컨텍스트 엔지니어링과 하네스 엔지니어링은 나의 이해에서는 거의 비슷하다. 컨텍스트 엔지니어링이든 하네스 엔지니어링이든 본질은 우리가 풀고자 하는 문제에 대해서, 모델이 더 잘 수행하도록 하기 위해 모델의 행동까지 포함한 전체 시스템을 설계하는 것이다.
아래의 그림에서 Large Language Model(LLM) 부분을 제외한 모든 부분인 것이다.

그래서 AI 엔지니어가 "에이전트를 개발한다"는 것은 크게 두 가지로 나눌 수 있다:
- ORPO, SFT 등으로 모델 파라미터를 학습하는 것
- 모델이 동작할 환경, 즉 하네스를 설계하는 것
그리고 우리가 실제 서비스에서 수행하는 대부분의 작업은 후자에 해당한다. 이러한 하네스 구조를 이해하는 가장 직관적인 예시가 Claude Code이다. Claude Code는 모델을 직접 통제하거나 복잡한 워크플로우를 강제하지 않는다. 대신 모델이 사용할 수 있는 도구, 필요한 지식, 컨텍스트 관리 방식, 그리고 권한 체계를 제공한다. 즉, 모델이 스스로 판단하고 행동할 수 있도록 환경을 구성해주는 방식이다.
사용자가 요청을 입력하면 모델이 이를 해석하고, 필요하다면 tool을 호출한다. 해당 tool이 실행되고 그 결과가 다시 모델에게 전달되며, 이 과정이 반복된다. 모델이 더 이상 tool을 호출하지 않는 시점에서 작업이 종료된다. 이 구조를 풀어서 보면 결국 하나의 루프다. 모델이 행동을 선택하고, 하네스가 그것을 실행하고, 그 결과를 다시 모델에게 전달하는 반복 구조다.
User → LLM → Tool 실행 → 결과 → 다시 LLM (반복)
이것이 핵심 루프이다. 사실 그냥 ReAct 구조이다.
모델이 멈출 때까지 tool 결과를 계속 다시 넣는다. 물론 실제 서비스에서는 여기에 정책, 라이프사이클 제어가 추가된다.
User → messages → LLM → response
↓
tool 필요?
/ \
yes no
↓ ↓
tool 실행 종료
결과 추가
루프 반복
최근 AI 코딩 에이전트의 패턴으로 하네스의 구성요소인 Tool에 대해서 감을 익혀보자. 아래와 같은 시스템 프롬프트와 툴이 들어간 상태일 것이다.
"너는 현재 작업 디렉터리에서 동작하는 코딩 에이전트다. 작업을 해결할 때 bash를 사용하라. 설명하지 말고 행동하라."
그리고 bash라는 툴이 있고, command라는 입력을 받는 인터페이스 설명을 입력한다.
SYSTEM = f"You are a coding agent at {os.getcwd()}. Use bash to solve tasks. Act, don't explain."
TOOLS = [{
"name": "bash",
"description": "Run a shell command.",
"input_schema": {
"type": "object",
"properties": {"command": {"type": "string"}},
"required": ["command"],
},
}]
사용자 쿼리를 분석해 모델이 “ls 명령 실행해(bash)”라고 말했다고 하자.
{
"name": "bash",
"input": { "command": "ls" }
}
이걸 진짜로 수행하는 건 우리가 정의한 하네스인 툴 run_bash 부분이다.
해당 코드는 위험한 명령이 포함되어 있으면(rm, reboot 등) 차단하고, 아니면 현재 디렉터리에서 쉘 명령을 실행한다.
def run_bash(command: str) -> str:
dangerous = ["rm -rf /", "sudo", "shutdown", "reboot", "> /dev/"]
if any(d in command for d in dangerous):
return "Error: Dangerous command blocked"
try:
r = subprocess.run(command, shell=True, cwd=os.getcwd(),
capture_output=True, text=True, timeout=120)
out = (r.stdout + r.stderr).strip()
return out[:50000] if out else "(no output)"
except subprocess.TimeoutExpired:
return "Error: Timeout (120s)"
여기서 중요한 점은, 하네스는 LLM의 행동을 실행하고, 결과를 검증하고, 시스템 레벨 의사결정을 수행하는 계층이라는 거다.
위 AI 코딩 에이전트에서 하네스는 아래를 수행한다.
- 모델 호출
- tool 실행
- 결과 전달
즉, 무엇을 할지 결정은 모델이 하고, 그 실행은 하네스가 한다.
실제 서비스 구조에서는 Skill, Task Planner, Summary, 복잡한 정책, 라이프사이클 제어 등이 포함되겠지만 결국 이 구조의 본질은 명확하다. 모델은 스스로 행동을 결정하는 주체이고, 하네스는 그 행동을 현실 세계에서 실행하는 장치다. 우리는 모델을 만드는 것이 아니라, 모델이 제대로 작동할 수 있는 환경을 설계하는 것이다. 그리고 그 환경의 품질이 곧 시스템의 품질을 결정한다.
참고:
https://github.com/shareAI-lab/learn-claude-code
'블로그 > 생각거리' 카테고리의 다른 글
| 멀티 에이전트 설계에서 반복적으로 부딪히는 질문들 (0) | 2026.03.23 |
|---|---|
| 데이터 분석가의 일 (0) | 2023.05.13 |