sossost.dev

AI Agent Engineering / 1

에이전트는 함수다

AI 하네스 엔지니어링에 대한 단상

6 min read

개발자라면 누구나 하나의 함수가 너무 많은 일을 하기 시작할 때의 불쾌함을 안다. 처음엔 깔끔했던 함수에 조건 분기가 하나 붙고, 사이드이펙트가 하나 끼어들고, 파라미터가 세 개에서 열 개로 불어나는 그 과정. 어느 순간 그 함수는 뭘 하는 건지 설명하기 어려운 존재가 된다. 리턴값도 오락가락한다.

나는 AI 에이전트도 정확히 같은 문제를 겪는다고 생각한다.


에이전트, 그 안에서 벌어지는 일

에이전트에게 프롬프트를 쌓는 행위는 함수에 로직을 추가하는 것과 다르지 않다. “이것도 해줘, 저것도 고려해줘, 그런데 이 경우엔 이렇게 해줘.” 요구사항이 쌓일수록 컨텍스트는 비대해진다. 관심사가 뒤엉킨다. 그리고 결정적으로, 아웃풋의 품질이 흔들리기 시작한다.

하나의 에이전트에게 리서치도 시키고, 요약도 시키고, 톤 변환도 시키고, 판단도 맡기면 — 그 에이전트는 결국 아무것도 잘 못하는 존재가 된다. 마치 500줄짜리 handleEverything() 함수처럼.

함수에서 배우는 것

좋은 함수는 하나의 관심사를 가진다. 인풋을 받거나 받지 않고, 자기 역할에 충실한 아웃풋을 리턴한다. 단일책임원칙(Single Responsibility Principle). 개발자가 코드를 설계할 때 가장 먼저 떠올리는 원칙 중 하나다.

에이전트에도 이 원칙이 그대로 적용된다고 본다.

하나의 서브에이전트에 명확한 프롬프트를 통해 페르소나를 부여하면, 그 에이전트는 자기 도메인 안에서 일관된 결과물을 만들어낸다. 리서치만 하는 에이전트, 요약만 하는 에이전트, 톤을 조율하는 에이전트. 각각이 자기 역할에 집중할 때, 동일한 인풋에 대해 상대적으로 범위가 좁고 일관된 아웃풋을 기대할 수 있다.

이건 이상론이 아니다. 코드에서 이미 증명된 패턴이다.

그러나 에이전트는 함수가 아니다

여기서 한 발 물러서야 할 지점이 있다. 비유는 강력하지만, 비유의 한계를 인정하지 않으면 오히려 함정이 된다.

함수는 deterministic하다. 같은 인풋이면 같은 아웃풋이 보장된다. 하지만 에이전트는 본질적으로 stochastic하다. 아무리 프롬프트를 정교하게 다듬고, 페르소나를 좁히고, temperature를 낮춰도 — 동일한 인풋에 대해 매번 같은 결과가 나온다고 장담할 수 없다. LLM은 확률 분포 위에서 토큰을 샘플링하는 존재이기 때문이다.

그래서 서브에이전트를 잘 쪼개면 일관성이 “높아진다”고는 말할 수 있지만, “보장된다”고 말하기는 어렵다. 함수의 단일책임원칙이 결과의 정확성을 보장하는 것과 달리, 에이전트의 단일책임은 결과의 분산을 줄여줄 뿐이다. 이 차이를 인식하는 것이 중요하다. 에이전트를 함수”처럼” 다루되, 함수”라고” 착각하지 않는 것. 이 미묘한 간극 안에 하네스 엔지니어링의 난이도가 숨어 있다.

메인 에이전트라는 오케스트레이터

그렇다면 이 서브에이전트들을 누가 호출하는가.

도메인별로 함수를 잘 쪼개 놓으면, 결국 그 함수들을 적절한 순서와 조건으로 호출하는 상위 로직이 필요하다. 컨트롤러, 유스케이스, 파사드 — 이름은 다양하지만 역할은 같다. 흐름을 관리하는 존재.

에이전트 시스템에서도 마찬가지다. 서브에이전트들을 세분화해서 구성한 뒤, 이들을 목적에 맞게 조합하고 호출하는 메인 매니징 에이전트가 있어야 한다. 이 메인 에이전트의 역할은 직접 일을 하는 게 아니라, 어떤 서브에이전트에게 어떤 인풋을 넘기고 어떤 순서로 파이프라인을 구성할지를 결정하는 것이다.

함수 호출의 흐름을 설계하듯이, 에이전트 호출의 흐름을 설계하는 것. 이것이 내가 생각하는 하네스 엔지니어링의 핵심이다.

그런데 여기에도 함수와의 결정적 차이가 존재한다. 함수 호출은 개발자가 컴파일 타임에 흐름을 확정한다. 어떤 조건에서 어떤 함수가 불리는지, 코드에 명시적으로 적혀 있다. 하지만 메인 에이전트의 서브에이전트 호출은 런타임에 LLM이 판단한다. 어떤 서브에이전트에게 넘길지, 인풋을 어떻게 가공할지, 이 모든 것이 메인 에이전트의 추론에 의존한다.

이 말은 곧, 오케스트레이터의 판단 품질이 전체 시스템의 상한선이 된다는 뜻이다. 서브에이전트가 아무리 정교하게 설계되어 있어도, 메인 에이전트가 잘못된 서브에이전트를 호출하거나 인풋을 엉뚱하게 전달하면 최종 결과물은 틀어진다. 파사드 패턴의 파사드가 무너지면 내부 모듈이 아무리 완벽해도 의미 없는 것과 같다.

