OpenClaw 자동화

컨텍스트 창이 꽉 찼을 때 벌어지는 일|OpenClaw 컴팩션과 세션 프루닝 구분하기

깊음위에 2026. 9. 27. 08:22

AI 에이전트를 며칠 붙잡고 쓰다 보면 어느 순간 반응이 이상해집니다. 앞에서 한 얘기를 잊거나, 갑자기 "컨텍스트가 너무 길다"는 오류가 나거나, 같은 질문인데 토큰 비용이 훌쩍 뜁니다. 대화가 길어졌다는 신호인데, 여기서 시스템이 뭘 하고 있는지 모르면 그냥 새 대화를 파는 것 말고는 손쓸 방법이 없습니다.

OpenClaw는 이 문제를 컴팩션(compaction)과 세션 프루닝(session pruning) 두 가지로 나눠서 다룹니다. 이름이 비슷해서 헷갈리는데, 하는 일도 다르고 저장되는 방식도 다릅니다. 이 글은 OpenClaw 공식 문서의 concepts/compaction과 concepts/session-pruning 문서를 한국어 독자용으로 풀어 정리한 해설입니다. 출처는 docs.openclaw.ai이고, 제가 특정 구성에서 직접 측정한 성능 수치는 들어 있지 않습니다.

먼저 둘의 차이부터

문서에 아예 비교표가 있습니다. 이것만 머리에 넣어도 절반은 정리됩니다.

  컴팩션 프루닝
무엇을 하나 오래된 대화를 요약 오래된 도구 결과를 잘라냄
저장되나 예 — 세션 트랜스크립트에 남음 클라이언트 측 projection으로 유지, 서버 측 clearing은 로컬 원본 보존
범위 대화 전체 도구 결과만

즉 컴팩션은 "요약해서 줄이기"이고, 프루닝은 "도구가 뱉은 긴 출력만 도려내기"입니다. 일반 대화 문장은 프루닝이 건드리지 않습니다. 문서 표현으로는 둘이 경쟁 관계가 아니라 보완 관계라서, 프루닝이 컴팩션 주기 사이의 도구 출력을 가볍게 유지해 주는 구조입니다.

컴팩션이 실제로 하는 일

순서는 단순합니다. 오래된 대화 턴을 요약 항목 하나로 압축하고, 그 요약을 세션 트랜스크립트에 저장하고, 최근 메시지는 그대로 둡니다. 여기서 중요한 단서가 몇 개 붙습니다.

  • 도구 호출과 결과는 쪼개지 않습니다. 분할 지점이 도구 블록 한가운데 떨어지면 OpenClaw가 경계를 옮겨서 어시스턴트의 도구 호출과 짝인 toolResult가 같이 남게 합니다. 짝이 깨진 기록이 모델에 들어가지 않게 하려는 처리입니다.
  • 한국어가 고려돼 있습니다. 내장 요약기는 청크 크기를 추정할 때 메시지 본문과 도구 인자 양쪽에서 한중일(CJK) 문자를 감안합니다. 다만 문서는 이 예산이 어디까지나 근사치이고, 도구 호출과 그 결과 묶음은 청크 목표를 넘겨도 함께 유지된다고 못 박습니다.
  • 원본은 안 지웁니다. 전체 대화 기록은 디스크에 그대로 남습니다. 컴팩션이 바꾸는 건 다음 턴에 모델이 보게 될 것뿐입니다.
  • 이미지는 요약기에 들어가지 않습니다. 내장 요약은 픽셀이 아니라 텍스트를 받습니다. 빠진 이미지 자리에는 [image data omitted from summary input] 같은 마커가 들어가고, 모델이 그 데이터를 처리한 것처럼 꾸미지 않습니다. 영향받은 앞쪽 8개 메시지는 최대 두 개씩, 그 뒤로는 집계 문장 하나로 처리되며, 이렇게 덧붙는 분량은 요약 요청당 최대 847 UTF-8 바이트로 제한됩니다.

자동 컴팩션과 오버플로 복구

자동 컴팩션은 기본으로 켜져 있습니다. 세션이 컨텍스트 한계에 가까워질 때 돌고, 모델이 컨텍스트 초과 오류를 반환했을 때도 압축한 뒤 재시도합니다.

