[Claude Code] 위키가 커질 때 메인 컨텍스트를 지키는 탐색 서브에이전트 설계
LLM 에이전트에게 "위키"를 붙여주면 처음 얼마간은 순수한 이득이다. 세션이 끝나도 지식이 남고, 다음 세션은 같은 삽질을 반복하지 않는다. 그런데 그 위키가 자라기 시작하면 조용히 다른 문제가 생긴다 — 지식을 "찾는" 행위 자체가 컨텍스트를 먹기 시작하는 것이다.
작업 중이던 저장소의 지식 위키가 대략 문서 150건, 문서 간 내부 링크 600여 개, 통합 색인 파일 하나가 90KB에 이르는 시점에 이 문제를 실제로 겪었다. 색인 파일 하나만 열어도 어림잡아 2만 토큰대를 태운다. 여기에 관련 문서를 찾느라 grep을 몇 번 더 돌리고 본문을 서너 편 열어보면, 정작 그 세션의 "본 작업"에 쓸 컨텍스트가 남지 않는 상황이 벌어진다. 이 글은 그 문제를 풀기 위해 도입한 조회 전용 서브에이전트 하나의 설계 기록이다.
문제의 모양 — 중간 읽기는 많고 답은 짧다
위키 탐색이라는 작업을 자세히 뜯어보면 특이한 비대칭이 있다. 색인을 훑고, 키워드로 grep을 두세 번 돌리고, 후보 문서를 열어 본문을 확인하고, 관련 링크를 한 단계 더 따라가는 — 이 전체 과정은 읽기 분량이 크다. 그런데 최종적으로 메인 에이전트가 실제로 필요로 하는 것은 "결론 몇 줄과 그걸 뒷받침하는 원문 한두 문단"뿐이다. 중간 읽기는 무겁고 최종 산출은 가볍다.
이런 모양의 작업은 서브에이전트로 컨텍스트를 격리했을 때 이득이 가장 크다. 무거운 중간 읽기를 별도 컨텍스트에 몰아넣고, 메인에게는 가벼운 결론만 돌려주면 되기 때문이다. 반대로 결론까지도 무거운 작업(예: 코드를 실제로 고쳐야 하는 구현 작업)은 서브에이전트로 넘겨도 결국 diff를 다시 검증해야 해서 격리 이득이 작다. 위키 탐색은 전자에 정확히 들어맞는다.
문제 제기는 팀 내부에서 나왔다 — "위키 규모가 커졌을 때 이걸 어떻게 관리해야 하나 고민하다가, 위키 탐색 전용 서브에이전트를 두어 메인 에이전트의 컨텍스트를 아끼는 방식은 어떤가"라는 제안이었다. 여기서 나온 결정이 이 글이 다루는 조회형 서브에이전트다.
설계 3원칙
곧바로 "위키 관련 일은 전부 서브에이전트에 위임"으로 가지 않았다. 세 가지 원칙을 먼저 세웠다.
첫째, 전건 위임이 아니라 조건부 라우팅. 서브에이전트 호출 자체가 토큰과 지연이라는 고정비다. grep 한 방으로 끝나는 단건 조회까지 위임하면 격리로 아낀 것보다 호출 오버헤드가 더 크다. 그래서 위임 대상을 세 종류로 좁혔다 — 여러 문서에 걸친 종합 질문, 메인이 이미 두 번 실패한 광역 탐색, 작업 착수 전의 포괄적 브리핑. 이 세 종류가 아니면 메인이 직접 읽는다.
둘째, 반환 계약은 요약 금지·원문 발췌. 위키에 적힌 지식은 뉘앙스가 생명이다. 어떤 값이 검증됐는지(verified인지 draft인지), 어떤 조건에서만 유효한지, 만료 배너가 붙어 있는지 — 이런 표지를 서브에이전트가 자기 문장으로 패러프레이즈하는 순간 사라진다. "컨텍스트는 아꼈는데 지식이 손상되는" 교환은 받아들이지 않기로 했다. 그래서 반환 형식을 문서 경로 + 검증 상태 + 만료 여부 + 원문 인용 블록으로 고정했다.
셋째, 작은 규모라도 시공 규약을 생략하지 않는다. 이 서브에이전트 자체는 규모가 작은 도구지만, 상태 파일을 갖춘 정식 절차로 계획하고 구현·검증까지 한 사이클로 완주시켰다. "소형이니까 즉흥적으로"를 허용하지 않는 것 자체가 하나의 결정이었다.
언제 메인이 하고 언제 위임하나
라우팅 판정은 아래 표로 고정했다.
| 요청 유형 | 판정 기준 | 처리 주체 |
|---|---|---|
| 단건 조회 | 색인에서 문서가 바로 특정되거나, 키워드 grep 한 번에 적중 |
메인이 직접 읽는다 |
| 종합 질문 | "이 주제에 대해 위키가 전반적으로 뭐라고 하나" 식으로 여러 문서에 걸침 | 탐색 서브에이전트에 위임 |
| 광역 탐색 | 메인이 표현을 바꿔가며 grep을 두 번 시도해도 못 찾음 |
탐색 서브에이전트에 위임 |
| 작업 전 브리핑 | 본 작업 착수 전, 관련 지식을 빠짐없이 훑어야 함 | 탐색 서브에이전트에 위임 |
핵심은 "위임 = 항상 이득"이 아니라는 점을 표로 못박은 것이다. 판정 기준이 애매하면 결국 매번 메인이 재량으로 판단하게 되고, 그 재량이 흔들리면 원칙 자체가 무의미해진다.
에이전트 정의 — 도구를 줄여서 강제한다
서브에이전트의 권한은 프롬프트 문구가 아니라 실제로 쥐어주는 도구 목록으로 강제한다는 게 이 저장소의 서브에이전트 작성 규약이다. "읽기 전용으로 행동하라"는 지시문은 모델이 실수로 어길 수 있지만, 애초에 쓰기 도구를 주지 않으면 구조적으로 불가능해진다. 그래서 이 탐색 에이전트의 frontmatter는 다음과 같이 도구를 세 개로 못박았다.
---
name: wiki-scout
description: 위키 탐색 전담 조회형 서브에이전트. 여러 문서에 걸친 종합 질문, 메인이 grep을
2회 시도해도 못 찾은 광역 탐색, 작업 착수 전 관련 위키 브리핑을 위임할 때 부른다. 단건
조회(색인에서 문서가 특정되거나 키워드 grep이 한 번에 적중하는 경우)는 위임 대상이 아니다
— 메인이 직접 읽는 편이 싸다.
tools: Read, Grep, Glob
---
Write·Edit·Bash가 전부 빠졌다. 이 에이전트는 낡거나 모순된 문서를 발견해도 고칠 수 없다 — 도구가 없기 때문이다. 발견 사실을 반환 문구에 적을 뿐이다. 감사(audit)나 수정은 다른 역할의 몫이고, 이 에이전트는 오직 "지금 위키가 뭐라고 적어뒀는가"를 있는 그대로 가져오는 역할로 한정했다.
동작 순서(execution loop)도 명시적으로 못박았다. 최신 개정에서는 색인을 열 때 "지금 참인 값의 묶음"부터 보고 "이력·경위 묶음"은 필요할 때만 열도록 순서를 나눴는데, 이 배경은 뒤에서 따로 다룬다.
1. 색인에서 시작 — 현행 묶음 우선.
통합 색인을 먼저 읽는다. 그중에서도 "지금 참인 값·절차"를 모아둔 묶음을 먼저
보고, "이력·경위"를 모아둔 묶음은 그런 질문을 받았을 때만 연다.
2. 값 노트 확인.
지금의 수치·설정·상태를 묻는 질문이면 서사형 문서보다 "값 하나짜리 원본
노트"를 먼저 찾는다 — 서사 문서에 같은 값이 남아 있어도 원본 노트가 우선한다.
3. 이력 묶음은 요청 시에만.
"왜 이렇게 됐나", "언제 바뀌었나" 같은 질문에만 이력 묶음을 연다. 지금 값을
묻는 질문에 과거 시점 문서를 답으로 쓰지 않는다 — 가장 흔한 오독이 이것이다.
4. 후보 수집.
키워드·동의어를 바꿔가며 grep을 2~3회 돌린다. 한 번으로 끝내지 않는다.
5. 열람.
후보 문서를 실제로 연다. 목록만 보고 판단하지 않는다.
6. 표지 확인.
문서마다 검증 상태·시간적 성격·만료 배너 유무를 확인한다.
7. 발췌 추출.
질문에 직접 답하는 부분만 원문 그대로 인용한다. 관련 없는 단락은 붙이지 않는다.
8. 반환 조립.
아래 반환 계약 형식으로 맞춘다.
반환 계약 — 요약이 아니라 인용
반환 형식은 이렇게 고정했다. 문서마다 경로, 검증 상태, 시간적 성격, 만료 여부, 소속을 한 줄로 붙이고 그 아래 원문을 인용 블록으로 싣는다.
## 문서별 발췌
<문서 경로> — status: <verified|draft|...> — scope: <current|snapshot|target|없음>
— 만료: <있음(배너 문구)|없음> — 귀속: <소속 구분>
> (질문에 답하는 부분의 원문 발췌 — 그대로, 필요하면 여러 블록)
## 요약
- 발췌들이 답하는 바를 3~5줄로 — 발췌를 대체하는 게 아니라 길잡이 역할만 한다.
- 문서 간 모순·공백(위키가 답하지 않는 부분)이 있으면 여기 명시한다.
- draft·만료 문서에서 온 내용이 섞였으면 그 사실을 한 줄로 경고한다.
여기서 "요약"은 발췌 다음에 오는 보조물이지 발췌를 대신하지 못한다. 반환 규격을 스스로 점검하는 체크리스트에도 "요약 문장이 발췌 자리를 차지한 문서가 하나도 없다"는 항목이 별도로 들어간다 — 계약 위반의 가장 흔한 실패 형태가 바로 이거였기 때문이다. 실제 구동 검증에서도 이 계약이 지켜지는지가 통과 기준이었고, 정적 검사만으로는 패러프레이즈 위반을 못 잡는다는 게 확인돼 실제로 세션을 돌려 반환물을 눈으로 대조하는 방식으로 검증했다.
시공 중 발견한 규약 충돌
작은 규모의 작업이었지만, 만들다 보니 기존 서브에이전트 작성 규약과 정면으로 부딪히는 지점이 하나 나왔다. 이 저장소의 서브에이전트 작성 규약에는 "장문 산출물은 파일로 저장하고 부모에게는 요약과 경로만 반환한다"는 항목이 있다. 그런데 이 탐색 에이전트의 반환 계약은 "요약 금지, 원문 발췌"다. 둘을 그대로 겹치면 모순이다 — 게다가 이 에이전트에게는 애초에 쓰기 도구가 없어서 파일 저장 자체가 구조적으로 불가능했다.
당시 상태 파일에 남은 결정 기록을 요지만 추려 옮기면 이렇다(원문 그대로가 아니라 발견·해소·판정 세 줄로 재구성한 것이다).
[결정 기록]
- 발견: "장문은 파일로 저장, 부모에게는 요약과 경로만" 규약과
"요약 금지·원문 발췌" 계약이 조회형 에이전트에서 서로를 배제함
(읽기 전용 도구 목록이라 파일 저장 자체가 불가능).
- 해소: 쓰기 도구를 추가로 부여하는 대신, 계약 쪽을 조정 —
"반환이 길어지면 관련도 상위 문서의 발췌만 온전히 싣고, 나머지는
경로·상태·만료 여부 목록으로만 실어 '범위를 좁혀 재위임하라'고
부모에게 알린다"로 재정의.
- 판정: 정당한 예외 — 원문 규약이 조회형 에이전트를 상정하지 않고
쓰여 있었다는 점을 근거로 규약 문서 자체에 조회형 예외로 명문화.
해소 방식의 핵심은 "예외를 암묵적으로 허용"하지 않고 규약 문서 쪽에 명시적으로 새 절을 추가한 것이다. 조회형처럼 쓰기 도구가 아예 없는 역할에서는 "장문이면 상위 문서의 발췌만 온전히 담고 나머지는 목록으로 대체하며, 범위를 좁혀 재위임을 요청한다"는 문장이 지금은 정식 규약의 일부다. 파일 저장은 여전히 없다 — 회피가 아니라 계약의 재정의로 풀었다.
색인이 둘로 갈라지며 탐색 순서가 바뀐 이야기
이 에이전트를 만든 뒤에도 위키 자체의 구조는 계속 바뀌었다. 최근 개정에서 통합 색인이 "지금 참인 것"과 "지나간 경위·과거 시점 기록"의 두 묶음으로 나뉘었다. 이전에는 색인 하나를 죽 훑으며 관련 항목을 찾으면 됐지만, 이제는 어느 묶음을 먼저 열지가 질문의 성격에 따라 갈린다 — 지금 값을 묻는 질문이면 "지금 참인 것" 묶음과 값 노트만으로 끝나야 하고, "왜 이렇게 됐나"를 묻는 질문일 때만 과거 시점 묶음을 연다.
이 구분이 왜 생겼는지는 명확하다. 시점이 찍힌 스냅샷 문서를 지금도 유효한 값으로 오독하는 사고가 반복됐기 때문이다. 어떤 값이 "검증됐다(verified)"는 것과 "지금 참이다(scope: current)"는 것은 서로 다른 축인데, 검증 표지만 믿고 시점 문서를 그대로 인용하면 낡은 값을 현재값처럼 전달하게 된다. 그래서 원칙이 하나 추가됐다 — 지금의 값을 묻는 질문에는 검증된 과거 스냅샷보다 아직 검증 전이라도 "지금 참" 표지가 붙은 원본 노트가 우선한다. 탐색 에이전트의 동작 순서도 이 원칙에 맞춰 "현행 묶음 → 값 노트 → 기록 묶음은 요청 시"로 재배열됐다.
색인 구조를 바꾼 김에 재검토 트리거도 하나 심어뒀다. 통합 색인의 "지금 참인 것" 묶음이 일정 줄 수(500줄)를 넘으면, 지금처럼 색인을 사람이 눈으로 훑는 방식 위에 임베딩 기반 검색 같은 파생 계층을 얹을지 검토하기로 했다. 아직 그 문턱에 닿지 않았으니 지금은 색인 훑기가 유일한 진입 경로다.
기각한 대안들
전건 위임. 위키와 관련된 질문은 예외 없이 전부 탐색 서브에이전트에 넘기는 안을 먼저 검토했다. 하지만 grep 한 번이면 끝나는 조회까지 위임하면 호출 지연·토큰 비용이 격리로 얻는 이득을 넘어선다. 조건부 라우팅으로 결론 낸 이유다.
요약 반환. 서브에이전트가 원문을 다 읽고 결론만 자연어로 요약해 돌려주는 안도 있었다. 컨텍스트는 확실히 더 아낄 수 있지만, 검증 상태·시간적 성격 같은 신뢰 표지와 조건·함정 같은 뉘앙스가 요약 과정에서 소실된다. "검증된 것만 신뢰한다"는 상위 원칙이 탐색 에이전트를 거치는 순간 무력화되는 셈이라 기각했다.
단건 조회까지 위임. 판정 경계를 더 단순하게 "위키에 관한 건 다 위임"으로 낮추는 안도 잠깐 논의됐지만, 이건 사실상 전건 위임의 변형이라 같은 이유로 기각했다.
재검토 조건도 정해뒀다 — 조건부 라우팅 세 종류의 위임이 실사용에서 실제로 이득을 내지 못하면(호출 비용이 격리 이득을 넘어서면) 이 설계 전체를 다시 연다.
교훈
작은 도구 하나를 만드는 과정에서 세 가지가 남았다.
첫째, 서브에이전트를 만드는 결정 자체보다 "무엇을 위임하고 무엇을 직접 할지"의 경계를 표로 못박는 일이 더 중요했다. 경계가 흐리면 위임은 항상 과잉이 되거나 항상 누락이 된다.
둘째, 권한은 프롬프트가 아니라 도구 목록으로 강제해야 실제로 지켜진다. 이 에이전트가 "읽기 전용"인 이유는 그렇게 행동하라고 지시했기 때문이 아니라, 애초에 쓰기 도구를 쥐고 있지 않기 때문이다.
셋째, 규약끼리 부딪히면 조용히 우회하지 말고 규약 문서 자체를 고쳐야 한다. "장문은 파일로 저장" 규약과 "요약 금지" 계약이 충돌했을 때, 임시방편으로 쓰기 도구를 몰래 얹는 대신 규약 문서에 조회형 예외를 명문으로 추가했다. 다음에 비슷한 역할을 만드는 사람(혹은 다음 세션의 에이전트)이 같은 충돌에 다시 부딪히지 않도록.
댓글
아직 댓글이 없습니다. 첫 댓글을 남겨보세요.