결국 하네스 엔지니어링에서 가장 어려운 일은 서브에이전트를 잘 만드는 것이 아니라, 메인 에이전트의 라우팅 판단을 신뢰할 수 있는 수준으로 끌어올리는 것이다. 그리고 이것은 아직 완전히 풀리지 않은 문제이기도 하다.

울타리를 치는 일

여기까지의 이야기는 에이전트 시스템의 내부 구조에 관한 것이었다. 하지만 한 단계 위로 올라가면, 더 근본적인 질문이 남아 있다. 이 에이전트 시스템 전체가 어디까지 움직일 수 있는가.

하네스(harness)라는 단어에는 고삐, 마구라는 뜻이 있다. 하지만 나는 고삐보다 울타리라는 비유가 더 정확하다고 생각한다. 고삐는 매 순간 방향을 당겨주는 것이고, 울타리는 경계만 쳐두고 그 안에서는 자유롭게 뛰게 하는 것이다. 제어의 방식이 근본적으로 다르다.

고삐식 제어는 결국 매 스텝마다 인간이 개입하는 것이다. 그건 자동화지 자율화가 아니다. 울타리식 제어는 다르다. 프로젝트의 목표와 권한이라는 경계를 설정하고, 그 안에서 메인 에이전트든 서브에이전트든 목표를 향해 어떻게 도달하느냐는 에이전트의 자율에 맡긴다.

이때 울타리의 기준점이 되는 것은 단 하나, 프로젝트의 골(goal)이다. 개선의 영역은 다양할 수 있다. 코드 품질일 수도 있고, UX일 수도 있고, 안정성을 더하는 테스트일 수도 있다. 하지만 이 모든 개선 벡터는 프로젝트의 골에 정렬되어야 한다. 골에 정렬되지 않은 개선은 개선이 아니라 노이즈다.

울타리를 “이것을 하지 마라”로 정의하는 게 아니라 “이 골을 향해 가라”로 정의하는 것. 부정형 제약이 아닌 긍정형 제약. 이것이 울타리 설계의 핵심이고, 나는 이것이 하네스 엔지니어링의 출발점이라고 생각한다.

자율화의 두 축

울타리 안에서 에이전트가 자율적으로 움직이는 방식에는 크게 두 가지 축이 있다고 본다.

첫 번째는 명령 기반 자율화다. 인간이 아이디어를 던지면, 에이전트가 이슈 생성부터 구현, PR까지의 프로세스를 자율적으로 완주한다. 트리거는 인간이 당기지만, 이후의 실행은 에이전트가 알아서 한다. 파이프라인이 명확하기 때문에 울타리도 자연스럽게 정의되고, 결과물의 품질도 예측 가능한 범위 안에 놓인다.

두 번째는 스케줄러 기반 자율화다. 인간의 트리거 없이, 정해진 주기마다 에이전트가 스스로 프로젝트를 점검하고 개선한다. 이 축은 첫 번째보다 도전적이다. “뭘 할지”를 에이전트가 판단해야 하기 때문이다. 골에 정렬된 범위 안에서 어떤 개선이 필요한지를 스스로 탐색하고 실행하는 것. 여기서 울타리의 중요성이 급격히 올라간다. 울타리가 모호하면 에이전트는 의미 없는 변경을 양산하거나, 프로젝트의 방향과 다른 곳으로 드리프트한다.

이 두 축은 대립하는 것이 아니라 보완하는 것이다. 명령 기반으로 큰 방향을 잡고, 스케줄러 기반으로 지속적인 개선을 돌리는 것. 인간이 의도를 주입하는 채널과, 에이전트가 자율적으로 가치를 쌓는 채널이 공존하는 구조다.

물론 이상적인 자율화는 이벤트 드리븐일 수도 있다. 에러 로그, 유저 피드백, 코드 변경 같은 시그널을 에이전트가 감지하고 “지금 개입해야겠다”고 스스로 판단하는 것. 하지만 현실에는 비용이라는 물리적 제약이 있고, 모든 설계는 이상과 현실 사이의 트레이드오프 위에 놓인다. 중요한 것은 자율화의 형태가 아니라, 울타리 안에서 에이전트가 골을 향해 자율적으로 가치를 생산하고 있느냐는 것이다.

결국은 설계의 문제

프롬프트 엔지니어링이라는 말이 있다. 하지만 나는 그 단어가 담는 범위가 점점 좁아지고 있다고 느낀다. 단일 프롬프트를 잘 쓰는 것만으로는 복잡한 목적을 달성하기 어렵다.

에이전트를 함수처럼 바라보고, 관심사를 분리하고, 파이프라인을 설계하고, 흐름을 제어하는 것. 그리고 그 모든 것을 감싸는 울타리를 — 프로젝트의 골에 정렬된 경계를 — 설계하는 것. 이건 프롬프트를 “잘 쓰는” 문제가 아니라 시스템을 “잘 설계하는” 문제다. 그리고 그 설계 감각은 — 우리가 이미 코드를 짜면서 수없이 훈련해 온 것이기도 하다.

AI 하네스 엔지니어링. 에이전트를 다루는 기술이라기보다, 에이전트가 자율적으로 가치를 만들어낼 수 있는 구조를 설계하는 기술. 나는 그렇게 이해하고 있다.