개인적으로 이 문서에서 가장 인상적인 대목은 도구가 이미 실행된 뒤에 거부당한 경우의 처리입니다. 프로바이더가 도구 호출 완료 이후 요청을 거절하면, 내장 런타임은 기록된 결과에서부터 이어갑니다. 모델과 계정을 그대로 두고, 원래 요청을 보존하며, 이미 끝난 동작을 다시 실행하지 않습니다. 파일을 쓰거나 메일을 보내는 도구를 붙여 놓은 상황이라면 이 한 줄이 꽤 큰 차이입니다. 단, 이 복구는 결과가 확정된 도구에만 적용되고 대기 중인 도구·승인·취소·의도적으로 턴을 끝낸 도구는 원래 규칙을 따릅니다.

실행을 중지하면 그 복구도 같이 멈춥니다. 다만 취소는 롤백이 아닙니다. 이미 완료된 컴팩션은 트랜스크립트에 남고 횟수에도 계속 반영되며, 늦은 답변만 보내지 않습니다.

돌고 있는지 확인하는 방법도 문서에 있습니다. 게이트웨이 로그의 embedded run auto-compaction start / complete, verbose 모드의 🧹 Auto-compaction complete, 그리고 /status에 뜨는 🧹 Compactions: <count>입니다.

끄고 싶다면 agents.defaults.compaction.enabled: false입니다. 이건 임계값 기반의 선제적 컴팩션과 선택적 유지보수를 끄는 것이고, 오버플로 복구 컴팩션과 수동 /compact은 그대로 남습니다. 완전히 끄는 스위치가 아니라는 점을 알고 써야 합니다.

safeguard 모드가 기본값이다

새로 만드는 설정은 agents.defaults.compaction.mode가 "safeguard"로 시작합니다. 더 엄격한 가드레일과 요약 품질 감사가 붙은 모드이고, 빠지려면 mode: "default"를 명시해야 합니다.

safeguard가 켜져 있으면 최종 요약 예산을 검증 전에 적용합니다. 필요한 제목들은 남은 본문 안에 있어야 하고, 미결 질문과 정확한 식별자는 실제로 저장될 텍스트에 그대로 남아 있어야 합니다. 검증을 통과 못 하면 설정된 횟수만큼만 교정을 시도하고, 끝내 통과하는 요약이 없으면 트랜스크립트에 쓰기 전에 컴팩션을 중단하고 원본 히스토리를 유지합니다. 망가진 요약으로 대화를 덮어쓰느니 안 하고 만다는 쪽입니다.

식별자 보존은 별도 옵션으로도 있습니다. compaction.identifierPolicy가 기본 "strict"라서 불투명한 ID들이 요약 과정에서 살아남습니다. 티켓 번호나 세션 키를 다루는 작업이라면 이걸 "off"로 내리지 않는 편이 낫습니다.

수동 /compact, 그리고 흔한 오해

어느 채팅에서든 /compact를 치면 강제로 압축합니다. 뒤에 지시를 붙여 요약 방향을 잡을 수도 있습니다.

/compact Focus on the API design decisions

이 포커스 문구는 오래된 히스토리 요약과 분할 턴 앞부분 요약 양쪽에 전달됩니다. 호스트는 운영자가 넣은 포커스를 800 유니코드 코드포인트로 제한하고 프롬프트 데이터로 이스케이프한 뒤 모델 요청에 넣습니다. 즉 여기에 명령을 심는 식의 사용은 막혀 있습니다. 수동 컴팩션은 compaction.keepRecentTokens(기본 20,000)를 컷 지점 예산으로 삼아 그만큼의 최근 꼬리를 재구성된 컨텍스트에 남깁니다.

요약만 다른 모델에 맡기는 것도 됩니다. compaction.model에 provider/model-id 문자열이나 설정해 둔 별칭을 넣으면 됩니다. 로컬 모델도 가능해서 요약 전용으로 Ollama 모델 하나를 따로 두는 예시가 문서에 나옵니다.

{
  "agents": {
    "defaults": {
      "compaction": {
        "model": "ollama/llama3.1:8b"
      }
    }
  }
}

여기서 문서가 직접 경고하는 오해가 하나 있습니다. 요약 모델을 더 큰 걸로 고른다고 전경 모델의 컨텍스트 창이 커지지는 않습니다. 요약을 잘하게 만드는 것과 대화가 들어갈 그릇을 키우는 건 별개입니다.

