에이전트, 그리고 엔지니어링
LLM을 다루는 일을 하다 보면, 같은 문제를 두고도 부르는 이름이 1~2년마다 바뀐다는 인상을 받게 된다. 2022년의 ‘프롬프트 엔지니어링’은 2024~2025년에 ‘컨텍스트 엔지니어링’이 되었고, 2026년에 들어서면서는 ‘하네스 엔지니어링(Harness Engineering)’이라는 표현이 빠르게 자리를 잡고 있다.
AI 분야가 빠르게 발전하면서, 사실 새 모델이 자꾸 나오는 것 만큼이나 개발자들을 가장 피곤하게 만드는 건, 명확히 정의되지 않은 용어들이 쏟아져 나와 막연한 채로 통용되는 일이다. 같은 단어를 다르게 이해하는 사람들이 많아지면서, 같은 단어를 사용하는데도 소통이 이상하게 엇나가는 경우도 많았다.
특히 ‘에이전트(Agent)’는 용어 정의가 명확하지 않았었지만, 지금까지 그 의미가 가장 많이 좁혀지기도 한 단어 중 하나다. 그래서 이 글에서는 먼저 에이전트를 어떻게 정의해야 하는지 정리하고, 그 위에서 프롬프트 엔지니어링, 컨텍스트 엔지니어링, 하네스 엔지니어링에 대해 차례로 정리한다.
Agent
‘에이전트’라는 단어는 LLM 시대에 들어 의미가 가장 빠르게 변한 표현 중 하나다.
2023년경 학술 논문들에서 ‘agent’는 지금보다 훨씬 가볍게 쓰였다. 한 가지 예가 Stanford의 Generative Agents: Interactive Simulacra of Human Behavior (Park et al., 2023)이다. 이 논문은 25명의 캐릭터에게 각자의 페르소나, 기억, 계획을 부여한 시뮬라크라를 ‘generative agent’라고 불렀다. 즉, LLM에 정체성과 메모리만 부여하면 에이전트라는 식의 비교적 느슨한 정의가 통용되던 시기다. 즉, 페르소나가 입혀진 LLM 인스턴스 정도로 정의된 것이다.
‘agent’의 정의가 지금과 같이 좁혀진 것은 2024년 12월 Anthropic의 “Building Effective Agents” 글을 기점으로 한다. 이 글의 정의를 그대로 옮기면 이렇다.
“Agents are systems where LLMs dynamically direct their own processes and tool usage, maintaining control over how they accomplish tasks.”
“Workflows are systems where LLMs and tools are orchestrated through predefined code paths.”
여기서 제안한 두 가지 키워드는 도구 사용(코드 실행, API 호출, 외부 시스템에 영향을 주는 행위를 할 수 있다는 것), 그리고 동적 제어 흐름(다음 단계를 사람이나 미리 정해진 코드가 아니라 모델 자신이 결정한다는 것)이다. 이 정의에 따르면 페르소나를 부여했을 뿐인 LLM은 더 이상 에이전트가 아니다. 에이전트라고 부르려면 외부 세계에 영향을 줄 수 있는 도구를 갖고, 그 도구를 언제 어떻게 쓸지 모델이 스스로 정하며, 관찰 - 추론 - 행동 - 다시 관찰의 루프(agentic loop) 안에서 동작해야 한다.
Anthropic은 한발 더 나아가 워크플로우(고정된 경로)와 에이전트(동적 경로)를 자율성의 스펙트럼으로 본다. 모든 작업을 풀 자율 에이전트로 풀 필요는 없고, 위험과 가치에 맞춰 자율성 수준을 고르는 것 자체가 시스템 설계자의 일이라는 뜻이다. 자율성이 높아질수록 위험도 함께 커진다. 페르소나가 입혀진 챗봇이 잘못된 답을 하면 사용자에게 잘못된 정보가 전달될 뿐이지만, 도구를 쥔 자율 에이전트가 잘못 행동하면 DB 테이블이 날아가거나, 잘못된 PR이 머지되거나, 외부 API에 비용이 청구된다. 그래서 ‘에이전트’가 “페르소나가 있는 LLM” 정도였던 시절에는 큰 안전장치 없이도 다룰 수 있었지만, 현재 정의의 에이전트를 다루려면 후술할 하네스 엔지니어링이 거의 필수가 된다.
프롬프트 엔지니어링
Copilot, ChatGPT 같은 LLM 서비스가 출시되었을 때, 사용자들은 같은 질문이라도 어떻게 묻느냐에 따라 답변 품질이 크게 달라진다는 것을 알게 되었다. 여기에서 프롬프트 엔지니어링이 출발했고, 이는 LLM에게 원하는 결과를 얻기 위해 입력 문장을 설계하고 최적화하는 기술로 정의되었다.
당시 빠르게 표준이 된 유명한 기법으로는 페르소나 부여하기, Chain of Thought, ReAct 등이 있다. 특히 ReAct 논문에서는 추론과 행동을 번갈아 수행하게 만드는 구조를 제안했는데, 모델이 모르면 검색해서 확인할 수 있게 만든 이 패턴이 오늘날 Claude Code, Codex, Cursor 같은 모든 코딩 에이전트의 기반이 된다고 볼 수 있다. 다만 프롬프트 엔지니어링은 복잡한 문제를 해결하려면 긴 컨텍스트를 가진 프롬프트가 필요했고, 대화 턴을 오래 지속해야 한다는 문제에 맞닥뜨리게 되었다.
컨텍스트 엔지니어링
대화가 길어지거나 도구 호출 결과가 쌓이면 컨텍스트 윈도우가 가득 차고, 가득 찬 컨텍스트는 오히려 모델 성능을 떨어뜨린다. 대화 기록 전체가 매 턴마다 다시 모델에 입력되는 구조 때문에 입력이 길어질수록 중요한 정보가 흐려지는 현상도 자주 관찰됐다.
2025년 중반, 이 문제를 한 단어로 묶은 표현이 Andrej Karpathy의 트윗을 통해 널리 퍼졌다.
“+1 for ‘context engineering’ over ‘prompt engineering’. (…) Context engineering is the delicate art and science of filling the context window with just the right information for the next step.”
비슷한 시기 Shopify CEO Tobi Lütke 역시 “LLM에 필요한 모든 맥락을 제공하는 일”이라는 표현으로 같은 개념을 강조했고, 두 사람의 영향력 덕분에 이 용어는 빠르게 표준어가 됐다. 이때부터 엔지니어의 역할은 운영체제처럼 이번 턴에 필요한 데이터와 코드만 RAM에 올려놓는 것으로 점점 변하기 시작했다. 관심의 단위가 문장에서 시스템 전체의 입력 파이프라인으로 확장된 것이다.
이 관점에서, 시스템 프롬프트, 채팅 히스토리, 장기 기억(memory), RAG로 끌어오는 외부 문서, MCP로 연결된 도구의 출력, 그리고 길어진 컨텍스트를 줄여서 다시 끼워넣는 압축(compaction)까지가 모두 같은 층위에서 컨텍스트의 일부로 다뤄지기 시작한다.
다만, 컨텍스트는 무조건 많이 넣을수록 좋은 게 아니다. 2026년 들어 Claude Opus가 1M까지 컨텍스트 윈도우를 늘렸지만, 실제로 사용해보면 약 300K를 넘어가면 결과물 품질이 빠르게 무너진다. 이건 트랜스포머 모델의의 자기회귀 구조상 어쩌면 당연한 일이기도 하다. 입력이 길어질수록 매 토큰마다 참조해야 할 양이 늘어나고, 연산량이 늘면 오류 확률도 함께 누적된다. Claude Code가 컨텍스트의 95%쯤이 차면 자동 압축을 거는 것도 같은 이유다. 실제로는 좀 더 일찍 압축하고 진행하는 것이 더 좋은 결과를 냈다.
그래서 실전에서는 “무엇을 처음부터 컨텍스트에 넣고, 무엇은 필요할 때 도구로 끌어올 것인가”를 나누는 일이 핵심 작업이 된다. 작업 목표와 제약, 코딩 컨벤션, 최근 아키텍처 변경, 절대 하면 안 되는 행동(보안 폴더 접근 금지 등)은 처음부터 주입할 필요가 있다. 반대로 디테일한 코드 본문, 대용량 로그, 외부 API 레퍼런스, 테스트 실행 결과 같은 것은 처음부터 들고 갈 필요가 없다. 모델이 필요하다고 판단할 때 도구로 가져오게 두는 편이 컨텍스트 예산을 훨씬 효율적으로 쓴다.
이 원칙은 OpenAI가 2026년 2월에 공개한 코딩 에이전트 회고에도 그대로 등장한다. 처음에는 하나의 큰 AGENTS.md에 모든 지침을 박아넣었는데, 분량이 늘어나자 모델이 앞부분만 대충 읽고 넘어가는 문제가 있었다. 결국 그들은 AGENTS.md를 책의 목차처럼 가벼운 진입점으로만 두고, 세부 규칙은 docs/ 하위에 architecture, product-spec, references, execution-plans, security 같은 파일로 흩어 놓아 모델이 필요할 때 점진적으로 펼쳐 보도록 구조를 바꿨다. 컨텍스트 엔지니어링이 “많이 넣기”가 아니라 “필요할 때만 펼쳐지도록 설계하기”에 가깝다는 점을 잘 보여주는 사례다.
다만 컨텍스트를 잘 짜도 해결되지 않는 영역이 남는다. 컨텍스트 엔지니어링은 한 세션이 모델에게 주어지는 시점까지를 다루지만, 에이전트가 도구를 들고 자율적으로 움직이는 동안 발생하는 일탈, 실수를 잡지는 못한다. 그렇다면 문제는, 환경 전체를 어떻게 짜야 에이전트가 안전하게 돌아갈까로 옮겨가게 된다.
하네스 엔지니어링
‘하네스(harness)’는 원래 마차를 끄는 말에 씌우던 안장, 고삐, 굴레를 가리키는 단어다. 방향을 지시하고, 실행 능력을 부여하고, 통제 범위를 강제하는 장치 일체. LLM 맥락에서 이 단어가 자리를 잡은 것은 2026년 2월, HashiCorp 공동 창업자이자 Terraform, Ghostty 개발자인 Mitchell Hashimoto의 블로그 글에서다. 그가 제시한 공식은 단순하고 아름답다.
Agent = Model + Harness (편안..)
핵심 아이디어는 이렇다. 에이전트가 실수를 할 때마다, 같은 실수를 다시 하지 못하도록 환경을 영구적으로 고친다. 모델 자체의 업그레이드를 기다리는 게 아니라, 에이전트를 둘러싼 작업 환경(harness)을 한 단계씩 다듬어 가는 것이다. 그러니까 ‘에이전트’를 만드는 일은 사실 모델을 다루는 일이 아니라, 모델 바깥의 모든 것 — 컨텍스트, 도구, 실행 루프, 검증, 사람의 개입 지점 — 을 통합 설계하는 일이다.
이 흐름이 부각된 데는 비슷한 시기 OpenAI가 “5개월간 사람이 코드 한 줄도 안 치고 에이전트만으로 서비스를 만들었다”는 회고를 공개한 영향도 컸다. 실제 사례가 나오자 “과연 어디까지 가능한가”에 대한 막연함이 “이렇게 하면 된다”의 구체적 패턴들로 바뀌기 시작했다. Anthropic은 더 직접적인 비교 실험도 공개했다. 동일 작업을 하네스 없이 단일 에이전트에게 맡겼을 때는 약 9달러를 쓰며 20분간 동작했지만 결과물은 실행조차 되지 않는 코드였고, 멀티 에이전트와 잘 짜인 하네스를 결합한 구성에서는 200달러를 쓰고 6시간 동안 16개 기능을 만들어 실제로 플레이 가능한 게임을 완성했다. 비용은 늘지만 신뢰도가 비약적으로 올라간다는 점이 핵심이다.
이런 변화의 배경에는 모델 속도와 사람의 검토 속도의 격차가 있다. 모델이 코드를 만들어내는 속도는 빠른데, 매번 사람이 결과물을 열어보고 피드백을 주는 워크플로는 사람이 먼저 지친다. 그래서 자율 루프를 안전하게 돌릴 수 있도록 환경 자체를 깎는 일 — 즉 하네스를 짜는 일이 개발자의 핵심 업무가 되어 가고 있다. 과거에는 “직접 코드를 잘 쓰는 사람”이 좋은 개발자였다면, 이제는 “에이전트가 잘 돌아가는 환경을 잘 설계하는 사람”이 그 자리를 대체하고 있다.
하네스를 구성하는 축은 보통 셋으로 나뉜다. 컨텍스트, 도구, 평가다.
컨텍스트는 앞 섹션의 컨텍스트 엔지니어링의 정의를 그대로 가져오면 된다. 도구 측면에서는 모델에게 어떤 기본 도구를 허용하고, 어떤 도구를 별도로 쥐어줄지를 정한다. 기본 웹 검색 같은 도구는 성능이 아쉬워서, Tavily나 Exa Search 같은 외부 검색을 MCP로 붙여 쓰는 경우가 많고, 이때 도구간 기능 오버랩을 줄이지 않으면 모델이 잘못된 도구를 골라 호출하는 일이 잦다. 도구가 내는 에러 메시지는 가능하면 모델 컨텍스트로 그대로 알려줘야 모델이 다음 행동을 잘 결정할 수 있다. 평가는 ‘단지 현재와 다르게만 수정해 개선하는 것’을 거부한다는 원칙이다. 테스트 통과율, 린트, 빌드, 스크린샷 비교처럼 측정 가능한 신호를 통해서만 개선 여부를 판단한다. 그래야 작성-검증-재시도 루프를 자동화할 수 있다.
다만 같은 모델이 같은 세션 안에서 자기 결과물을 평가하면 거의 항상 “잘 짰다”고 평가한다는 문제가 있다. 그래서 보통은 작성자와 검증자를 다른 모델 또는 다른 세션으로 분리하는 패턴을 쓴다. 예를 들어 계획 수립은 Codex가, 1차 코드는 Claude, 1차 검증과 수정은 Codex .. 와 같이 작업단위를 교차로 평가하는 식이다.
하네스를 실제로 어떻게 구성하는지를 보면 패턴이 더 구체적으로 보인다. 가장 자주 보이는 격리 방식은 git worktree다. 메인 브랜치를 직접 건드리지 않고 별도의 워크트리에서 에이전트가 코드를 작성, 테스트하게 한 뒤, 검증을 통과한 결과만 메인으로 머지한다. 자율 실행 중에 사고가 나도 메인이 깨지지 않으니 사람이 끼어들 일이 줄어든다. 두 번째는 실행 계획을 마크다운 파일로 강제로 남기게 하는 방법이다. 코드는 어차피 git에 남지만 “왜 이렇게 짰는지의 계획”은 대화 세션에만 남고, 세션이 끝나면 사라진다. 회고할 수 있도록 계획 자체를 파일로 떨어뜨려 둬야 한다. 세 번째는 훅(hook)이다. 아무리 CLAUDE.md나 AGENTS.md에 “마스터 브랜치 직접 수정 금지” “테스트 없는 커밋 금지”라고 적어둬도, 모델이 무시하는 경우가 있다. 그래서 진짜 지켜져야 하는 규칙은 git pre-commit hook(예: Husky)이나 Claude Code의 hooks처럼 코드 레벨 게이트로 박아둔다. 마스터 브랜치 직접 수정은 hook이 차단하고, 테스트가 없는 변경은 커밋 자체가 거절되며, lint/build/테스트 통과가 커밋 전 강제로 실행된다. AI의 판단이 아니라 프로그래밍 로직으로 통과해야만 다음 단계로 갈 수 있도록 만드는 것이다.
엔지니어링 방식이 변화하면서 로그를 다루는 관점도 함께 바뀌었다. 예전엔 “쓸데없는 print 지워라”가 시니어의 기본 잔소리였지만, 지금은 에이전트가 자기 행동을 되짚어볼 수 있도록 충분한 로그를 남기는 쪽으로 가치가 역전됐다. 로그, 스크린샷, 에러 트레이스가 곧 에이전트의 ‘눈’이고, 같은 작업을 다시 시도할 때 무엇이 잘못됐는지를 모델이 직접 읽고 수정할 수 있게 된다.
하네스의 구성 단위를 코딩 에이전트(Claude Code 기준)에서 자주 쓰이는 네 도구로 매핑하면 이렇다. Commands는 자주 쓰는 프롬프트를 슬래시 커맨드로 모듈화하는 가장 가벼운 단계다. Rules(CLAUDE.md, AGENTS.md 등)는 매 세션에서 모델이 읽는 컨벤션 모음인데, 이건 유도이지 강제가 아니다. Skills는 예시, 템플릿, 스크립트를 패키지로 묶은 워크플로 단위로, 단일 프롬프트로 끝나지 않는 작업을 모듈화한다. 마지막으로 Hook은 코드 레벨에서 강제되는 게이트 역할을 한다. SuperClaude나 oh-my-claude-code 같은 잘 만든 프레임워크를 가져다 쓰는 것도 한 방법이지만, 팀마다 코딩 컨벤션과 워크플로가 달라서 보통은 자기 환경에 맞게 직접 깎아 가는 편이 잘 맞는다. 또한, 모델이 개선되면 기존 하네스의 일부는 필요없어지기도 한다.