에이전트 메모리 엔진 (9/10) — ByteRover Context Tree 적용: BM25 하이브리드 검색

외부 도구의 설계 아이디어를 분석하고, 자체 환경에 맞는 하이브리드 검색 시스템으로 재설계한 구현 기록


핵심 요약

  • ByteRover CLI의 5-tier 하이브리드 검색 아이디어를 분석한 후, OpenClaw 환경에 맞게 재설계하여 구현했다
  • ByteRover 방법론 기준 평가에서 원본 65점 대비 OpenClaw 자체 구현 90점을 달성했다
  • 한국어 교착어 문제를 BM25 + tree keyword 하이브리드 검색으로 해결했다

배경: 메모리 검색 정확도 문제

AI 에이전트 시스템에서 기억을 축적하는 것보다 필요한 기억을 정확하게 검색하는 것이 훨씬 어렵습니다. 지식 파일이 43개로 늘어나면서 "가치관이 뭐야?" 같은 단순한 자연어 쿼리에도 정확한 파일을 찾지 못하는 케이스가 반복되었습니다.

이 문제를 해결하기 위해 ByteRover CLI가 제안한 5-tier 하이브리드 검색(BM25 + LLM agentic, 92-96% 정확도)의 설계를 분석했습니다. ByteRover를 직접 도입하는 대신 핵심 아이디어만 추출해 OpenClaw 네이티브로 재구현하는 방향을 선택했습니다.

OpenClaw vs Hermes 맥락: OpenClaw는 안정적으로 운영 중인 메모리 시스템입니다. Hermes는 OpenClaw 마이그레이션 대상으로, 초기 전환 시도에서 토큰 폭주 문제가 발생해 OpenClaw로 회귀한 이력이 있습니다. 현재 Hermes 재시도(검증 단계)가 진행 중이며, 이번 Context Tree 구현은 OpenClaw 기반에서 이루어졌습니다.


구현 내용

1. ByteRover vs OpenClaw 구현 비교

항목 ByteRover 공식 OpenClaw 자체 구현
총점 (자체 평가) 65/100 90/100
Retrieval 정확도 92-96% 100% (10/10 쿼리)
검색 방식 BM25 + LLM agentic BM25 + tree keyword 하이브리드
의존성 외부 CLI 필요 스크립트 내장 (의존성 0)
한국어 미검증 교착어 부분매칭 구현

점수 차이의 근거: ByteRover는 범용 도구이고, OpenClaw 구현은 특정 에이전트 운영 환경에 특화되어 있습니다. 범용성을 포기하고 특화 성능을 극대화한 결과입니다.


2. 4가지 핵심 적용 메커니즘

메커니즘 1: Context Tree 계층 구조

문제: 단일 파일 방식에서는 self-architecture.md가 46KB까지 증가했습니다. 매번 전체 파일을 로딩해야 했고, 쿼리와 무관한 정보가 컨텍스트를 점유했습니다.

설계: bank/ 하위 7개 도메인, 43개 파일로 계층 분리했습니다.

bank/
├── identity/      (3 files)   — 가치관, 페르소나, 자아 정의
├── daily/         (6 files)   — 루틴, 습관, 컨디션 기록
├── knowledge/    (12 files)   — 도메인 지식, 학습 내용
├── patterns/      (4 files)   — 반복 패턴, 행동 규칙
├── entities/      (6 files)   — 관계, 도구, 서비스 정의
├── experience/    (1 file)    — 경험 사례
├── opinions/      (2 files)   — 의견, 신뢰도 기반 평가
├── world/         (3 files)   — 프로젝트, 환경, 도구 현황
└── _meta/         (3 files)   — 인덱스, 스키마, 설정

결과: 최대 파일 크기 46KB → 10.6KB (75% 감소).


메커니즘 2: BM25 하이브리드 검색 스코어링

tree-index.json에 노드→키워드→파일 매핑(24개 노드)을 정의하고, 하이브리드 스코어를 계산합니다.

score = 0.4 * tree_keyword_match + 0.6 * bm25_idf_score

IDF 캐시: tree-index.json에 3,452 terms를 사전 내장합니다. 외부 라이브러리 없이 BM25를 구동하기 위한 설계입니다.

쿼리 캐시: TTL 30분, 최대 20 entries. 동일 쿼리 반복 시 재계산을 생략합니다.

한국어 교착어 처리:

def normalize_korean(token: str) -> str:
    for keyword in index_keywords:
        if token.startswith(keyword) or keyword in token:
            return keyword
    return token

기존 flat 매칭에서는 "가치관이"가 "가치관"과 매칭되지 않았습니다. 교착어 특성상 조사가 붙은 형태를 원형으로 환원하는 처리가 필요했습니다.


메커니즘 3: MemTree 자동 분할

bank-size-watch.py가 파일 크기를 모니터링하고 임계치 초과 시 자동 분할합니다.

THRESHOLDS = {
    "warn":  8 * 1024,   # 8KB — 경고 로그
    "split": 15 * 1024,  # 15KB — 자동 분할 트리거
}

실제 분할 사례: - guide.md (10KB) → 3개 파일로 분할 - full.md (46KB) → 7개 파일로 분할 - 분할 후 30+ 의존성 경로 자동 업데이트

분할 시 의존성 경로 갱신이 자동화되지 않으면 참조 깨짐이 발생합니다. 분할 전 의존성 그래프를 파악하는 단계가 필수입니다.


메커니즘 4: TAG_ROUTING 키워드 기반 분류