컴팩션 직전의 메모리 플러시

압축하기 전에 OpenClaw는 조용한 메모리 플러시 턴을 돌려서 오래 남길 메모를 디스크에 저장할 수 있습니다. 요약으로 날아가면 아쉬운 내용을 파일 쪽으로 옮겨 두는 장치입니다. 이 housekeeping 턴만 로컬 모델로 돌리고 싶으면 compaction.memoryFlush.model을 지정합니다.

중요한 건 실패했을 때의 태도입니다. 메모리 플러시는 선택적 유지보수라서, 재시도를 다 써서 실패해도 세션을 초기화하거나 대화 기록을 버리지 않습니다. notifyUser를 켜 두면 이런 경우 "성능 저하" 알림이 뜨고 답변은 계속됩니다. 반대로 필수 컴팩션이 실패하면 OpenClaw는 그 실패를 보고하고 대화를 그대로 유지합니다. 혼자 알아서 처음부터 다시 시작하지 않습니다. 메모리 구조 자체가 궁금하시면 OpenClaw는 대화를 어떻게 기억할까?|메모리 구조와 드리밍 쉽게 이해하기를 먼저 보시면 이 문단이 훨씬 잘 읽힙니다.

세션 프루닝: 도구 결과만 도려내기

프루닝은 목표가 더 좁습니다. exec 결과, 파일 읽기, 검색 결과처럼 쌓이면 무거워지는 도구 출력만 줄입니다. 일반 대화 텍스트는 다시 쓰지 않습니다. 켜는 방법은 agents.defaults.contextPruning.mode를 "cache-ttl"로 두는 것이고, 실제로 어디서 잘리는지는 요청의 프로바이더·엔드포인트·인증 방식이 결정합니다.

Anthropic API 키 직결인 경우

프로바이더가 anthropic이고 anthropic-messages API에 API 키 인증, 기본 엔드포인트 또는 api.anthropic.com이면 OpenClaw가 프루닝을 Anthropic의 서버 측 도구 결과 clearing에 위임합니다. 클라이언트 쪽에서 새 프루닝 라운드를 열지 않고, 서버가 모델이 보기 전에 오래된 결과를 지웁니다. 이 경로에서는 ttl이 관여하지 않고 로컬 전체 히스토리는 그대로 남습니다. 요청 파라미터는 설정 옵션 없이 OpenClaw가 유도하는데, keep이 가장 최근 도구 사용 3건과 그 결과, clear_tool_inputs가 false라서 도구 호출 인자는 보존된다는 점만 알아도 감이 옵니다.

그 외 경로(클라이언트 측)

Bedrock, Google, Microsoft Foundry, OAuth, 프록시, Vertex 같은 나머지 경로는 클라이언트 측 프루닝을 씁니다. 새 라운드는 시간 조건과 크기 조건을 둘 다 넘겨야 돕니다.

  1. 캐시 TTL이 만료되기를 기다립니다. cache-ttl 모드를 켜고 ttl을 안 주면 5분입니다(번들 Anthropic 플러그인은 대신 1h를 심어 둡니다). 성공한 모델 요청마다 시계가 요청 시작 시각으로 갱신되고, 실패한 요청은 갱신하지 않습니다.
  2. TTL이 지나면 전체 컨텍스트 크기를 모델의 컨텍스트 창과 비교합니다. 대략 30% 미만이면 건너뜁니다.
  3. 소프트 트림 — 4,000자를 넘는 도구 결과는 앞 1,500자와 뒤 1,500자만 남기고 가운데를 ...로 바꿉니다.
  4. 그래도 사용량이 대략 50% 이상이고 잘라낼 도구 콘텐츠가 5만 자 이상 남아 있으면 하드 클리어로 내용을 자리표시자([Old tool result content cleared])로 대체합니다. hardClear.enabled: false로 이 단계만 뺄 수 있습니다.
  5. 바뀐 결과를 세션 projection으로 기록하고 TTL 시계를 리셋합니다.

