OpenAI의 ‘하네스 엔지니어링’ 글을 바탕으로, AI 에이전트를 통제하고 대규모 코드베이스의 품질과 유지보수성을 높이기 위한 도구·관행·제약의 의미를 살펴본다.
URL: https://martinfowler.com/articles/exploring-gen-ai/harness-engineering.html
Title: Harness Engineering
OpenAI의 최근 글 ‘Harness engineering’을 읽어보는 것은 매우 흥미로웠다. 이 글은 한 팀이 “사람이 직접 타이핑한 코드는 전혀 없이(no manually typed code at all)”라는 강제 조건을 걸고, AI 에이전트로 대규모 애플리케이션을 유지보수하기 위한 하네스를 구축한 과정을 설명한다. 5개월 후 그들은 실제 제품을 만들었고, 현재 코드가 100만 라인을 넘어섰다.
그 글의 제목은 “Harness engineering: leveraging Codex in an agent-first world”인데, 본문에서는 “harness(하네스)”라는 단어가 한 번만 등장한다. 아마 Mitchell Hashimoto의 최근 블로그 글에서 영감을 받아 나중에 붙인 용어일 수도 있다. 어쨌든 나는 AI 에이전트를 통제하는 데 사용할 수 있는 도구와 관행을 묘사하는 단어로서 “하네스”가 마음에 든다.
OpenAI 팀이 말하는 하네스 구성요소는 3개 범주에 걸쳐 결정론적(deterministic) 접근과 LLM 기반 접근을 섞어 쓴다(분류는 내 해석에 따른 것이다):
또한 그들은 이것이 매우 반복적(iterative)인 과정임을 강조한다:
“에이전트가 고전하면, 우리는 그것을 신호로 취급한다. 무엇이 빠졌는지—도구, 가드레일, 문서—를 찾아내고, 언제나 Codex 자체가 수정사항을 작성하도록 하여 이를 저장소에 다시 반영한다.”
설명된 모든 조치는 장기적인 내부 품질과 유지보수성을 높이는 데 초점이 맞춰져 있다. 내가 그 글에서 놓치고 있다고 느낀 부분은 기능성과 동작(behaviour)에 대한 검증이다.
그 공백은 일단 제쳐두고, 그리고 OpenAI가 이것이 성공적이었다고 표현한 내용을 신뢰할 수 있다고 가정하자(저자와 팀에 대한 존중과 별개로, OpenAI는 우리가 AI로 유지보수 가능한 코드를 믿게 만드는 데 이해관계가 있다). 아래는 그 글에 실제로 담긴 내용에 대해 내가 든 생각들이다.
대부분의 조직은 주된 기술 스택이 두세 개뿐이다. 모든 애플리케이션이 저마다 완전히 다른 ‘눈송이(snowflake)’는 아니다. 이 글을 읽으며, 팀들이 시작할 때 흔한 애플리케이션 토폴로지(topology)에 맞춘 하네스 세트 중 하나를 선택하는 미래를 상상하게 됐다. 이는 팀들이 ‘골든 패스(golden path)’ 위에서 새로운 서비스를 인스턴스화하도록 돕는 오늘날의 서비스 템플릿을 떠올리게 한다. 커스텀 린터, 구조적 테스트, 기본 컨텍스트 및 지식 문서화, 추가 컨텍스트 제공자까지 포함한 하네스가 새로운 서비스 템플릿이 될까? 팀들은 이를 출발점으로 삼고, 시간이 지나며 각 애플리케이션의 특수성에 맞게 하네스를 다듬어 갈까?
서비스 템플릿의 경우, 팀들은 경험이 쌓이면 다시 템플릿에 기여하지만, 다른 팀들은 업데이트를 통합하기가 종종 어렵다. 하네스에서도 비슷한 포킹(forking)과 동기화(synchronization) 문제가 나타날까?
이 글은 또한 내 예전 가설 몇 가지를 다시 떠올리게 했다.
초기의, 그리고 지금도 이어지는 AI 코딩 과대광고(hype) 상당수는 LLM이 타깃 런타임에 대해 무한한 유연성을 제공할 것이라고 가정한다. 어떤 언어든, 어떤 패턴이든, 제약 없이 생성하면 LLM이 알아서 해낼 것이라는 식이다. 하지만 우리가 신뢰할 수 있는, 유지보수 가능한 대규모 AI 생성 코드를 원한다면 뭔가는 양보해야 한다.
설명된 하네스는 신뢰와 신뢰성을 높이기 위해 해결 공간(solution space)을 제약해야 했음을 시사한다. 특정 아키텍처 패턴, 강제되는 경계(boundary), 표준화된 구조. 즉 “무엇이든 생성”하는 유연성 일부를 포기하고, 프롬프트/규칙/기술적으로 구체적인 하네스를 받아들이는 것이다.
코딩이 코드 타이핑이 아니라 생성의 조향(steering)이 되어갈수록, AI는 우리를 더 적은 수의 기술 스택으로 밀어붙일지도 모른다. 프레임워크와 SDK의 사용성(usability)은 여전히 중요하다. 무엇이 인간에게 좋은가가 AI에게도 좋다는 사실을 우리는 반복해서 보고 있다. 하지만 그 정도의 디테일에서는 개발자 취향이 덜 중요해질 것이다. 인터페이스의 사소한 비효율이나 특이점(idiosyncracies)은 우리가 직접 상대하지 않으니 덜 짜증날 수 있다. 우리는 좋은 하네스가 이미 उपलब्ध한 스택을 선택하고, “AI 친화성(AI-friendliness)”을 우선시할지도 모른다.
이는 기술 스택뿐 아니라 코드베이스 구조와 토폴로지에도 적용될 수 있다. 하네싱(harnessing)하기 쉬워서 AI로 유지보수하기 쉬운 구조를 기본값으로 삼을지도 모른다. OpenAI 팀은 아키텍처의 경직성(rigidity)과 강제 규칙(enforcement rules)을 이야기한다. 내가 보기엔 주요 초점은 데이터 구조를 안정적으로 유지하는 것과 모듈 경계를 정의하고 강제하는 것이다. 합리적으로 들린다. 하지만 구체적인 예시가 없어서, 그들의 하네스에서 “우리는 경계에서 Codex가 데이터 형태(data shapes)를 파싱하도록 요구한다”가 실제로 어떤 모습인지 아직도 상상하기 어렵다.
하지만 코드베이스 설계 패턴을 하네스로 널리 다루는 방법을 우리가 알아내게 된다면, 많은 AI 열성팬들이 기대하듯 자연어 자체가 아니라 이런 토폴로지가 새로운 추상화 계층이 될까?
좋은 하네싱 기법을 개발해 AI 자율성을 9까지 끌어올리고 결과에 대한 자신감을 높일 수 있다고 하자. 그렇다면 어떤 기법은 기존 애플리케이션에도 적용할 수 있고, 어떤 것은 처음부터 하네스를 염두에 두고 만든 애플리케이션에서만 가능할까?
오래된 코드베이스에서는 하네스를 레트로핏(retrofit)하는 노력이 그만한 가치가 있는지 따져야 한다. AI가 이를 더 빠르게 해줄 수는 있지만, 그런 애플리케이션은 대개 표준화가 거의 없고 엔트로피가 가득해서, 애초에 가치가 없을 수도 있다. 한 번도 정적 코드 분석 도구를 돌린 적 없는 코드베이스에 도구를 적용한 뒤 경고(alert)에 파묻히는 상황이 떠오른다.
이 팀이 5개월 동안 하네스를 작업했다는 사실은, 이것이 빠른 결과를 위해 곧바로 뛰어들 수 있는 일이 아니라는 점을 보여준다. 하지만 지금 여러분의 하네스가 무엇인지 돌아볼 가치는 있다. 프리커밋 훅(pre-commit hook)이 있는가? 그 안에는 무엇이 들어 있는가? 커스텀 린터에 대한 아이디어가 있는가? 코드베이스에 어떤 아키텍처 제약을 부과하고 싶은가? ArchUnit 같은 구조적 테스트 프레임워크를 실험해 본 적이 있는가?
놀랍지 않게도, 그들이 설명하는 것은 단지 Markdown 규칙 파일 몇 개를 생성하고 유지하는 것보다 훨씬 더 많은 작업처럼 들린다. 그들은 하네스의 결정론적 부분을 위해 방대한 툴링을 구축했다. 컨텍스트 엔지니어링 또한 지식 베이스를 큐레이션하는 것뿐 아니라 상당한 설계 작업을 포함했다 — 코드 설계 자체가 컨텍스트의 거대한 일부이기 때문이다.
OpenAI 팀은 이렇게 말한다:
“현재 우리의 가장 어려운 도전은 환경(environments), 피드백 루프(feedback loops), 그리고 제어 시스템(control systems)을 설계하는 데 있다.”
이는 Chad Fowler의 최근 글 ‘Relocating Rigor’를 떠올리게 했다. 유지보수성 문제를 “더 좋은 모델”이 마법처럼 해결해 주길 바라는 대신, 그 엄격함(rigor)이 어디로 이동할 수 있는지에 대한 구체적인 아이디어와 경험을 듣는 것은 신선하다.
그리고 마지막으로, 드물게도 이 분야에서 마음에 드는 용어가 하나 생겼다. 다만 나온 지 2주밖에 안 됐으니, 누군가 원프롬프트(one-prompt) LLM 기반 코드 리뷰 에이전트를 하네스라고 부르기 전까지는… 비유적으로 숨을 조금만 더 참고 있어도 될 것 같다.