홈시리즈멘토링

© 2026 정기창. All rights reserved.

본 블로그의 콘텐츠는 CC BY-NC-SA 4.0 라이선스를 따릅니다.

☕후원하기소개JSON Formatter러닝 대기질개인정보처리방침이용약관

© 2026 정기창. All rights reserved.

콘텐츠: CC BY-NC-SA 4.0

☕후원하기
소개|JSON Formatter|러닝 대기질|개인정보처리방침|이용약관

LLM 에이전트에 지식베이스를 통째로 먹이지 않는 법 — 1hop 인덱스 오버레이 패턴

정기창·2026년 5월 18일

Claude Code 같은 LLM 코딩 에이전트와 개인 지식베이스를 처음 엮었을 때, 연결은 분명히 됐는데 어딘가 허전했습니다. 에이전트가 노트를 열 수는 있었고, 작업 결과를 노트로 저장할 수도 있었습니다. 그런데 정작 중요한 "이 작업에 필요한 배경 지식을 에이전트가 알아서 끌어다 쓰는" 부분은, 매번 제가 "이 노트 좀 봐줘"라고 지목해야만 동작했습니다. 자동화라기보다는 수동 호출에 가까웠습니다.

그래서 한 발 더 나아가 보기로 했습니다. "작업이 시작되면 지식베이스를 알아서 읽게 하면 되겠지"라고요. 돌이켜 보면 이게 가장 순진한 발상이었습니다. 이 글은 그 순진한 자동화가 어디서 무너졌고, 결국 어떤 구조로 정착했는지를 정리한 구축기입니다. 핵심 패턴은 얇은 규칙 + 단일 진입점 인덱스 + 1hop 매핑 + 비파괴 오버레이 + 양방향 큐레이터 에이전트입니다.

순진한 자동화가 무너지는 지점

1차 연계가 얕았던 이유는 분명합니다. 읽기 맥락의 주입이 사람의 트리거에 의존했기 때문입니다. 사람이 지목하지 않으면 에이전트는 지식베이스가 있다는 사실조차 작업에 반영하지 못합니다. 결국 매번 같은 맥락을 손으로 떠먹여 줘야 했고, 이건 자동화가 메워야 할 바로 그 틈이었습니다.

그래서 떠올린 것이 "작업 시작 시 지식베이스를 스캔한다"였습니다. 문제는 지식베이스가 수백 개 단위의 파일과 십수 개의 폴더로 자라 있었다는 점입니다. 작업마다 통째로 grep하거나 스캔하면 컨텍스트 윈도우가 폭발하고, 토큰 비용이 입력 규모에 비례해 늘어나며, 정작 필요한 한두 노트는 잡음 속에 묻혀버립니다. "맥락을 모른다"는 문제를 "맥락을 다 읽는다"로 풀면, 더 비싼 문제가 됩니다.

여기서 문제를 다시 정의했습니다. 진짜 과제는 "지식베이스를 어떻게 읽힐까"가 아니라, 도메인 메모리를 필요한 만큼만 적시에 주입하는 방법이었습니다. 즉 주입량을 입력 규모와 분리해내는 것이 본질이라는 생각이 들었습니다.

얇은 규칙 + 1hop — lazy 인덱스라는 사상

해법의 사상은 단순합니다. 매 세션에 상시 주입되는 것은 얇은 행동 규칙 한 박스뿐입니다. "도메인 작업이면 큐레이터에게 위임하라, 단 전수 스캔하지 마라, 인덱스를 1hop만 타라" 같은 지침이 전부입니다. 지식 본문은 절대 상시 주입하지 않습니다.

실제 지식의 진입은 단일 진입점 인덱스 파일 하나에서 출발합니다. 도메인 키워드로 1hop만 매핑해서 해당 폴더의 목차로 가고, 거기서 핵심 노트 한두 개만 읽습니다. 전수 스캔은 규칙 차원에서 못 박았습니다.

[기존 — 순진한 자동화]
작업 시작 → 지식베이스 전체 grep/스캔 → 수백 파일 컨텍스트 주입
  비용 ∝ 지식베이스 크기 (계속 증가)

[이후 — lazy 인덱스]
작업 시작 → 얇은 규칙(상시) → 단일 진입점 인덱스(1hop)
          → 도메인 폴더 목차 → 핵심 노트 1~2개
  비용 ≈ 상수 (지식베이스 크기와 무관)

사실 이건 완전히 새로운 발상은 아닙니다. 에이전트 메모리 시스템에서 흔히 쓰는 "카테고리 인덱스만 상시 로드하고, 본문은 필요할 때 lazy하게 읽는다"는 패턴을, 지식베이스라는 더 큰 대상으로 확장한 것에 가깝습니다. 익숙한 사상을 옆 동네로 옮긴 셈입니다.