여기서 안전장치 두 개는 임계값과 무관하게 항상 적용됩니다. 최근 어시스턴트 턴 3개는 절대 프루닝되지 않고, 세션의 첫 사용자 메시지 이전 내용도 절대 프루닝되지 않습니다. 두 번째는 SOUL.md, USER.md 같은 부트스트랩 읽기를 보호하려는 규칙입니다. 에이전트의 성격과 사용자 정보가 대화 도중에 슬그머니 증발하지 않는 이유가 여기 있습니다.

한 가지 더. 위에 나온 30%·50%·4,000자·1,500자 같은 수치는 설정 키가 아니라 내장 동작입니다. 손댈 수 있는 표면은 contextPruning의 mode, ttl, tools, hardClear뿐입니다. 어떤 도구 이름을 프루닝 대상으로 삼을지는 contextPruning.tools.allow / deny로 좁힙니다.

Anthropic을 쓰면 자동으로 켜진다

번들 Anthropic 플러그인은 Anthropic(또는 Claude CLI) 인증 프로필을 처음 해석할 때 프루닝과 하트비트 주기를 자동 설정합니다. 단, 사용자가 명시적으로 설정하지 않은 필드에만 적용됩니다.

인증 방식 contextPruning.mode ttl heartbeat.every
OAuth / 토큰 (Claude CLI 재사용 포함) cache-ttl 1h 1h
API 키 cache-ttl 1h 30m

직접 contextPruning.mode나 heartbeat.every를 적어 뒀다면 OpenClaw가 덮어쓰지 않습니다. 그리고 이 자동 기본값은 Anthropic 계열 인증에서만 발동합니다. 다른 프로바이더는 따로 설정하지 않는 한 프루닝이 off입니다. "왜 나는 컨텍스트가 계속 불어나지?" 싶을 때 먼저 볼 지점입니다.

증상별로 무엇을 만질까

  • 컴팩션이 너무 자주 돈다 → 모델 컨텍스트 창이 작거나 도구 출력이 큰 경우입니다. 세션 프루닝을 켜 보라는 게 문서의 권고입니다.
  • 컴팩션 후 맥락이 낡은 느낌이다 → /compact Focus on <주제>로 요약 방향을 잡거나, 메모리 플러시를 켜서 메모가 파일로 살아남게 합니다.
  • 그냥 깨끗하게 시작하고 싶다 → /new입니다. 압축하지 않고 새 세션을 엽니다.
  • 트랜스크립트 파일 자체가 계속 커진다 → compaction.maxActiveTranscriptBytes에 "20mb" 같은 값을 주면 히스토리가 그 크기에 닿을 때 정상 컴팩션을 먼저 돌립니다. 바이트를 기계적으로 자르는 게 아니라 의미 단위 요약을 요청하는 방식입니다.

정리

컴팩션은 대화를 요약해 트랜스크립트에 남기고, 프루닝은 도구 결과만 도려내며 원본은 보존합니다. 자동 컴팩션은 기본 on이고 safeguard 모드가 새 설정의 기본값이며, 실패할 때는 덮어쓰기보다 원본 유지를 택합니다. 프루닝은 Anthropic 계열이면 대체로 알아서 켜지고 나머지는 직접 켜야 합니다. 그리고 최근 어시스턴트 턴 3개와 첫 사용자 메시지 이전 구간은 어느 경우에도 지켜집니다.

같은 맥락에서 읽으면 좋은 글은 OpenClaw 서브에이전트란? 일을 나눠 맡길 때 권한·깊이·보고가 정해지는 규칙(긴 작업을 아예 다른 세션으로 떼어내는 방법)과 MCP 서버를 OpenClaw에 붙이는 법(도구를 늘릴 때 컨텍스트가 어디서 불어나는지)입니다. OpenClaw 자체가 처음이시면 OpenClaw란? 카톡·텔레그램으로 AI 에이전트를 부리는 셀프호스팅 게이트웨이부터 보시면 됩니다.

이 글의 모든 동작 설명과 수치는 OpenClaw 공식 문서 concepts/compaction·concepts/session-pruning(미러 docs.openclaw.ai)에 적힌 내용을 옮기고 풀어 쓴 것입니다. 제가 직접 벤치마크를 돌려 얻은 값이 아니고, 버전에 따라 기본값이 바뀔 수 있으니 실제 적용 전에는 설치본의 문서를 한 번 더 확인하시는 편이 좋습니다.