서론
Claude Code로 긴 작업을 할 경우, 대화가 길어지면 요약(compact)이 들어갑니다. 요약 후에는 조금 전에 결정했다고 생각했던 내용을 Claude가 기억하지 못하는 경우가 있습니다. 다시 설명하면, 다음 요약에서 또 사라집니다.
사람의 손에 의한 설계 작업이 완전히 빠진 상태에서, 어느 정도의 요구사항만으로 LLM(대규모 언어 모델)이 직접 만들고 수정해 나가는 과정. 저는 그런 미래를 상정하여 Claude Code를 VS Code 내에서 사용할 수 있는 확장 기능을 그 진행 방식대로 제작하고 있습니다. 어떤 문제에 직면하는지 스스로 체험하기 위함입니다.
그 과정에서 여러 번 부딪혔던 문제가 바로 '결정한 것이 사라지는 것'이었습니다. 결정한 내용의 보관 장소는 대화 기록인데, 요약으로 인해 무너지면 다른 곳에 남겨둘 곳이 없습니다. 대화도 길어지기 쉽고, 요약은 반복적으로 들어갑니다. 그래서 compact로 인해 손실되는 부분을 보완하는 기능을 직접 추가하기로 했습니다. 생각했던 것은 제 발언을 요약과는 별개로 원문 그대로 다음 단계로 전달하는 방식입니다.
이것은 코드 작성 작업에 국한된 이야기가 아닙니다. 문서나 자료를 만드는 작업에서도 결정한 내용의 상당 부분은 완성된 결과물에 들어가지만, '이 단어는 사용하지 않는다', '이 내용은 넣지 않는다'라고 결정한 것은 남아있지 않습니다. 넣지 않기로 결정한 것은 어디에도 기록되어 있지 않기 때문입니다. 남는 것은 오직 대화 기록뿐입니다.
어떻게 보완해야 사라지지 않을까? 이를 결정하기 위해 실제 개발 대화를 사용하여 실험을 진행했습니다. 알게 된 점은 4가지입니다.
compact는 한 번이라도 정보를 손실합니다. 다만, 제가 제시한 지시는 첫 번째에서는 단 하나도 사라지지 않았습니다.
- 지시가 사라지는 것은 compact를 반복할 때입니다. 3번을 반복하자, 2개의 대화에서 채점한 제 지시의 33%와 57%가 사라졌습니다. 원인은 이전 회차까지의 제 발언을 다음 요약으로 가져오지 않았기 때문이었습니다.
- 제 발언 전체를 원문 그대로 가져오자, 3번 반복해도 사라진 지시는 0건이었습니다. 같은 방법은 compact에 붙이는 프롬프트 하나만으로도, 발언량이 적을 때는 재현할 수 있습니다.
먼저 바로 복사하여 사용할 수 있는 프롬프트를 제시합니다. 맨 앞의 /compact를 붙여 실행하세요.
/compact 요약의 마지막에 '사용자 발언 (원문)'이라는 절을 추가한다. 그곳에, 이 대화에서 사용자가 보낸 발언을 처음부터 끝까지 순서대로, 단 하나도 빠짐없이, 바꿔 쓰지 않고, 원문 그대로 베껴 쓴다. 이전 요약에도 같은 절이 있다면, 그 내용 전체를 모두 맨 앞에 베껴 쓴다. 만약 한 건의 발언이 1000자를 초과하는 경우에만, 앞부분과 뒷부분을 남기고 중간 부분을 생략해도 좋다. 다른 절은 평소대로 작성한다.
발언량이 70~90건 정도 되는 대화에서는 3번 반복해도 빠진 것이 하나도 없었습니다. 자동으로 들어가는 요약에 같은 프롬프트를 붙이는 방법도 후반부의 '자동인 경우'에 게재했습니다.
실험 방법
사용된 것은 확장 기능을 만드는 과정에서 길어진 실제 대화 기록 2건입니다(대화 A와 대화 B. 둘 다 한국어입니다).
- 대화 기록을 특정 시점에서 자릅니다.
- 그곳에서 요약합니다 (1회차).
- 요약 뒤에 실제 대화의 나머지 부분을 그대로 붙입니다.
- 다시 요약합니다 (2회차). 이 과정을 한 번 더 반복합니다 (3회차).
会話 A のコンテキストの大きさ。22.7 万トークンの会話を 1.1 万に要約し、続きを足して 4.3 万になったところで 0.6 万に、さらに 3.4 万になったところで 0.7 万に要約した
| 대화 | 1회차 요약 | 2회차 요약 | 3회차 요약 | 제 발언 (누적) |
|---|
| A | 22.7만 → 1.1만 | 4.3만 → 0.6만 | 3.4만 → 0.7만 | 24 → 42 → 72건 |
| B | 38.8만 → 0.8만 | 6.3만 → 0.7만 | 1.6만 → 0.5만 | 36 → 83 → 86건 |
숫자는 토큰 수이며, 아무것도 붙이지 않은 /compact를 사용했을 때의 값입니다. 1회차에는 20~40만 토큰의 대화를 1만 전후로 줄였습니다. 2회차에 요약되는 것은 '1회차 요약'과 '그 뒤의 대화'를 합친 것입니다.
세어본 내용은 제가 그 시점까지 제시한 지시나 결정 사항이 요약 뒤에서 읽을 수 있는지 여부입니다. 대화마다 18개 항목을 선택하여, 요약할 때마다 별도로 작동시킨 Claude에게 채점하게 했습니다. 같은 절차를 3번씩 반복했습니다.
확인 범위는 한 명의 사용자(저)가 진행한 한국어 대화이며, 요약 모델은 Opus 5.5만 사용했습니다. 확인한 것은 요약 뒤에 작성되어 있는지 여부입니다. 그 이후의 Claude가 그대로 작동하는지까지는 보지 않았습니다.
실험 조건과 채점 방법
조건
- 요약은 Claude Code의
/compact 기능 자체입니다. 모델은 Opus 5.5로 고정했습니다. 생각하는 깊이(effort)는 지정하지 않았으며, Claude Code에 내장된 값입니다.
- 실험 시 사용자 설정이나 메모리,
CLAUDE.md
를 새로 읽게 하지는 않았습니다. 대화 기록에 원래부터 포함되어 있던 내용은 그대로입니다. - Claude Code 버전은 2.1.319와 2.1.321입니다. 내장된 요약 지시문이 두 버전에서 한 글자도 틀리지 않음을 확인했습니다. "자동의 경우"로 시도한 부분만 2.1.322입니다.
채점 기준(採点の区分)
- 정확히 남은 것: 현재 상태와 어디에 효과가 있는지 파악할 수 있다. -
- 사라진 것: 아무데도 쓰여 있지 않다. -
- 인용만 된 것: 발언 자체는 올라와 있지만, 지금도 유효한지, 어떤 내용인지 파악하기 어렵다. -
- 오래된 그대로: 철회했거나 끝난 것이 현재도 유효한 것처럼 작성되어 있다. -
- 범위가 확장된 것: 그 자리의 이야기였던 것이 영구적인 규칙처럼 작성되어 있다.
이 외에, 제가 언급하지 않은 결정사항을 추가로 기록한 경우도 계산했습니다.
채점자(採点者)
채점은 방식의 이름을 숨기고, 별도로 구동한 Claude(Opus 5.5)에게 맡겼습니다. "대책" 부분에서 언급되는 두 가지 방식(기계적으로 가져오는 형태와 프롬프트로 다시 작성하게 하는 형태)은 나중에 만들었기 때문에, 각각 다른 채점 담당 Claude가 채점했습니다. 이전 채점과 기준이 어긋나지 않는지 보기 위해, 채점이 완료된 요약본을 6개씩, 그리고 그것과 구별할 수 없는 형태로 섞었습니다. 이전 채점과 완전히 일치한 비율은 각각 89%와 95%였고, "사라짐/사라지지 않음"의 일치율은 95%와 99%였습니다.
compact가 놓치는 것은 무엇인가요
한 번의 요약으로 전체가 이 정도 손실됩니다
우선, 전반적인 이야기입니다. 아무것도 추가하지 않는 /compact는 단 한 번만으로도 정보를 누락합니다. 첫 번째 요약 이후를, 제 지시 외로도 계산해 보았습니다.
| 계산 항목 | 첫 번째 요약 이후 |
|---|
| 작업을 계속하는 데 필요한 사실(완료된 것, 남아있는 작업, 수용된 안의 내용 등) | 명확하게 쓰여 있음 70%, 일부만 23%, 없음 7% |
| ... | |
| 사실의 3할은 누락되거나 사라졌습니다. 파일명이나 ID는 대화 A에서 3~5할, 대화 B에서 약 8할이 사라졌습니다. "한 번이라도 compact를 실행하면 잊힐 수 있다"라는 체감은 숫자와 같습니다. | |
이 표의 계산 방법
- 요약: 대화 A와 B 각각에 대해 첫 번째 요약을 3회 실행했습니다(총 6건). -
- 사실: 첫 번째 요약보다 앞서 언급된 14개 항목(대화 A 6개, B 8개)을 해당 대화의 요약본 3개로 채점했습니다. 총 42개 항목입니다. 별도로 구동한 채점 담당 Claude 2개가 모두 채점했으며, 판정이 일치한 것은 42개 항목 중 39개였습니다. 표에 나온 비율은 두 개를 합친 84건의 판정에서 나왔습니다. -
- 파일명이나 ID: 채점자를 사용하지 않고, 문자열이 요약본에 포함되는지 여부를 프로그램으로 계산했습니다(대화 A 28건, B 57건). 범위는 3개 요약본 중 최소값과 최대값입니다.
하지만 제가 내린 지시는 첫 번째 요약에서는 사라지지 않았습니다
그중에서도, 제가 직접 제시한 지시사항만은 첫 번째 요약에서 단 한 건도 사라지지 않았습니다. 사라지기 시작하는 것은 두 번째부터입니다.
| 사라진 지시 비율 | 첫 번째 이후 | 두 번째 이후 | 세 번째 이후 |
|---|---|
| 대화 A | 0% | 24% | 33% |
| 대화 B | 0% | 18% | 57% |
세 번째까지 사라진 것은, 예를 들어 다음과 같은 발언들입니다.
버그 수정 우선으로
디자인이 이상해지지 않도록만 주의해 주세요
둘 다 짧은 한마디이지만, Claude와의 대화 흐름 속에서는 명확한 지시였습니다. 3번 반복하는 절차를 3번 다시 수행했을 때, 첫 번째는 모두 사라졌고, 두 번째는 2번 사라지고 1번은 남았습니다. 사라질지 여부는 요약할 때마다 달라집니다.
첫 번째에서 사라지지 않는 것은 제 체감과는 달랐습니다. 한 번이라도 요약이 들어가면 결정했던 것을 잊을 수 있다는 느낌이었기 때문입니다. 숫자로부터 추론할 수 있는 이유는 두 가지가 있습니다.
사라졌다고 느끼는 내용 중 상당수는 지시 사항이 아니었습니다. 어떤 파일을 수정했는지, 무엇이 완료되었고 무엇이 남아있는지 등과 같은 사실이나 파일명은 위 표에서 볼 수 있듯이 1회차부터 누락됩니다. 지시가 남아있더라도 경위를 다시 설명해야 합니다.
- 긴 작업에서는 요약이 한 번으로 끝나지 않습니다. 요약은 자신도 모르는 사이에 여러 번 들어갑니다. 지시 사항이 사라지는 것은 그 두 번째부터입니다.
원인은 이전 회차의 발언을 가져오지 않았기 때문이었다
실험에 앞서 저는 이렇게 생각했습니다. 제 발언은 짧고, 이전 문맥에 의존하고 있습니다. 대화 A에서는 72건의 발언을 합쳐도 3,403자이며, 건당 50자에 미치지 못합니다. '일본어로', 'A로 괜찮아'와 같은 한마디가 많습니다. 요약하는 입장에서 보면 어떤 것이 중요한 결정인지 구별하기 어렵습니다. 그래서 누락되는 것일 거라고 생각했습니다.
아무것도 추가하지 않은 요약 내용을 세어보니, 달랐습니다.
Claude Code의 요약에는 원래 'All user messages(사용자 발언 목록)'라는 항목이 있습니다. compact 역시 제 발언들을 나열하려고 노력하고 있는 것입니다. 그래서 제 발언 중 몇 건이 요약에 그대로 문장으로 포함되어 있는지 세어보았습니다.
会話 A で、要約のあとに私の発言がそのまま載っている件数。何も付けない要約は 1 回目のあと 23 件中 18 件、2 回目のあと累計 41 件中 15 件、3 回目のあと累計 71 件中 29 件で、載っているのはどれもその回に新しく入った発言。発言を全部持ち越す形は 23 件、41 件、71 件のすべて
| 요약 회차 | 대화 A: 이번 회차에 새로 추가된 발언 | 대화 A: 그 이전의 발언 | 대화 B: 이번 회차에 새로 추가된 발언 | 대화 B: 그 이전의 발언 |
|---|
| 1회차 | 23건 중 18건 | — | 34건 중 30건 | — |
| 2회차 | 18건 중 15건 | 23건 중 0건 | | |
| 47건 중 45건 | 34건 중 0건 | | | |
| 3회차 | 30건 중 29건 | 41건 중 0건 | | |
| 2건 중 2건 | 81건 중 0건 | | | |
(6자 미만의 발언은 다른 문장의 일부로 우연히 일치할 수 있으므로 제외했습니다. 따라서 건수는 '실험 방법' 표(제 발언의 누계)보다 약간 적습니다. 3회 실행한 것 중 1회분만으로도 나머지 2회차와 거의 같습니다. 그림 오른쪽은 다음 항목에서 설명할 대책의 형태입니다.)
이번 회차에 새로 추가된 발언들은 짧은 한마디를 포함하여 대부분 그대로 포함되어 있었습니다. 요약이 짧은 발언을 구별하지 못해서 누락시키는 것이 아니었습니다. 1회차에서 지시가 사라지지 않는 이유가 이것입니다.
반면, 그 이전의 발언은 단 하나도 그대로 남아있지 않았습니다.
즉, 요약은 해당 회차의 발언은 남깁니다. 하지만 이전 요약에 포함되어 있던 목록을 다음 요약으로 복사하지 않습니다. 2회차 요약이 읽는 것은 1회차 요약이지만, 거기에 있었던 발언 목록은 '이전 이야기'로 본문에 재정리됩니다. 이때 포착되지 못한 결정 사항은 이미 어디에도 남지 않게 됩니다.
대화가 길어졌기 때문에 사라진 것일 수도 있다고 생각했습니다. 그래서 같은 대화를 3회차 지점까지 진행한 후, 요약을 단 한 번만 거쳤을 때의 결과와 비교해 보았습니다.
| 사라진 지시 (총 54 항목 중) | 1회만 요약했을 경우 | 3회 누적 요약 시 |
|---|---|
| 대화 A | 0건 | 18건 |
| 대화 B | 2건 | 31건 |
길이는 같지만, 크게 사라진 것은 누적했을 때뿐이었습니다. 1회만 요약을 거쳤을 때도 대화가 이렇게 길어지면 약간은 사라집니다(대화 B의 2건).
대책: 발언을 원문 그대로 전부 가져오기
원인이 '가져오지 않는 것'이라면, 대책은 '가져오는 것'입니다. 제 추측은 틀렸지만, 생각했던 대책(발언 전체를 다음 회차로 전달하는 방식)이 실제 원인에 정확히 효과를 발휘했습니다.
발언을 가져오는 방식은 두 가지를 시도했습니다.
기계적으로 가져오기: 프로그램이 대화 기록에서 제 발언을 추출하여 요약에 붙여 다음으로 전달하는 방식. 확장 기능에 넣은 것이 이것입니다. -
프롬프트로 작성하게 하기: /compact 뒤에 발언 전체를 원문 그대로 복사하고, 이전 요약에 있던 내용도 복사하도록 요청하는 프롬프트를 추가하기만 합니다. 프로그램은 사용하지 않습니다.
| 사라진 지시 비율 | 1회차 이후 | 2회차 이후 | 3회차 이후 |
|---|---|
| 아무것도 추가하지 않은 요약 (대화 A) | 0% | 24% | 33% |
| ... |
어떤 방식이든, 3회 누적했을 때 사라진 지시는 0건이었습니다. 발언이 그대로 포함되어 있기 때문에 당연한 결과였습니다.
상세 결과 (정확히 남은 % / 사라진 %)
총 3회 실행한 결과입니다. 항목 수는 해당 회차까지 제가 제시했던 지시 사항만을 계산했습니다. '정확히 남은 것'과 '사라진 것'을 합쳐도 100%가 되지 않는 부분은 각각 '인용만', '이전 그대로', '범위 확장'에 해당합니다. '결정 목록'은 AI에게 결정 목록 작성을 맡기는 설계입니다(본 절의 '추가로 시도한 설계'에서 설명하겠습니다). '비교용'은 비교를 위해 만든 형태로, 아무것도 첨가하지 않은 요약에 발언 원문을 붙인 것뿐입니다. 기계적으로 내용을 가져오는 형태와 달리, 요약 부분의 단락 구성을 변경하라고 요청하는 문장이나 긴 발언을 생략하는 처리는 없습니다.
대화 A
| 회차 | 항목 수 (3회 누적) | 아무것도 첨가하지 않은 요약 | 결정 목록 | 비교용 | 기계로 가져오는 형태 | 프롬프트로 필사시키는 형태 |
|---|
| 1 | 24 | 100 / 0 | 100 / 0 | 100 / 0 | 100 / 0 | 100 / 0 |
| ... | | | | | | |
대화 B
| 회차 | 항목 수 (3회 누적) | 아무것도 첨가하지 않은 요약 | 결정 목록 | 비교용 | 기계로 가져오는 형태 | 프롬프트로 필사시키는 형태 |
|---|
| 1 | 18 | 89 / 0 | 89 / 0 | 89 / 0 | 94 / 0 | 94 / 0 |
| ... | | | | | | |
'정확히 남은 것'은 채점자에 따라 몇 포인트씩 변동합니다. 발언을 가져오는 세 가지 형태 사이의 차이는 방식의 차이라고 단정하기 어렵습니다. '사라진 것'은 채점자 간 일치도가 95~99%로, 움직이기 어려운 수치입니다.
확장 기능에 적용한 메커니즘
아이디어는 하나이며, AI가 작성하는 부분을 줄이는 것입니다.
- 요약 자체는 compact에게 맡깁니다. 첨가하는 것은 요약의 기존 단락 구성을 변경하지 않도록 요청하고, 제목을 독립된 행에 쓰라고 요청하는 한 문장뿐입니다. 무엇을 남길지는 지시하지 않습니다. -
- 제 발언은 대화 기록에서 기계적으로 추출합니다. 요약 AI에게 필사시키는 것이 아니라, 프로그램이 기록을 읽어 사용자 발언만을 시간과 함께 추출합니다. AI의 손을 거치지 않기 때문에 의역이나 누락이 발생하지 않습니다. -
- 이전 회차까지의 발언도 모두 가져옵니다. 아무것도 첨가하지 않은 요약에서 부족했던 부분이 바로 이 지점입니다. -
- 긴 발언만 중간 부분을 생략합니다. 1건이 1000자를 초과하는 발언(로그나 코드 붙여넣기 등)은 시작 부분과 끝 부분만 남깁니다. 생략된 부분에는 몇 글자를 생략했는지, 그리고 전문은 원본 기록에 있음을 기재합니다. -
- 요약 뒤에 발언 목록을 첨부하여 전달합니다. 이때 읽는 법(풀이)을 덧붙입니다.
첨부하는 풀이는 다음 세 가지입니다.
- 사용자 발언은 시간 순서의 원문이며, 의역하지 않았습니다. 언어 사용과 의도는 이 원문을 기준으로 합니다.
- 다만, 각 결정이 현재 어떻게 되어 있는지(유효/철회/미실시)는 요약 부분에서 판단합니다. 원문에는 나중에 철회된 발언도 포함되어 있습니다.
- 원문과 요약 내용에 차이가 있다면 사용자에게 확인을 요청합니다.
요약과 원문에 각각 다른 역할을 부여했습니다. 무엇을 말했는지는 원문, 현재 어떻게 되어 있는지는 요약입니다.
추가로 시도한 설계: AI가 결정 목록을 작성하게 하는 방식
발언의 원문을 전달하는 대신, 요약할 때 AI에게 결정 목록을 작성하도록 하고 건별로 '누가 결정했는지'를 기재하게 하는 설계도 시도했습니다. 아무것도 첨가하지 않은 요약보다는 남아있었지만(3회에 걸쳐 사라진 지시는 대화 A에서 20%, 대화 B에서 26%), 제가 말하지 않은 결정이 '사용자가 결정했다'는 목록에 포함되는 경우가 있었습니다(1~3회 누적 합계로, 대화 A에서 5건, 대화 B에서 6건. 아무것도 첨가하지 않은 요약에서는 0건).
AI에게 작성하게 한 목록은 AI가 작성한 필사본입니다. 원문과 비교할 수 있는 한, 정확한지 알 수 없습니다. 필사본이 늘어나면 그 자체로 오래된 버전으로 남아 이후 작업에 방해가 된다는 점은 이전 기사에서도 언급했습니다. 그래서 목록 작성을 중단하고 발언의 원문을 그대로 전달하는 형태로 변경했습니다.
프롬프트 1개로 시도할 경우
확장 기능을 넣지 않아도 같은 실험을 할 수 있습니다. 요약을 직접 하는 경우와 자동으로 들어오는 경우에 따라 프롬프트를 붙이는 방식이 다릅니다.
수동의 경우
앞서 제시한 프롬프트를 맨 앞의 /compact마다 복사하여 실행합니다. 요약할 때마다, 매번입니다. 도중에 자동 요약이 들어오면 그 회차는 아무것도 첨가하지 않은 요약과 같은 움직임을 보입니다. 작업량이 많은 경우에는 다음 '자동의 경우' 설정도 함께 넣어주세요.
실험에 사용된 것은 바로 그 문구 자체입니다. 핵심은 세 번째 문장인 “이전 요약에 같은 섹션이 있다면, 그 내용을 모두 그대로 맨 앞에 복사하여 붙여넣는다”입니다. 아무것도 추가하지 않는 요약 방식으로는 전달되지 않았던 정보를 전달하도록 요청하고 있습니다.
대화 A와 B에서는 18개의 요약(2개 대화 × 1~3차 × 3회) 모두에서, 제 발언은 공백의 차이를 제외하고는 전부 원문 그대로 포함되었습니다 (3차 시점 기준 72건과 86건).
자동 방식일 경우
자동으로 생성되는 요약에는 /compact처럼 뒤에 내용을 추가할 수 없습니다. 방법은 두 가지가 있습니다.
CLAUDE.md 파일에 작성하기. 프로젝트의 가장 상단 폴더에 있는 CLAUDE.md 파일에 “Compact Instructions”라는 섹션을 만들고, 그곳에 프롬프트를 작성합니다.```
Compact Instructions
요약의 마지막에 “사용자 발언 (원문)”이라는 섹션을 추가한다. 여기에 이 대화에서 사용자가 보낸 발언을 처음부터 끝까지 순서대로, 한 건도 빠짐없이, 의역하지 않고 원문 그대로 복사하여 붙여넣는다. 이전 요약에 같은 섹션이 있다면, 그 내용도 모두 그대로 맨 앞에 복사하여 붙여넣는다. 한 건의 발언이 1000자를 초과하는 경우만, 앞부분과 뒷부분을 남기고 중간 부분을 생략해도 좋다. 그 외의 섹션은 평소대로 작성한다.
대화 시작부터 이 섹션이 존재하는 상태에서, 대화 A의 첫 번째 요약 위치에 자동 요약을 넣도록 설정하자, 24건의 발언이 모두 원문 그대로 포함되었습니다. 수동 방식과 동일한 결과입니다.
다만, 대화 중간에 추가할 경우 다음 요약까지는 반영되지 않았습니다. 발언 섹션은 생성되지 않았고, 원문 그대로 포함된 건수는 24건 중 19건이었습니다. `CLAUDE.md` 파일은 대화를 시작할 때 읽히며, 다음에 다시 읽히는 시점은 요약 이후이기 때문입니다. `CLAUDE.md`에 작성할 때는 대화를 시작하기 전에 미리 적어둡니다.
**반드시 전달되게 하려면, hook을 사용한다.** Claude Code에는 요약 직전에 작동하는 hook(PreCompact)이 있으며, 이 hook이 출력한 문구는 요약에 추가되는 프롬프트로 사용됩니다 (공식 설명). 프로젝트의 `.claude/settings.json` 파일에 다음과 같이 작성합니다. 이미 이 파일이 존재하는 경우, `hooks` 안에 `PreCompact` 항목을 추가합니다 (`PreCompact`가 이미 있다면 그 옆에 하나를 더 추가하고, `hooks` 자체가 없다면 `hooks` 전체를 추가합니다).
{
"hooks": {
"PreCompact": [
...
프롬프트는 `.claude/compact-prompt.txt` 파일에 저장해 둡니다.
요약의 마지막에 “사용자 발언 (원문)”이라는 섹션을 추가한다. 여기에 이 대화에서 사용자가 보낸 발언을 처음부터 끝까지 순서대로, 한 건도 빠짐없이, 의역하지 않고 원문 그대로 복사하여 붙여넣는다. 이전 요약에 같은 섹션이 있다면, 그 내용도 모두 그대로 맨 앞에 복사하여 붙여넣는다. 한 건의 발언이 1000자를 초과하는 경우만, 앞부분과 뒷부분을 남기고 중간 부분을 생략해도 좋다. 그 외의 섹션은 평소대로 작성한다.
이 설정으로도 같은 위치에서 자동 요약이 들어가도록 했을 때, 24건 모두 원문 그대로 포함되었습니다. hook의 출력물은 자동 요약이 발생할 때마다 요약 프롬프트에 추가됩니다. 수동 `/compact` 방식에는 기존처럼 직접 추가합니다. 설정을 마친 후에는 대화를 처음부터 다시 시작하여 사용해 주세요. hook은 작동 흔적을 남기지 않으므로, 첫 번째 자동 요약 이후에 요약에 “사용자 발언 (원문)” 섹션이 있는지 확인해 보세요. 명령어에 `cat`을 사용하므로 Windows에서는 Git Bash가 필요합니다.
### 발언이 많은 대화에서는 오류 발생
발언이 더 많아도 같은지, 수동 방식에 대해 다른 실제 대화(대화 C)로 확인했습니다. 발언은 133건이며, 총 약 12,000자입니다. 다른 AI의 조사 결과를 붙여넣은 긴 발언도 포함되어 있습니다. 마찬가지로 요약을 3번 반복하고 두 가지 방식을 각각 한 번씩 실행했습니다.
프롬프트로 복사하도록 지시한 방식은 발언이 45건이었던 첫 번째 이후에는 모두 포함되었습니다. 오류가 발생한 것은 발언이 114건이 된 두 번째였습니다. 세 번째 이후의 결과는 다음과 같습니다.
| 관찰된 내용 | 프롬프트로 작성하게 하는 방식 | 기계적으로 전이하는 방식 |
|---|---|---|
| 133건 중 그대로 포함된 발언 | 129건 | 133건 |
| ... |
崩れたのは 133件中 4 件で、数は多くありません。ただ、中身がよくありません。
-
**누락된 발언은 되돌릴 수 없습니다.** 2번째에서 누락된 1건은 3번째에서도 그대로 누락되어 있었습니다. 다음 회차는 이전 목록을 단순히 복사하는 것이기 때문입니다.
- **삭제한 부분에 AI의 의역이 들어갑니다.** 원문 그대로 전달해야 할 문단에 AI가 작성한 요약이 섞였습니다.
- **프롬프트가 지켜지지 않았습니다.** 제외해도 되는 발언은 1000자 초과만으로 제한했는데, 888자와 610자의 발언도 삭제되었습니다.
작성하는 주체가 AI인 이상, 발언이 늘어날수록 누락되지 않다는 것은 보장할 수 없습니다.
### 두 가지 방식의 차이점
| 프롬프트로 작성하게 하는 방식 | 기계적으로 전이하는 방식 | |
|---|---|
| 필요한 것 | 프롬프트 1개 | 프로그램 (확장 기능) |
| ... |
크기는 3회 실행한 중앙값입니다. 기계적으로 전이하는 방식은 요약의 크기에, 추가로 전달할 분량을 따로 측정하여 더했습니다.
아무것도 추가하지 않은 요약은 대화 A에서 약 7,000 토큰, 대화 B에서 약 4,600 토큰입니다. 프롬프트로 작성하게 하는 방식은 발언을 추가했음에도 불구하고 아무것도 추가하지 않은 요약과 거의 같은 크기였습니다. 이는 발언 목록을 추가한 만큼 요약의 다른 부분이 짧아졌기 때문으로 보입니다. 대화 A의 3번째에서는 'Primary Request and Intent (요청 및 의도)' 섹션이 약 2,000자에서 약 400자로 줄어들었습니다.
줄어든 부분에 지시 외 정보가 줄지 않았는지 확인했습니다. 지시와 별개로 작업을 계속하는 데 필요한 사실을 대화마다 15건씩 수집하여, 3번째 요약 후 계산해 보니 '분명히 쓰여 있음'의 비율은 아무것도 추가하지 않은 요약이 49%였던 것에 비해, 프롬프트로 작성하게 하는 방식은 43%였습니다. 차이는 작고 변동 범위 내입니다. 다만, 'Claude가 제시하고 제가 수용한 안의 내용'에 한정하면, 50% 대비 33%로 낮게 나왔습니다. 기계적으로 전이하는 방식은 이 부분에서도 50%를 기록하여 아무것도 추가하지 않은 요약보다 떨어지지 않았습니다 (전체는 56%).
## 요약이 짧아진 만큼 줄어든 것은 무엇인가
원 대화에서 제가 지시한 것이 아니지만 작업을 계속하는 데 필요한 사실을 대화마다 15건씩 수집했습니다 (완료된 내용, 남아있는 작업 및 그 조건, Claude가 제시하고 제가 수용한 안의 내용, 현재 작업과 다음 단계). 정보를 수집하는 역할을 맡은 Claude에게는 요약을 보여주지 않았습니다. 이를 3번째 요약에서 채점했습니다. 채점 역할의 Claude 2개가 18개의 모든 요약을 채점했습니다 (총 270 항목, 완전 일치율 91%).
| 방식 | 분명히 쓰여 있음 | 일부만 | 없음 |
|---|---|
| 아무것도 추가하지 않은 요약 | 49% | 23% | 28% |
| ...
- '없음'은 발언을 전이하는 두 가지 방식 모두에서 크게 줄었습니다. 발언이 포함되어 있기 때문에, 적어도 주제에는 언급될 수 있습니다.
- 'Claude가 제시하고 제가 수용한 안의 내용'은 제 발언이 '그것으로'라는 식이라 요약이 내용을 작성하지 않으면 전달되지 않는 종류입니다.
- 기계적으로 전이하는 방식은 어떤 관점에서 보아도 아무것도 추가하지 않은 요약과 같거나 높았습니다. 요약 내용에 지시를 내리지 않았을 뿐만 아니라, 발언까지 포함되어 있기 때문입니다.
- 대화 초기의 사실은 모든 방식에서 약한 상태였습니다 ('분명히 쓰여 있음'이 19~26%).
저는 AI의 작성 능력에 좌우되지 않는 방식을 원했기 때문에, 기계적으로 전이하는 방식을 확장 기능으로 구현했습니다. 크기는 약 2배가 되지만, 대화가 길어져도 무너지지 않습니다. 발언이 적은 대화에서 먼저 시도해 보고 싶다면, 프롬프트 하나만으로 충분합니다.
## 원문을 가져와도 남아있는 약점
원문 전체를 가져온다고 해서 모든 것이 완벽하게 해결되는 것은 아니었습니다.
**인용은 있지만, 지금도 유효한지 알 수 없다.** 대화 B의 3번째에서는 기계적으로 전이하는 방식으로 20%, 프롬프트로 작성하게 하는 방식으로 19%가 이랬습니다. 예를 들어 '리치하게 하지 않아도 돼'라는 발언은 포함되어 있습니다. 하지만 무엇을 리치하게 하지 않는 것인지는 요약 부분에 쓰여 있지 않으면 알 수 없습니다. 발언 자체가 사라진 것은 아닙니다. 다만, 그것만으로는 사용할 수 없는 상태입니다. 짧고 문맥에 의존하는 발언의 약점은 떨어지는 곳이 아니라, 여기서 나타났습니다.
**취소된 내용이 반영되지 않는 경우가 있습니다.** 제가 처음에 결정했다가 나중에 취소한 건에 대한 사례가 대화 B에 있었습니다. 원문에는 결정한 발언과 취소한 발언 모두가 실려 있습니다. 그럼에도 불구하고, 기계적으로 가져오는 형태로는 세 번 모두 결정 사항이 유효한 상태로 작성되었습니다. 결정한 발언과 취소된 발언이 떨어져 나란히 배치되어 있어도, 요약에 쓰인 한 문장이 더 강하게 읽힙니다. 같은 사안이라도 아무것도 추가하지 않은 요약에서도 이전 내용으로 남아 있는 경우가 있었습니다. 하지만 프롬프트로 직접 작성하도록 요청한 세 번의 경우에서는 그렇지 않았습니다 (2번은 취소된 내용이 적혔고, 1번은 상태를 파악하기 어려웠습니다). 요약 작성 방식에 따라 나타나기도 하고 사라지기도 하는 약점입니다.
둘 다 원문과 요약을 연결하는 과정에서 발생하고 있습니다. 발언 자체를 누락하지 않는 것과, 발언의 현재 상태가 파악되는 것은 별개의 문제입니다. "모순이 발견되면 사용자에게 확인한다"는 방식은 이를 위한 보험입니다.
## 선행 연구와의 관계
이 실험과 병행하여 논문도 찾아보았습니다. 요약 과정에서 지시 사항이 누락되는 것 자체는 이미 측정된 바가 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63