비파괴 인덱스 오버레이

여기서 한 가지 원칙을 세웠습니다. 기존 노트를 이동하거나 이름을 바꾸거나 병합하지 않는다는 것입니다. 대신 새 인덱스 레이어만 위에 얹습니다. 루트에 마스터 인덱스 하나, 큰 폴더마다 목차 노트 하나. 사람이 쓰던 구조는 그대로 둡니다.

지식베이스를 오래 쓰다 보면 인덱스 비슷한 파일들이 제각각의 이름으로 굴러다닙니다. 이걸 통일하려고 정리하는 대신, fallback 탐색 순서로 흡수하기로 했습니다. 큐레이터가 폴더에 들어가면 정해진 우선순위로 진입점을 찾습니다.

폴더 진입점 탐색 fallback 순서
_INDEX → README → 00-* → _index → _overview
       → (폴더와 동명인 노트) → 마지막으로 ls

큰 폴더에는 또 다른 함정이 있습니다. 수십~백 개 노트를 한 줄씩 전부 요약해서 인덱스에 넣으면, 그 인덱스 자체가 토큰 폭탄이 됩니다. 그래서 개별 1줄 요약은 금지하고, 월별·구간 단위 롤업과 진입 추천 노트만 둡니다.

왜 굳이 비파괴를 고집했는지 생각해보면, 결국 그 지식베이스는 사람이 매일 쓰는 공간이기 때문입니다. 자동화가 사람의 폴더 구조를 깨면 사람의 워크플로우가 망가집니다. 오버레이는 되돌리기 쉽고 사람 워크플로우와 충돌이 0에 가깝습니다. 사람용 대시보드와 에이전트용 머신 인덱스를 물리적으로 분리해두면, 양쪽이 서로를 침범하지 않습니다.

양방향 큐레이터 에이전트 (IN / OUT)

읽기 주입을 메인 에이전트가 직접 하지 않고, 전담 서브에이전트로 분리했습니다. 메인 에이전트는 도메인 작업을 감지하면 이 큐레이터에게 자동으로 위임합니다. 큐레이터는 두 방향으로 동작합니다.

IN은 읽기입니다. 단일 진입점에서 1hop으로 핵심 노트를 찾아 읽고, 메인에게는 3~6줄 요약과 파일 경로만 돌려줍니다. read-only이며 부작용이 없습니다. 메인 에이전트의 컨텍스트에는 노트 원문이 아니라 압축된 요약만 들어옵니다.

OUT은 쓰기입니다. 작업에서 나온 결정이나 발견을 적절한 폴더에 기록하고, 인덱스를 동기화하고, 지식베이스 git 레포에 토픽 단위로 묶어 1커밋/push까지 자동으로 닫습니다. 읽기만 자동화하고 쓰기를 사람 손에 남겨두면, 시간이 지날수록 지식베이스와 실제 작업이 어긋납니다. 읽기만이 아니라 쓰기까지 닫아야 지식베이스가 죽지 않습니다.

다만 쓰기에는 경계가 필요했습니다. 신규 노트 생성이나 문서 끝에 덧붙이는 것은 자유롭게 허용하되, 기존 본문을 치환하거나 삭제하는 파괴적 쓰기는 사람 확인을 거치도록 했습니다. 자동화가 사람이 쓴 글을 소리 없이 덮어쓰는 것만큼 위험한 건 없다는 생각이 들었습니다. 사적이거나 민감한 영역은 읽기는 허용하되 능동적 기록은 명시적으로 요청했을 때만 하도록 막아두었습니다.

커밋 단위도 설계 대상이었습니다. 기록 한 건마다 커밋하면 히스토리가 잡음으로 가득 찹니다. 그래서 작업이나 도메인 단위로 묶어 한 번에 커밋하도록 했습니다. 히스토리는 "무엇을 왜 했는가"가 읽혀야 의미가 있습니다.

에이전트 행동 규칙과 도메인 사실은 저장 위치가 다르다

구축하면서 가장 오래 고민한 지점입니다. 같은 정보라도 성격에 따라 저장 위치가 달라야 한다는 것입니다.

성격 예시 저장 위치 특성
에이전트 행동 규칙 "이 영역엔 자발적 제안 자제" 에이전트 메모리 매 세션 자동 로드, 어디서든 즉시 강제
도메인 사실·상태 "이 작업 영역은 현재 비활성" 지식베이스 source of truth, 이력 추적, 위임해야 읽힘

