자가 리팩토링 AI 에이전트 구축 방법: Hermes의 "메모리 가비지 컬렉터" 내부 구조
요약
자율형 AI 에이전트의 메모리 비대화 문제를 해결하기 위해 Hermes 프레임워크가 도입한 'Hermes Curator'의 구조를 설명합니다. 의미론적 가비지 컬렉션 개념을 통해 중복된 지식을 통합하고 구조화된 지식으로 변환하는 아키텍처를 다룹니다.
핵심 포인트
- 메모리 비대화로 인한 지연 시간 및 환각 문제 해결
- 의미론적 의미를 분석하는 지능형 가비지 컬렉션 도입
- 중복된 기술을 하나의 '엄브렐러 스킬'로 통합 및 아카이브
- 2단계 전략을 통한 효율적인 메모리 관리 및 토큰 비용 절감
만약 당신이 자율형 AI 에이전트(autonomous AI agent)를 구축해 본 적이 있다면, 아마도 "메모리 비대화 (memory bloat)" 문제에 직면했을 것입니다.
처음에는 에이전트가 빠르고, 예리하며, 매우 효율적입니다. 작업을 해결하고, 코드를 작성하며, 새로운 기술을 저장합니다. 하지만 세션이 쌓이면서 무언가 고장 나기 시작합니다. 에이전트의 메모리가 수백 개의 매우 구체적이거나, 중복되거나, 오래된 지침들로 뒤섞이게 됩니다. 갑자기 검색 지연 시간(retrieval latency)이 급증하고, 토큰 비용이 치솟으며, 에이전트는 인지적 소음(cognitive noise)으로 인해 환각(hallucinating)을 일으키거나 작업에 맞지 않는 잘못된 "기술 (skill)"을 검색하는 등의 문제를 겪기 시작합니다.
대부분의 개발자들은 단순한 벡터 데이터베이스(vector database) 검색이나 기본적인 LRU (Least Recently Used) 캐시 제거 방식으로 이를 해결하려 합니다. 하지만 이것들은 투박한 도구입니다. 이 방식들은 버려지는 정보의 "의미 (meaning)"를 이해하지 못합니다.
Hermes 에이전트 프레임워크(Hermes Agent framework)에서 우리는 시스템 엔지니어링의 고전적인 개념인 **가비지 컬렉션 (Garbage Collection)**을 빌려와 이 문제를 해결했습니다.
우리는 Hermes Curator (agent/curator.py)를 구축했습니다. 이는 에이전트의 장기 기술 라이브러리를 지속적으로 검토, 통합 및 아카이브하는 지능적이고 상태를 유지하는(stateful) 백그라운드 데몬(daemon)입니다. 이것은 에이전트의 "집행 기능 (executive function)"으로서, 지저분한 에피소드 경험(episodic experiences)을 깨끗하고 구조화된 의미론적 지식(semantic knowledge)으로 변환합니다.
다음은 이 자가 리팩토링 메모리 시스템 뒤에 숨겨진 아키텍처, 이론 및 코드에 대한 심층적인 분석입니다.
(여기서 설명하는 개념과 코드는 저의 전자책 Hermes Agent, The Self-Evolving AI Workforce에서 발췌되었습니다.)
핵심 개념: 의도를 가진 가비지 컬렉터
시스템 프로그래밍에서 가비지 컬렉터 (GC)는 더 이상 사용되지 않는 객체가 차지하는 공간을 회수함으로써 메모리를 자동으로 관리합니다. Hermes Curator는 에이전트의 기술 라이브러리에 대해 정확히 동일한 작업을 수행하지만, 결정적인 차이점이 있습니다. 단순히 메모리 주소를 보는 것이 아니라, **의미론적 의미 (semantic meaning)**를 본다는 점입니다.
만약 에이전트가 CSV 파일을 파싱하기 위한 스크립트를 10가지의 서로 다른 변형으로 생성한다면, 전통적인 가비지 컬렉터 (GC)는 도움을 줄 수 없습니다. 데이터베이스 관점에서 보면, 이것들은 10개의 고유하고 유효한 파일입니다. 하지만 Hermes Curator에게 이것은 엔트로피가 높은 중복 (high-entropy redundancy)입니다.
Curator의 역할은 이러한 중복된 기술들을 식별하고, 이를 명확한 하위 섹션과 템플릿을 가진 하나의 포괄적인 "엄브렐러 스킬 (umbrella skill)"로 통합하며, 쓸모없어진 원본들을 아카이브(archive)하는 것입니다.
API 토큰을 과도하게 소모하지 않으면서 이를 효율적으로 수행하기 위해, Curator는 압축형 세대별 GC (compacting generational GC)와 수동 메모리 조각 모음 (manual memory defragmenter) 사이의 차이점을 모방한 **2단계 전략 (two-tiered strategy)**을 사용합니다:
+-------------------------------------------------------------+
| The Hermes Curator |
+-------------------------------------------------------------+
...
1. 자동화된 휴리스틱 기반 패스 (The "Generational GC")
이 단계는 Python으로 구현된 순수 비-LLM (non-LLM) 단계입니다. 이는 타임스탬프와 상태 머신 (state machines)에 기반한 결정론적 규칙에 따라 실행됩니다. 세대별 GC가 생존 시간에 따라 객체를 "young" 세대에서 "old" 세대로 이동시키는 것과 매우 유사하게, 이 패스는 사용 이력에 따라 기술을 active에서 stale로, 그리고 최종적으로 archived로 자동 전환합니다. 이는 비용이 저렴하고 실행 빈도가 높으며, 값비싼 LLM 호출을 유발하지 않고도 일상적인 정리 작업의 대부분을 처리합니다.
2. LLM 기반의 의도적 패스 (The "Defragmenter")
이 단계는 정교하고 자원 집약적인 단계입니다. 이 단계는 격리된 포크(forked) AI 에이전트를 생성하여 활성 기술의 의미론적 내용 (semantic content)을 분석합니다. 단순히 중복된 파일을 찾는 대신, 지식 베이스를 계층적이고 발견 가능성이 높은 디렉토리로 재구조화하는 "엄브렐러 구축 (umbrella-building)"을 수행합니다. 이는 코드베이스 리팩토링 (codebase refactoring) 도구처럼 작동하여, 향후 검색을 위해 에이전트의 지식 아키텍처를 지속적으로 최적화합니다.
의미론적 메모리 큐레이션의 이론적 토대
Curator의 아키텍처는 컴퓨터 과학, 정보 이론(Information Theory), 그리고 인지 심리학(Cognitive Psychology)에서 유래한 네 가지 핵심 원칙을 기반으로 구축되었습니다.
1. 지역성의 원리(Principle of Locality)와 탐색 비용
하드웨어 설계에서 지역성의 원리(Principle of Locality)는 시스템이 특정 시점에 저장 공간의 상대적으로 작은 부분에만 접근하는 경향이 있다는 것을 의미합니다. 캐시(Cache)가 작동하는 이유는 바로 이 원리를 활용하기 때문입니다.
에이전트의 기술 라이브러리(Skill Library)는 본질적으로 학습된 행동들의 캐시입니다. 만약 이 캐시가 너무 커지고 지나치게 구체적인 평면적 파일(Flat files)들로 가득 차게 되면, 토큰 소비와 인지 부하(Cognitive load) 측면 모두에서 이를 탐색하는 비용이 기하급수적으로 증가합니다.
Curator는 **Umbrella Skills(포괄적 기술)**를 구축함으로써 이 문제를 해결합니다. Umbrella skill은 캐시 라인(Cache line) 역할을 합니다. 에이전트의 검색 시스템은 수백 개의 좁은 기술들을 일일이 스캔하는 대신, 올바른 umbrella skill을 찾기만 하면 됩니다. 그러면 해당 기술이 특정 하위 파일, 템플릿 또는 스크립트를 가리키게 됩니다. 이는 평면적이고 지연 시간이 높은(High-latency) 검색 공간을 계층적이고 지연 시간이 낮은(Low-latency) 공간으로 변환합니다.
2. 정보 엔트로피(Information Entropy)와 콜모고로프 복잡도(Kolmogorov Complexity)
정보 이론(Information Theory)의 관점에서 볼 때, 중복되고 좁은 기술들로 구성된 기술 라이브러리는 높은 **중복성(Redundancy)**을 가집니다. 이러한 중복성은 라이브러리의 "엔트로피(Entropy)"를 높여, 검색 알고리즘이 관련 정보를 분리해내는 것을 더 어렵게 만듭니다.
Curator는 기술 라이브러리의 **콜모고로프 복잡도(Kolmogorov Complexity)**를 최소화합니다. 간단히 말해, 에이전트가 축적한 모든 구체적인 지식을 완전히 설명할 수 있는 가장 짧고 우아한 "프로그램"(즉, umbrella skills의 집합)을 찾아내는 것입니다.
3. 백그라운드 인덱서(Background Indexer) 패턴을 갖춘 저장소
데이터 엔지니어링(Data Engineering)에서 백그라운드 인덱서(Background indexer)는 데이터 무결성을 검증하고, 물리적 데이터 레이아웃을 최적화하며, 쿼리 인덱스(Query indexes)를 업데이트하기 위해 비동기적으로 실행됩니다. Curator는 정확히 이 패턴을 구현합니다:
- 데이터 무결성 (Data Integrity): 스킬 상태(활성(active), 오래된(stale), 보관됨(archived))가 실제 사용량과 일치하도록 보장합니다.
- 레이아웃 최적화 (Layout Optimization): 관련 파일들을 병합함으로써 의미론적인
VACUUM및REINDEX를 실행합니다. - 감사 추적 (Audit Trail): 상세한 실행 보고서(
run.json및REPORT.md)를 출력하여, 자율 에이전트(autonomous agent)가 수행한 모든 자가 리팩토링(self-refactoring) 단계를 인간 개발자가 감사할 수 있도록 보장합니다.
4. Fork-Join 병행성 (Concurrency) 및 상태 격리 (State Isolation)
에이전트가 사용자와 활발하게 대화하는 동안, 에이전트 자신의 코드를 평가하고 수정하기 위해 LLM을 실행하는 것은 매우 위험합니다. 공유된 상태(shared state)는 경쟁 상태(race conditions), 파일 손상 또는 의도치 않은 도구 실행(tool executions)으로 이어질 수 있습니다.
이를 방지하기 위해, Curator는 **Fork-Join 병행성 모델 (Fork-Join concurrency model)**을 사용합니다. 이는 백그라운드 데몬 스레드(background daemon thread)에서 독립적이고 샌드박스화된 AIAgent를 생성합니다. 이 자식 에이전트는 자신만의 격리된 세션 기록(session history)을 가지며, 사용자의 활성 대화에 접근할 수 없고, 표준 출력(standard outputs)이 리다이렉션됩니다. 만약 백그라운드 Curator가 충돌하더라도, 메인 사용자 세션은 완전히 영향을 받지 않은 상태로 유지됩니다.
심층 분석: 휴리스틱 라이프사이클 매니저 (Heuristic Lifecycle Manager)
첫 번째 계층인 결정론적 상태 머신(deterministic state machine)이 agent/curator.py에서 어떻게 구현되었는지 살펴보겠습니다. 이 함수는 시간(time)을 기반으로 스킬의 라이프사이클을 관리하여, 오래된 데이터(cold data)에 API 토큰을 낭비하지 않도록 보장합니다.
# agent/curator.py
from datetime import datetime, timezone, timedelta
from typing import Dict, Optional, Any, List, Set
...
휴리스틱 패스 (Heuristic Pass)의 핵심 아키텍처 시사점:
- 결정적 유한 상태 머신 (Deterministic Finite-State Machine, FSM): 상태 전이 (Transitions)가 예측 가능하며 계산 비용이 저렴합니다.
- "고정된 (Pinned)" 탈출구: 인간 또는 상위 프로세스가 특정 기술 (Skill)을 "고정 (pin)"할 수 있으며, 이는 자동 가지치기 (Pruning) 대상에서 완전히 제외되는 영구적 지식으로 표시됩니다.
- 안전 우선 아카이빙 (Safety-First Archival): 코드가
_u.delete_skill()이 아닌_u.archive_skill()을 호출한다는 점에 주목하십시오. 자율 시스템은 복구 경로 없이 자신의 지식을 영구적으로 파괴해서는 안 됩니다. 아카이빙은 파일을 콜드 스토리지 (Cold Storage)로 이동시켜, 안전하게 보관하면서도 활성 검색 창 (Active Retrieval Window)에서는 제외합니다.
LLM 패스: 심층 리팩토링을 위한 에이전트 포킹 (Forking)
휴리스틱 패스 (Heuristic Pass)가 완료되면, 큐레이터 (Curator)는 두 번째 단계인 의미론적 리팩토링 스윕 (Semantic Refactoring Sweep)을 시작합니다.
큐레이터는 단순한 API 호출을 실행하는 대신, 완전히 격리된 AIAgent 인스턴스를 생성 (Spawn)합니다. 이 백그라운드 에이전트는 고도로 구조화된 시스템 프롬프트 (System Prompt)의 안내를 받으며, 기술 (Skill)을 읽고, 쓰고, 병합할 수 있는 도구 접근 권한 (Tool Access)을 부여받습니다.
큐레이터가 이러한 프로세스 격리를 처리하는 방식은 다음과 같습니다:
# agent/curator.py
import os
...
이 설계가 효과적인 이유:
- 리소스 최적화 (Resource Optimization): 메인 사용자 대면 에이전트는 추론 능력이 매우 뛰어난 모델 (예:
claude-3-5-sonnet또는gpt-4o)에서 실행되는 반면, 백그라운드 큐레이터는 매우 최적화되고 비용 효율적인 모델 (예:gpt-4o-mini또는claude-3-haiku)에서 실행될 수 있습니다. - 엄격한 샌드박싱 (Strict Sandboxing):
skip_context_files=True및skip_memory=True를 설정함으로써, 백그라운드 에이전트가 민감한 사용자 세션 데이터를 읽는 것을 방지합니다. 에이전트는 자신에게 할당된 기술 파일들만 볼 수 있습니다. - 무한 루프 방지 (No Infinite Loops):
_memory_nudge_interval = 0으로 설정하면 백그라운드 에이전트가 또 다른 백그라운드 큐레이션 프로세스를 재귀적으로 트리거하는 것을 보장하며 방지할 수 있습니다. 재귀적 실행은 API 예산을 빠르게 소진시킬 수 있습니다.
LLM 작업과 포렌식 증거의 화해 (Reconciling LLM Actions with Forensic Evidence)
자율 시스템을 구축할 때 가장 어려운 부분 중 하나는 LLM의 비신뢰성 (unreliability)을 처리하는 것입니다. 만약 LLM이 최종 텍스트 요약에서 read_csv_v1을 csv_parser_umbrella로 통합했다고 주장했지만, 실제 내부적으로는 코드를 복사하지 않고 read_csv_v1을 그냥 삭제해 버렸다면 어떻게 될까요? 혹은 완전히 잘못된 umbrella 이름을 환각 (hallucination)했다면 어떻게 될까요?
이를 해결하기 위해 Hermes는 _reconcile_classification()에서 **진실 탐색 화해 알고리즘 (truth-finding reconciliation algorithm)**을 구현합니다. 이 알고리즘은 LLM의 서술된 요약을 맹목적으로 신뢰하지 않습니다. 대신, LLM의 주장과 세션 중에 수행된 도구 호출 (tool calls)의 실제 포렌식 기록 (forensic record)을 교차 참조합니다.
# agent/curator.py
def _reconcile_classification(
...
이러한 다중 신호 검증 (multi-signal validation)은 세 가지 별개의 증거 계층에 의존합니다:
- "결정적 증거 (The Smoking Gun)" (흡수된 선언 - Absorbed Declarations): 에이전트가
delete_skill(name, absorbed_into="target")을 호출할 때, 도구 자체가 에이전트에게 코드가 어디로 이동하는지 선언하도록 강제합니다. 이는 의도를 나타내는 가장 강력한 신호입니다. - "목격자 증언 (The Witness Testimony)" (모델 블록 - Model Block): 큐레이션 실행이 끝날 때 모델이 출력하는 구조화된 YAML 블록입니다. 이는 모델이 자신이 _무엇을 했다고 생각하는지_를 나타냅니다.
- "포렌식 증거 (The Forensic Evidence)" (휴리스틱 도구 호출 감사 - Heuristic Tool-Call Audit): 원시 파일 쓰기 및 도구 호출에 대한 사후 분석입니다. 모델이 기술 (skill)을 통합했다고 주장하지만, 파일 시스템 로그에 대상 umbrella에 대한 쓰기 기록이 없다면, 시스템은 환각을 포착하여 감사 보고서에 표시합니다.
신뢰 구축: 감사 추적 (The Audit Trail)
자율적인 자가 리팩토링 (self-refactoring)은 시스템 관리자에게 매우 두려운 일일 수 있습니다. 에이전트가 자신의 코드베이스를 스스로 다시 작성할 수 있다면, 무언가 잘못되었을 때 어떻게 디버깅할 수 있을까요?
그 답은 **엄격한 이중 형식 감사 추적 (strict, dual-format audit trail)**에 있습니다. Hermes Curator가 실행될 때마다 logs/curator/{timestamp}/ 아래에 두 개의 파일을 포함하는 영구 기록을 작성합니다:
run.json: 실행 전후의 정확한 상태, 모든 도구 호출 (tool calls) 목록, 토큰 사용량, 그리고 정밀한 전이 델타 (transition deltas)를 포함하는 매우 상세하고 기계가 읽을 수 있는 (machine-readable) 파일입니다.REPORT.md: 무엇이 아카이브되었고, 무엇이 통합되었으며, 그 이유가 무엇인지 요약하는 깔끔하고 사람이 읽을 수 있는 (human-readable) 마크다운 (markdown) 파일입니다.
# agent/curator.py
from pathlib import Path
import json
...
이 로그를 유지함으로써, 개발자들은 에이전트의 지식 베이스 (knowledge base)가 어떻게 진화하고 있는지 쉽게 추적할 수 있습니다. 만약 에이전트의 성능이 저하되기 시작한다면, 빠른 git diff 확인이나 최신 REPORT.md를 훑어보는 것만으로도 어떤 기술 (skills)이 병합되거나 아카이브되었는지 정확히 파악할 수 있어 즉각적인 롤백 (rollback)이 가능합니다.
결론
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기