retain-merge.py가 대화에서 추출된 기억 태그(W/B/O/S)를 정규표현식 키워드로 분류하고 대상 파일을 자동 선택합니다.

TAG_ROUTING = {
    "W": {  # World — 환경/도구/프로젝트
        r"도구|툴|tool": "world/tools.md",
        r"프로젝트|project": "world/projects.md",
    },
    "B": {  # Behavior — 패턴/습관
        r"패턴|반복|루틴": "patterns/routines.md",
    },
    "O": {  # Opinion — 의견/평가
        r"생각|판단|평가": "opinions/assessments.md",
    },
    "S": {  # Self — 정체성/가치관
        r"가치관|원칙|철학": "identity/values.md",
    },
}

Fuzzy Dedup: 80% 키워드 오버랩 기준으로 중복 축적을 차단합니다. 같은 내용이 표현만 달리해서 반복 저장되는 문제를 방지합니다.


3. 3계층 메모리 파이프라인 아키텍처

전체 구조는 3계층으로 동작합니다.

Layer 1: memory/          ← 일일 대화 로그
  └── memoryFlush 자동 생성. Retain 태그 포함. 원시 기억 저장.

Layer 2: bank/            ← 큐레이션 지식 (Context Tree 구조)
  └── Reflect(매일 03:00) 자동 증류: memory/ → bank/
      스크립트 7개 자동 실행 (Phase 1~3.5)

Layer 3: recall/          ← 검색 버퍼
  └── recall-tree.py BM25 하이브리드 검색
      TTL 1시간 캐시

보조 시스템: - micro-cycle: 30분마다 memory/bank/ 경량 증류. 장시간 세션에서 기억 손실 방지. - confidence-decay: opinions/*.md 신뢰도 일일 감쇠(-0.02/day). 0.30 미만 자동 삭제로 오래된 의견 정리. - proactive briefing: 18개 모드 자율 브리핑. 컨텍스트 전환 시 관련 기억을 선제적으로 제공.


4. 검색 쿼리 흐름

쿼리 입력
  ↓
쿼리 캐시 조회 (30분 TTL)
  ├── 캐시 HIT → 즉시 반환
  └── 캐시 MISS
        ↓
      한국어 교착어 정규화
        ↓
      tree-index.json 노드 매핑 (tree keyword score)
        ↓
      BM25 IDF 스코어링 (IDF 캐시 3,452 terms)
        ↓
      하이브리드 스코어 합산 (0.4:0.6)
        ↓
      상위 N개 파일 반환 → recall/ 캐시 저장 (1시간 TTL)

실측 결과

항목 적용 전 적용 후
검색 정밀도 flat 매칭 (한국어 실패 빈번) 10/10 자연어 쿼리 통과
최대 파일 크기 46KB 10.6KB (75% 감소)
중복 축적 3회 이상 재발 0건 (fuzzy dedup)
토픽 커버리지 불완전 43/43 파일 100%
memory-warning 31건 6건

대표 케이스: "가치관이 뭐야?" 쿼리가 기존에는 NO_MATCH였으나, 교착어 정규화 후 identity/values.md를 정확히 매칭합니다.


설계 결정과 트레이드오프

ByteRover 직접 도입을 선택하지 않은 이유: 외부 CLI 의존성, 클라우드 동기화 기능, Git-like 브랜치 관리 등 대상 환경에서 불필요한 기능이 시스템 복잡도를 높였습니다. 핵심 알고리즘만 추출해 내장 스크립트로 구현하면 의존성 없이 동일한 검색 품질을 달성할 수 있습니다.

BM25 가중치 0.4:0.6 선택 근거: 초기 0.5:0.5에서 시작했으나, 한국어 교착어 환경에서는 BM25 IDF 스코어링 비중이 높을 때 정확도가 상승했습니다. tree keyword 매칭은 노드 분류 역할에 집중하고, 세부 스코어링은 BM25에 위임하는 구조입니다.

분할 후 의존성 관리: full.md → 7개 파일 분할 시 30+ 경로 참조가 깨지는 문제가 발생했습니다. 분할 전 grep -r "full.md" .으로 의존성 맵을 먼저 파악하고, 분할 후 자동 경로 업데이트 스크립트를 실행하는 순서가 필요합니다.


정리

ByteRover Context Tree의 설계 원칙—계층적 파일 구조, BM25 하이브리드 스코어링, 자동 분할—은 AI 에이전트 메모리 시스템에 직접 적용 가능한 아이디어입니다. 다만 범용 도구를 그대로 도입하면 대상 환경에 맞지 않는 기능이 시스템 복잡도를 높입니다.

핵심 알고리즘만 추출하고 한국어 교착어 처리와 네이티브 IDF 캐시를 추가한 자체 구현이 원본보다 높은 검색 정확도를 기록한 이유는 특화 설계에 있습니다. 범용성과 특화 성능은 트레이드오프 관계이며, 대상 환경을 먼저 정의한 후 도구를 선택하거나 재구현하는 접근이 유효합니다.

시리즈 전체 안내: 시리즈 목차

댓글

이 블로그의 인기 게시물

"LLM 핵심 학습 (1/6) — 기본: 토큰화·임베딩·어텐션·위치 인코딩"

"LLM 핵심 학습 (2/6) — 파인튜닝: LoRA·QLoRA·증류·Adapter"

"ML 기초 학습 (1/9) — 머신러닝과 sklearn: 학습의 좌표계"