한 명이던 AI 에이전트를 넷으로 나눈 이유
이 글은 에이전트를 여러 개 만드는 방법이 아니라, 일하던 방향을 세로에서 가로로 틀어보고 무엇이 달라졌는지에 관한 기록이다.
컨테이너 격리를 풀고 Hermes로 옮긴 뒤 한 달 반 정도를 한 명의 에이전트로 썼다. 아침 뉴스 브리핑을 돌리고, 회의 녹음을 회의록으로 만들고, 블로그 글을 쓰고, 사내 위키를 정리하고, Confluence에 보고서를 올렸다. 잘 돌았다. 문제는 잘 돈다는 감각과 별개로 조금씩 새고 있었다는 것이다.
Hermes가 처음이라면 (이미 아는 분은 건너뛰어도 된다)
Hermes는 터미널, 데스크톱 앱, 메신저에서 같은 코어로 도는 개인 AI 에이전트다. 이 글에서 중요한 건 세 가지다.
- SOUL.md: 에이전트의 정체성. 사람이 쓰고 에이전트는 못 고친다.
- USER.md / MEMORY.md: 에이전트가 스스로 쓰는 메모리. 전자는 “사용자가 누구인가”, 후자는 “내가 배운 것”이다. 매 턴 시스템 프롬프트에 주입된다.
- 프로파일:
~/.hermes하나가 프로파일 하나다. 프로파일마다 설정, 모델, 메모리, 세션, 스킬, 게이트웨이가 완전히 분리된다.
그동안은 폴더 하나에 붙어 있었다
지금까지 일하던 방식은 단순했다. 블로그를 고칠 때는 블로그 저장소에서, 위키를 정리할 때는 위키 저장소에서. 프로젝트 폴더가 곧 작업 단위였고, 에이전트는 그 안에 계속 머물렀다. 나누는 건 세션뿐이었다. 대화가 길어지면 새 세션을 열고, 맥락이 필요하면 다시 설명했다.
세로로 파는 방식이다. 한 도메인 안에서 깊이 들어가고, 다른 도메인으로 갈 때는 통째로 옮겨간다.
이게 나쁘지 않았다. 폴더의 AGENTS.md가 그 도메인 규칙을 갖고 있으니 에이전트는 들어가는 순간 계약을 받았다. 문제는 에이전트 쪽이었다. 도메인은 갈아타는데 에이전트는 하나라서, 모든 도메인의 규칙이 한 명에게 쌓였다.
메모리 한도가 찼다
재편 직전 상태를 재보니 에이전트가 사용자에 대해 기억하는 USER.md가 1,334자, 한도 1,375자의 97%까지 차 있었다.
포화 자체는 관리하면 될 일이다. 진짜 문제는 그 안에 들어 있는 내용이었다. 두 규칙이 나란히 앉아 있었다. 블로그에 쓸 때는 회사 코드네임과 실명을 익명화한다. 사내 위키에 쓸 때는 같은 식별자를 보존한다.
정반대다. 그리고 매 턴 둘 다 주입된다. 어느 쪽을 적용할지는 모델의 주의력에 맡겨져 있었다. 특수문자 규칙도 같은 모양이었다. 블로그는 화살표와 em dash를 금지하고 커밋 훅으로 막는데, 위키는 의미 전달을 위해 자유롭게 쓴다. 같은 문장을 어디에 쓰느냐에 따라 반대가 된다.
한도가 남아 있었어도 이건 안 풀렸다. 규칙을 더 정교하게 쓰는 문제가 아니라, 한 명이 상충하는 계약 두 개를 동시에 들고 있는 게 문제였기 때문이다.
여기서 방향을 틀기로 했다. 도메인을 따라 세로로 파는 대신, 역할별로 에이전트를 나누고 각자가 도메인을 넘나들게 하는 것. 실제 조직이 그렇게 돈다. 기획자가 프로젝트마다 따로 있지 않고, 한 사람이 여러 프로젝트를 오간다.
동시에 작업 방식도 바꾸려던 참이었다. 그전까지 구현과 검증은 터미널에서 codex나 claude를 직접 띄워서 했다. 이걸 Hermes 안으로 가져오고, 역할마다 다른 모델을 쓰고 싶었다. 설계는 강한 모델로, 구현은 싸고 빠른 모델로.
방향을 정하고 에이전트에게 검토를 시켰다. 그리고 반대당했다.
나누자고 했더니 반대당했다
첫 답변에서 에이전트는 역할별 분리를 권하지 않았다. 근거는 과거 사용 기록이었다.
- 세션 305건 중 195건(62.7%)이 크론이고, 대화형은 116건뿐이다
- 역할 형태 스킬이 전부 안 쓰였다.
requesting-code-review0회,systematic-debugging0회,test-driven-development0회 - 반면 도메인 형태 스킬은 활발하다.
hermes-agent49회,scheduled-web-briefings45회 - 협업 보드(
kanban.db)는 전 테이블 0행이다
그러니 도메인별로 나누라는 결론이었다. 두 번째에도 같은 논리를 반복했다. 세 번째에 잘랐다.
지금까지 써왔던 세션 수와 스킬 수에 의존하지 말고, 앞으로는 역할별 분리로 하려고 한다.
그제야 방향을 틀었다. 여기서 짚어야 할 건 데이터가 틀렸다는 게 아니다. 저 숫자는 전부 맞다. 틀린 건 해석이었다.
역할 스킬 사용량 0은 “안 맞는다”가 아니라 “아직 안 해봤다”이다. 보드가 비어 있는 건 “쓸모없다”가 아니라 “안 썼다”이다. 텔레메트리는 무슨 일이 있었는지 답하지, 앞으로 무엇을 해야 하는지는 답하지 못한다. 이걸 근거로 사용자의 의도적 변경을 말리는 건 범주 오류다.
그리고 이게 정확히 맥락 과적재의 다른 얼굴이다. 한 에이전트에 쌓인 과거가 새 방향을 막아섰다.
넷을 만들면 여덟이 되는 문제
넷으로 갈랐다.
| 프로파일 | 역할 | 모델 |
|---|---|---|
| default (PM) | 사용자와의 유일한 창구, 분해와 배분 | claude-opus-5 |
| archie | 설계, spec과 plan, 리스크 판단 | claude-opus-5 |
| build | 구현과 검증 | glm-5.3 |
| scribe | 기록과 발행 | claude-opus-5 |
갈라놓고 보니 걸리는 게 있었다. 익명화 규칙은 역할이 아니라 대상 저장소에 붙는다. scribe가 위키에 쓸 때와 블로그에 쓸 때 규칙이 반대다. 그럼 역할 넷에 도메인 둘을 곱해 여덟을 만들어야 하나. 세로로 파던 걸 가로로 바꿨더니 이번엔 격자가 생긴 셈이다.
답은 둘을 다른 층에 두는 것이었다. 역할은 프로파일이 나르고, 도메인은 워크스페이스가 나른다. 프로파일에는 모델과 정체성과 메모리가 들어가고, 저장소에는 그 도메인의 AGENTS.md 계약이 들어간다.
이게 성립하는 건 디스패처가 워커를 띄울 때 작업 디렉터리를 태스크 워크스페이스로 고정하기 때문이다. 소스 주석이 그 의도를 직접 말한다.
# Pin TERMINAL_CWD to the task's workspace so the worker's file tools and
# context-file loader anchor on the workspace, not whatever cwd the
# dispatching gateway happened to export.
# ... (#34619 — workers loaded the dispatching gateway's AGENTS.md instead
# of the task's).이슈 번호가 붙어 있다. 워커가 자기 워크스페이스가 아니라 게이트웨이의 AGENTS.md를 읽던 버그를 고친 흔적이다. 같은 실수를 먼저 한 사람이 있었다는 뜻이기도 하다.
그래서 scribe 하나가 위키 태스크를 받으면 실명 보존 계약을, 블로그 태스크를 받으면 익명화와 타이포그래피 게이트를 자동으로 받는다. 프로파일을 늘리지 않아도 된다. 전제가 하나 있다. 그 저장소에 계약 파일이 실제로 있어야 한다. 없으면 분리의 절반이 조용히 아무것도 안 한다.
위임은 규칙 하나로 돈다. 보드에 태스크를 만들고 담당자 이름을 적으면, 디스패처가 그 이름을 프로파일로 해석해서 프로세스를 띄운다. 담당자가 곧 프로파일이고, 프로파일이 곧 모델이다.
써보니 워커가 뜨고 끝나는 데 짧게는 10초, 길면 50초가 든다. 짧은 질문을 태스크로 만들면 그 자리에서 답하는 것보다 느리다. 그래서 십 분 안에 끝날 일은 PM이 직접 하고, 여러 단계로 나뉘거나 다른 모델이 나은 일만 넘기기로 했다.
한 가지 함정도 확인했다. Hermes에는 하위 에이전트를 부르는 delegate_task가 따로 있는데, 여기에는 호출별 모델 지정이 없다. 전역 설정 하나를 쓴다. 역할별로 모델을 다르게 가져가려면 프로파일이 필요하고, 위임 도구만으로는 안 된다.
첫 태스크가 다섯 번 죽었다
구조를 다 만들고 실제 태스크를 던졌다. 위키의 계약 문서 아홉 개가 서로 모순되는지 전면 검토하라는 것이었다. 문서 대조에 코드 격차 분석, git 이력 검증까지 한 태스크에 넣었다.
워커가 150턴 상한에 걸려 죽었다. 요약도 못 남기고 죽었다.
I reached the maximum iterations (150) but couldn't summarize.
Error: The read operation timed out그리고 자동 재시도가 돌아 다섯 번 반복됐다. 태스크에 런타임 상한을 안 걸어둔 탓에 시간 제한도 안 걸렸다.
분해는 PM의 일인데 분해하지 않고 통째로 던진 결과다. 조직으로 치면 요구사항 정리 없이 “이거 다 봐줘” 하고 넘긴 것과 같다. 사람이면 되물었을 텐데 워커는 되묻지 않고 150턴을 태웠다.
되묻지 않는다는 게 핵심이다. 워커에게는 사람에게 물을 수단이 있다. 막히면 태스크를 보류 상태로 돌리고 보드에 이유를 남기는 것이다. 그런데 그건 무엇이 부족한지 알아야 쓸 수 있다. 요구가 너무 넓으면 워커는 자기가 막혔다는 것조차 모른다. 문서를 하나 더 읽으면 끝날 것 같은 상태가 150번 이어진다.
그래서 완료 조건을 먼저 쓰는 걸 계약에 박았다. 무엇이 되면 끝인지 없이 할당하지 않는다. 이 한 줄이 없으면 워커는 끝을 스스로 정해야 하고, 그건 워커가 할 수 없는 판단이다.
하루를 그대로 굴려봤다
다음 날 실제 업무를 그대로 태워봤다. 교육 자료 정리, 위키 문서 승급, 장애 대응 기록.
모델 분리는 의도대로 갈렸다. build 세션 63회에 opus가 한 번도 섞이지 않았다. 프로파일로 나누니 실제로 나뉜 것이다.
그런데 넷이 다 돈 건 아니었다. archie는 설계를 맡겨본 적이 없고, build는 짧은 개발 몇 건만 나눴다. 실제로 값을 한 건 PM과 scribe 조합 하나뿐이었다. 넷으로 나누는 설계와 넷이 실제로 도는 운영은 다른 문제였다.
돈 하나는 제대로 돌았다. 위키 문서를 만들라고 태스크를 던졌더니 워커 로그에 이런 순서가 남았다.
read wiki-artifact-schema.md
read frontmatter-schema.md
$ git pull --rebase --autostash
write inbox/meetings/2026-08-31-...내가 시킨 건 “문서를 만들어라”였다. 스키마 파일을 찾아 읽고 다른 PC 변경을 먼저 당겨오는 건 아무도 지시하지 않았다. 워크스페이스의 AGENTS.md에 그렇게 적혀 있어서 그대로 한 것이다. 앞에서 말한 두 층 분리가 문장이 아니라 로그로 확인된 순간이었다.
다섯 번 죽었던 그 위키 작업도 이번엔 한 번에 끝났다. 달라진 건 모델도 프롬프트도 아니고 분해뿐이다.
대신 새로운 불편이 생겼다. 태스크를 던지고 나면 지금 무엇을 하고 있는지 알 수가 없다. 워커는 게이트웨이와 무관한 별도 프로세스로 뜨고, 그 출력은 로그 파일로 간다. 대화창에는 아무것도 안 나온다. 진행을 보려면 데스크톱 앱을 나가 브라우저로 대시보드를 열어야 했다. 앱 안에서 대화하다가 앱 밖으로 나가는 셈이다.
그래서 워커가 자기 채널에 한 줄씩 남기게 했다. 도구 호출을 중계하지 말고 사람이 읽어서 의미 있는 문장만 쓰라고 계약에 박았다. “파일을 읽었다”는 보고가 아니라 소음이다.
여기서 한 번 더 걸렸다. 산출물 경로를 알려줘도 열려면 다시 찾아가야 하길래 문서를 바로 여는 링크를 붙이게 했는데, 정작 알림에 안 보였다. 소스를 열어보니 완료 알림은 요약의 첫 줄만, 그것도 200자까지만 싣는다. 링크를 요약 끝에 붙였으니 실릴 자리가 없었다. 링크를 첫 줄로 옮기고 나서야 보였다.
나누면 각자 잘 돈다. 대신 전체가 지금 어디쯤인지는 따로 만들어야 한다.
남은 것
지금은 짧은 개발이면 PM을 안 거치고 build와 직접 대화한다. 구조를 만들어놓고 우회로를 쓰는 셈인데, 빠르니까 그렇게 된다.
다른 도구에서 본 방식이 자꾸 생각난다. Orca의 orchestration은 코디네이터가 살아서 태스크 그래프를 소유하고, 워커의 완료나 에스컬레이션을 기다린다. 중간에 결정 게이트를 걸 수 있고, 워커가 막히면 코디네이터가 그 자리에서 받는다. Hermes의 kanban은 반대다. PM이 태스크를 만들고 손을 뗀다. 디스패처가 준비된 것을 띄우고 완료는 알림으로 돌아온다. 기다리지 않으니 그동안 토큰을 태우지 않는다. 대신 워커가 막히면 사람에게 올라온다.
싼 쪽은 이미 Hermes다. 그러니 가져올 게 있다면 비용이 아니라 감독 방식이다. 코디네이터가 계속 붙어 있지는 않되 워커가 막힌 순간에는 되받는 구조. 그게 되면 언제 PM을 거치고 언제 직접 갈지를 매번 판단하지 않아도 된다. 아직 안 해봤다. 지금은 직접 가는 게 빠르다는 것만 안다.
USER.md는 프로파일마다 독립으로 뒀다. 심볼릭 링크로 공유할 수도 있었지만 하지 않았다. 각 에이전트가 겪은 나는 서로 다를 수 있고, 하나의 불변한 인물일 필요가 없다고 봤다. 대신 대가가 있다. 한쪽에서 교정한 게 다른 셋에 전파되지 않는다. 같은 지적을 네 번 해야 할 수 있다. 그래서 넷이 공유해야 하는 협업 계약은 에이전트가 못 고치는 SOUL.md에 두고, 관찰은 각자 쌓게 했다. 재편 후 각 프로파일의 USER.md는 한도의 13% 내외다. 97%에서 내려왔다.
역할을 어떻게 갈라야 맞는지는 아직 모른다. 설계와 문서화를 나눌지, 구현과 검증을 나눌지도 확신이 없다. 하루 굴려본 결과가 그걸 보여준다. 넷을 만들었는데 실제로 값을 한 조합은 하나였고, 나머지 둘은 아직 자리를 못 찾았다.
그래도 세로로 파던 걸 가로로 바꾼 건 되돌리고 싶지 않다. 도메인을 옮길 때마다 에이전트가 통째로 옮겨가던 방식에서, 역할이 도메인을 넘나드는 방식으로 바뀌었다. 계약은 저장소에 두고 사람만 오가게 하는 것. 실제 조직이 그렇게 도는 이유를 이제 조금 알 것 같다.