구체적인 사례가 하나 있었습니다. 어떤 작업 영역을 한동안 비활성(dormant)으로 표시해야 했는데, 이걸 한 곳에만 적으면 반쪽이 됩니다. "그러니 이 영역엔 더 제안하지 마라"는 행동 규칙은 메모리에 박아 매 세션 즉시 강제되게 하고, "왜·언제 멈췄는가"라는 상태 사실은 지식베이스 인덱스의 frontmatter와 배너에 박아 이력으로 추적되게 했습니다. 그리고 둘을 상호 링크로 연결했습니다. 즉시성은 메모리가, 정합성과 추적성은 지식베이스가 책임지는 구조입니다.

자동 위임 고리와 부트스트랩 순서

이 모든 게 동작하려면 메인 에이전트가 "지금이 도메인 작업이구나"를 알아채고 큐레이터에게 넘겨야 합니다. 그 고리를 Claude Code의 글로벌 규칙 박스에 걸었습니다. 발동 조건, 절차, 안티패턴을 명시하되, 핵심은 짧습니다. 메인 에이전트의 책임은 "1초 도메인 분류 → 매칭되면 위임" 한 번뿐입니다. 그 뒤의 IN 요약, OUT 기록, 커밋은 이미 박혀 있는 연쇄로 알아서 흘러갑니다.

마지막으로 부트스트랩 순서에서 한 번 더 배웠습니다. 에이전트 정의는 보통 세션 시작 시점에 로드되므로, 새로 만든 큐레이터는 다음 세션부터 호출됩니다. 그런데 인덱스가 없는 상태에서 큐레이터가 먼저 돌면, 큐레이터는 결국 전수 스캔으로 퇴화합니다. 그래서 인덱스를 에이전트보다 먼저 만들어야 합니다. 설계 순서 자체가 패턴의 일부라는 생각이 들었습니다.

컨텍스트 엔지니어링 관점에서 정리하며

구축을 마치고 돌이켜 보면, 핵심은 네 가지로 압축됩니다.

  • 지식베이스를 통째로 먹이지 마라. 얇은 규칙 + 단일 진입점 인덱스 + 1hop이 컨텍스트 비용을 입력 규모와 무관한 상수로 만든다.
  • 자동화는 비파괴여야 사람 워크플로우와 공존한다. 정리하지 말고 오버레이로 얹고, 기존 명명은 fallback 순서로 흡수한다.
  • 읽기만이 아니라 쓰기(OUT)까지 닫아야 지식베이스가 죽지 않는다. 단 파괴적 쓰기에는 사람 게이트를 둔다.
  • 같은 사실도 행동 규칙과 도메인 사실로 갈라 저장한다. 메모리는 즉시성을, 지식베이스는 정합성과 추적성을 맡는다.

RAG나 벡터 검색을 끌어오기 전에, 단일 진입점 인덱스와 1hop 규칙만으로도 개인 규모의 지식베이스는 충분히 다룰 수 있다는 것이 이번 구축의 결론이었습니다. 결국 컨텍스트 엔지니어링은 "무엇을 더 넣을까"가 아니라 "무엇을 넣지 않을까"를 설계하는 일에 가깝다는 생각이 들었습니다.

Claude CodeLLM 에이전트컨텍스트 엔지니어링에이전트 메모리지식베이스 자동화RAG 대안서브에이전트

관련 글

CLAUDE.md는 이미 LLM Wiki였다 — 모노레포 개발자가 본 Karpathy 방법론

Karpathy의 LLM Knowledge Base 방법론을 모노레포 환경에 1:1 대입해봤습니다. 7개 구성요소 중 6개는 이미 동작하고 있었고, 전면 도입보다 빠진 조각만 채우는 게 핵심이라는 결론에 도달했습니다.

관련도 91%

큰 작업의 거처를 챗봇 UI에서 로컬 하네스로 — 옆에서 함께 옮긴 이야기

주변에서 외부 챗봇의 커스텀 기능 위에 무거운 작업을 굴리던 분이 매번 같은 자리에서 막히는 걸 보고, 그 작업의 거처를 Claude Code 위 로컬 하네스로 옮겨드린 과정. 옆에서 본 네 가지 막힘과 함께 갖춰둔 여섯 가지 패턴을 정리했습니다.

관련도 91%

Claude Code 라우팅 매트릭스 빈 행 3개를 새 전문 에이전트로 메운 회고

Claude Code 라우팅 매트릭스를 글로벌 CLAUDE.md 와 review-loop SKILL.md 에 박은 직후, 24행을 다시 들여다보니 fallback 으로 흘러갈 수밖에 없던 도메인 세 개가 어렵지 않게 떠올랐습니다. devops-engineer · dba · test-data-verifier 세 전문 에이전트를 더하며 만난 정의 작업의 무게를 정리한 후속편입니다.

관련도 91%