Auto-Compact가 제 제약 사항을 삼켜버렸습니다: 사후 분석 (Post-Mortem)
요약
AI 에이전트가 긴 작업을 수행할 때 자동 압축(auto-compact) 과정에서 중요한 제약 사항이 유실되는 문제를 분석합니다. 컨텍스트 압축 시 발생하는 정보 손실을 방지하기 위한 스펙 외부화 및 차별적 압축 전략을 제안합니다.
핵심 포인트
- 자동 압축 시 요약기가 핵심 제약 사항을 누락할 위험이 있음
- 제약 사항은 채팅 기록이 아닌 외부 구조화된 파일로 관리해야 함
- 압축 후에는 반드시 작업 스펙을 모델이 다시 읽도록 강제해야 함
- 정보의 중요도에 따라 무손실 압축과 차별적 압축 정책을 적용해야 함
AI 보조 작성 고지: Yixiao Wang가 사건 경위, 기술적 판단 및 최종 승인을 제공하였으며, 그의 AI 협업자인 Jibai가 초안 작성 및 편집을 보조했습니다.
사건부터 말씀드리겠습니다.
긴 작업이었습니다. 저는 에이전트(agent)에게 모듈 체인을 리팩터링(refactor)하도록 요청했고, 첫 메시지에 제약 사항을 명시적으로 기재했습니다 — "모듈 X를 건드리지 마세요; 하위 의존성(downstream dependents)이 있습니다." 첫 한 시간은 완벽했습니다. 하지만 2시간 이상이 지나고 수백 번의 도구 호출(tool calls)이 진행된 후, 에이전트는 X를 수정했습니다.
그것은 불복종도 아니었고, 지시 사항을 놓친 것도 아니었습니다. 추적(trace) 결과는 명확한 이야기를 들려줍니다: 자동 압축(auto-compact)이 실행되었을 때, 요약기(summarizer)가 제약 사항을 삼켜버린 것입니다. 압축된 컨텍스트(context) 내에서 "X를 건드리지 마세요"라는 문구는 단순히 존재하지 않게 되었습니다. 모델은 여전히 볼 수 있는 모든 것을 충실히 실행했습니다 — 문제는 모델이 더 이상 규칙을 볼 수 없게 되었다는 점입니다.
이 교훈은 기록할 가치가 있는 판단으로 일반화될 수 있습니다:
데모와 프로덕션(production) 사이의 간극은 대부분 모델의 문제가 아닙니다. 그것은 두 가지 하네스(harness) 문제, 즉 제약 사항의 지속성(constraint persistence)과 독립적 검증(independent verification)의 문제입니다.
데모에서는 작업이 10분 안에 끝나고, 컨텍스트가 넘치지 않으며, 모든 제약 사항이 윈도우(window) 안에 머뭅니다. 하지만 프로덕션에서는 작업이 수백 번의 턴(turn)에 걸쳐 몇 시간 동안 실행되며, 컨텍스트는 반드시 압축될 것입니다 — 컨텍스트는 휘발적이지만, 작업 제약 사항은 내구성이 있어야 합니다. 이 모순이 해결될 때까지, 모든 긴 작업은 복권과 같습니다.
해결책 #1: 스펙(spec)을 외부화하세요 — 압축 풀(compression pool)에 절대 넣지 마세요
제약 사항은 채팅 기록(chat history)에만 존재해서는 안 됩니다. 왜냐하면 채팅 기록이 바로 압축되는 대상이기 때문입니다. 저의 접근 방식은 다음과 같습니다: 작업 스펙을 네 가지 필드를 가진 구조화된 파일로 외부화하는 것입니다:
[locus: 시작 위치 — 파일/모듈 경로]
[signal: 무엇이 문제를 보여주는 증거인가 — 에러 로그 / 실패하는 테스트]
[done: 무엇이 완료로 간주되는가 — 검증 가능한 수락 기준(acceptance criteria)]
...
두 가지 메커니즘이 중요합니다: 스펙 파일(spec file)은 압축 풀(compression pool)에 절대 들어가지 않으며, 매 압축(compact)이 끝난 후 스펙을 강제로 다시 읽도록(re-read) 합니다. 채팅 기록이 아무리 엉망이 되더라도, "X를 건드리지 마시오"라는 지침은 매번 모델의 눈에 원문 그대로 전달됩니다.
해결책 #2: 압축은 차별화되어야 한다 — 일괄 요약 금지
Auto-compact의 기본 동작은 "오래된 내용을 일괄적으로 요약하는 것"입니다. 하지만 컨텍스트(context) 내 정보는 중요도가 극명하게 다릅니다. 올바른 방법은 카테고리별로 특화된 처리를 하는 것입니다:
| 정보 유형 | 압축 정책 |
|---|---|
| 작업 스펙(Task spec) 및 수락 기준(acceptance criteria) | 무손실 (Lossless) — 단 한 단어도 누락되지 않음 |
| ... |
실패한 시도(failed-attempts)에 대한 정책은 직관에 반할 수 있습니다. 너무 많이 남겨두면 잔류하는 잘못된 경로가 이후의 판단을 오염시켜, 모델이 자신의 과거 이력에 끌려가게 됩니다. 반대로 모든 것을 버리면 모델은 똑같은 막다른 길을 다시 걷게 될 것입니다. _결론만 남기는 것(Conclusion-only)_이 이 두 가지 해악 사이의 균형점입니다.
해결책 #3: 매 압축 후 일관성 자가 점검 수행
메커니즘은 매우 간단합니다: 각 압축이 끝난 후, 한 단계를 삽입합니다 — "현재 계획이 여전히 작업 스펙을 충족하는가? 한 줄씩 확인하라."
이는 수백 개의 토큰(token)을 소모하지만, 제약 사항의 이탈(constraint drift)을 사후 발견(사람이 피해를 목격함)에서 비행 중 차단(에이전트가 자신의 계획과 스펙이 불일치함을 인지함)으로 전환해 줍니다. 저는 이것을 긴 작업을 위한 재정렬 의식(re-alignment ritual)이라고 생각합니다:
인간도 3시간짜리 회의 중에는 논점이 흐려지곤 합니다. 그래서 우리는 의제(agenda)와 회의록(minutes)을 만들었습니다. 외재화된 스펙과 압축 후 자가 점검은 에이전트의 의제이자 회의록입니다.
부수적인 관찰: 컨텍스트는 양동이가 아니라 계층화된 예산이다
이번 실패를 겪은 후, 저는 긴 작업(long-task)을 위한 컨텍스트 전략을 재구축했습니다. 핵심적인 변화는 "계속 채워지는 하나의 양동이"를 각기 다른 규율을 가진 4개의 계층으로 교체한 것입니다:
- 고정 접두사 (Fixed prefix) (시스템 프롬프트 (system prompt) + 도구 정의 (tool definitions)): 안정적이고, 캐시 친화적(cache-friendly)이며, 수정되지 않음;
- 작업 명세 (Task spec): 상주하며 손실이 없고, 절대 압축되지 않음;
- 작업 기억 (Working memory) (현재 계획, 주요 결정): 구조화된 요약;
- 관찰 스트림 (Observation stream) (도구 출력): 공격적으로 가지치기(pruned) — 상주(residency) 대신 검색(retrieval) 방식 사용. 파일은 컨텍스트 창(window) 안에 머물지 않고, 로컬 인덱스(local index)에 존재하며 사용 시점에 가져옴(fetch).
진행 과정 중 한 가지 선택 사항: 데스크톱 시나리오에서의 로컬 검색을 위해, 테스트 결과 SQLite FTS5 + BM25가 벡터 데이터베이스 (vector database)보다 더 안정적이고, 저렴하며, 설명 가능(explainable)하다는 것을 발견했습니다. 전문 검색(full-text) 히트는 그 이유가 명확히 설명되지만, 벡터 검색(vector recalls)은 왜 결과가 나타났는지 설명하지 못하는 경우가 많습니다. 모든 시나리오에 임베딩 (embeddings)이 필요한 것은 아니며, 이러한 판단 덕분에 벡터 인프라 (vector-infra) 유지 관리 부담을 통째로 덜 수 있었습니다.
결론 (Closing)
장기 작업(Long-task)의 신뢰성은 더 큰 컨텍스트 창 (context windows)으로 해결되지 않습니다. 창이 아무리 크더라도 결국 압축이 실행되고 무언가는 누락됩니다. 이는 단 하나의 명확한 설계 원칙으로 해결됩니다:
휘발성인 것(대화)과 지속적인 것(명세)을 분리하고, 어떤 메커니즘도 후자의 수명을 전자에 종속시키지 마십시오.
_이 글은 Into the Harness 시리즈의 두 번째 포스트입니다. 관련 글: "Model + Harness = Agent: The Gap Isn't Where You Think."
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기