Codex가 컨텍스트를 절반 남겨 두고 자동 압축을 시작한다면, 화면에 보이는 사용량과 압축을 결정하는 수치가 서로 다른 계산을 쓰기 때문입니다. 2026-10-19 기준 Codex 0.163.0과 main 브랜치에는 이 차이가 그대로 남아 있습니다.
화면의 사용량과 압축 시점이 어긋나는 증상
Codex는 마지막 응답의 토큰 사용량과 컨텍스트 창을 화면에 보여 줍니다. 자동 압축은 그 값이 아니라 별도의 내부 카운터가 임계값을 넘을 때 시작됩니다. 두 수치가 벌어지면 창의 절반이 비어 있는데도 "Context compacted"가 뜹니다.
아래 표는 openai/codex 이슈에 2026-10-12부터 2026-10-18까지 올라온 보고에서 수치만 그대로 옮긴 것입니다.
| 화면 표시 사용량 | 표시된 컨텍스트 창 | 압축을 발동시킨 내부 카운터 | 자동 압축 임계값 | 보고 |
|---|---|---|---|---|
| 456,201 | 828,400 (약 55%) | 790,681 | 784,800 | #53309, 2026-10-13 |
| 307,156 | 486,400 (약 63%) | 465,647 | 460,800 | #53309, 2026-10-13 |
| 483,523 | 828,400 (약 58%) | 787,812 | 784,800 | #53309, 2026-10-16 |
| 486,150 | 997,500 (약 49%) | 954,222 | 945,000 | #55126, 2026-10-18 |
네 사례 모두 화면 표시 사용량은 임계값의 51~67% 수준인데 내부 카운터는 임계값을 넘겼습니다. 내부 카운터는 표시값에 과거 추론 토큰 추정치를 더한 값입니다.
컨텍스트 초과, 사용량 한도와 어떻게 다른가
세 가지는 원인도 대응도 다릅니다. 구분하지 않으면 엉뚱한 설정을 고치게 됩니다.
- 컨텍스트 초과는 "Codex ran out of room in the model's context window" 문구와 함께 스레드가 더 진행되지 않는 상태입니다. 새 스레드를 시작해야 합니다.
- 사용량 한도 소진은 5시간·주간 할당량이 차서 모델 호출 자체가 막히는 상태입니다. 기다리면 풀립니다.
- 자동 압축은 정상 동작입니다. 문제는 시점입니다. 이 글은 세 번째만 다룹니다.
왜 표시값보다 일찍 압축되는가
압축 판정에 쓰는 카운터는 마지막 응답의 토큰 사용량에 두 가지를 더합니다. 마지막 모델 출력 뒤에 붙은 로컬 항목의 추정치, 그리고 마지막 사용자 메시지 경계보다 앞에 있는 암호화 추론 항목의 추정치입니다.
문제는 두 번째 항목입니다. 서버가 과거 추론 토큰을 이미 사용량에 포함해 보냈다면 다시 더하면 안 되므로, Codex는 응답의 x-reasoning-included 헤더나 응답 메타데이터의 reasoning.context 값을 보고 추정을 건너뛸지 결정합니다. 이 신호가 꺼져 있다고 판단되면 클라이언트가 직접 추정합니다.
rust-v0.163.0 태그의 codex-rs/core/src/context_manager/history.rs에 있는 계산은 다음과 같습니다.
if server_reasoning_included {
last_tokens.saturating_add(items_after_last_model_generated_tokens)
} else {
last_tokens
.saturating_add(self.get_non_last_reasoning_items_tokens())
.saturating_add(items_after_last_model_generated_tokens)
}
추정 대상은 마지막 사용자 경계보다 앞에 있는 암호화 reasoning 항목 전부입니다. 항목마다 다음 식으로 토큰 수를 어림합니다.
bytes = max(floor(encoded_length × 3 / 4) - 650, 0)
tokens = ceil(bytes / 4)
같은 파일의 estimate_reasoning_length와 approx_tokens_from_byte_count_i64가 이 식입니다. encoded_length가 2,168바이트인 항목 하나는 244토큰으로 잡히는데, 이는 #53309가 보고한 244토큰과 같은 값입니다. 항목 수가 많고 각 항목이 길수록 추정치가 커집니다. 압축도 더 일찍 걸립니다.
내 세션에서 어느 쪽인지 확인하는 방법
먼저 화면에 보이는 값의 출처를 확인합니다. 롤아웃 파일에 token_count 이벤트가 남습니다.
ls -t ~/.codex/sessions/$(date +%Y)/$(date +%m)/$(date +%d)/rollout-*.jsonl | head -1
jq -r 'select(.type=="event_msg" and .payload.type=="token_count")
| [.payload.info.last_token_usage.total_tokens,
.payload.info.model_context_window] | @tsv' <롤아웃 파일> | tail -5
여기서 나온 사용량이 임계값보다 한참 낮은 시점에 압축이 걸렸다면 다음 단계로 넘어갑니다. 압축을 발동시킨 카운터는 codex_core::session::turn이 TRACE 등급으로 남기는 줄에 들어 있습니다. 로그 DB(~/.codex/logs_2.sqlite)를 쓰는 빌드라면 기본 필터가 TRACE이므로 logs 테이블에서 바로 찾을 수 있고, 없으면 RUST_LOG=codex_core=trace로 실행해 같은 줄을 확인하면 됩니다.
SELECT datetime(ts, 'unixepoch', 'localtime') AS 시각, feedback_log_body
FROM logs
WHERE feedback_log_body LIKE '%post sampling token usage%'
ORDER BY ts DESC LIMIT 3;
읽을 필드는 auto_compact_scope_tokens, auto_compact_scope_limit, full_context_window_limit, full_context_window_limit_reached, token_limit_reached입니다. auto_compact_scope_tokens가 limit을 넘었는데 같은 시각의 화면 표시 사용량이 limit보다 훨씬 작으면 이중 계산 경로를 탄 것입니다. 반대로 full_context_window_limit_reached가 true라면 실제로 창이 찬 것이므로 이 글의 문제가 아닙니다.
임계값을 올려도 해결되지 않는 이유
model_auto_compact_token_limit을 크게 잡아도 두 단계에서 잘립니다.
- 설정한 model_context_window는 모델 카탈로그의 max_context_window보다 클 수 없습니다. models-manager의 with_config_overrides가 더 작은 값을 씁니다.
- 자동 압축 임계값은 컨텍스트 창의 90%를 넘을 수 없습니다. ModelInfo::auto_compact_token_limit이 설정값과 창의 90% 중 작은 쪽을 고릅니다.
2026-10-19 기준 rust-v0.163.0 소스의 식을 그대로 옮겨 계산하면 다음과 같습니다.
| 설정 | 유효 컨텍스트 창 (95%) | 실제 자동 압축 임계값 (90%) |
|---|---|---|
| model_context_window = 1,000,000, 카탈로그 최대 872,000 | 828,400 | 784,800 |
| model_context_window = 512,000, 카탈로그 최대 872,000 | 486,400 | 460,800 |
| 카탈로그 최대 1,050,000, 설정 없음 | 997,500 | 945,000 |
커뮤니티에 자주 인용되는 "model_context_window = 1000000, model_auto_compact_token_limit = 900000" 조합은 카탈로그 최대가 872,000인 모델에서 실제로는 784,800으로 내려갑니다. 900,000을 1,000,000으로 올려도 임계값은 784,800 그대로입니다. 2026-10-17 보고 #54825가 "임계값을 컨텍스트 창보다 크게 올려도 자동 압축이 꺼지지 않는다"고 적은 이유가 이 클램프입니다.
지금 할 수 있는 대응
- 화면의 퍼센트를 압축 시점의 기준으로 쓰지 않습니다. 표시값은 마지막 응답의 사용량입니다. 압축은 그 값에 추정치를 더한 카운터로 결정됩니다. 네 사례에서 표시값과 발동 카운터의 차이는 약 15만~47만 토큰이었습니다.
- 임계값을 올리는 대신 스레드를 짧게 끊습니다. 추정치는 마지막 사용자 경계보다 앞선 추론 항목의 합이므로, 한 스레드가 길어질수록 커집니다. 작업 단위로 스레드를 나누면 추정치 자체가 작게 유지됩니다.
- 압축 시점을 직접 고릅니다. 미드턴 강제 압축은 진행 중이던 작업을 버립니다. 로그에 reason=ContextLimit phase=MidTurn이 남은 사례가 #53309와 #54825에 있습니다. 구간을 마무리한 지점에서 /compact를 직접 실행하면 시점을 통제할 수 있습니다.
- 추론 강도를 낮추면 추정 대상인 암호화 추론 항목의 길이 합이 줄어 압축이 늦춰집니다. 계산 방식이 고쳐지는 것은 아니고 시점만 미뤄집니다.
- 공개된 비공식 패치가 있습니다. CLI와 app-server 빌드에는 적용되지만 Codex 데스크톱에 내장된 코어는 교체하지 못합니다. 공식 수정이 아니므로 운영 환경에 적용하기 전에 이슈의 진행 상황을 확인하는 편이 안전합니다.
수정 상태와 앞으로 확인할 것
이 계산 차이는 2026-08-20에 #39767로 처음 보고됐습니다. 2026-09-28의 #49026을 거쳐 2026-10-12부터 2026-10-18까지 보고가 몰렸습니다. #55126은 0.163.0에서도 같은 차이가 재현됐다고 적었습니다. 2026-10-19 확인 기준 main 브랜치의 get_total_token_usage에도 같은 분기가 남아 있습니다. 공식 수정 릴리스는 아직 없습니다. Codex CLI 업데이트 직후 실행 자체가 막히는 문제는 원인도 대응도 다릅니다. 그 증상은 Codex CLI 0.157.0 오류 대응 글(/220)에 정리해 두었습니다.
앞으로 확인할 지점은 두 가지입니다. x-reasoning-included 헤더가 재접속하거나 재개한 세션에서도 일관되게 전달되는지, 그리고 reasoning.context가 all_turns인 응답을 클라이언트가 어떤 값으로 반영하는지입니다. 이 둘이 정리되면 표시 사용량과 압축 판정이 같은 수치를 쓰게 됩니다.
지금 이 증상을 겪는다면 설정을 더 만지기 전에 롤아웃 파일의 사용량과 logs 테이블의 auto_compact_scope_tokens를 먼저 비교해 보십시오. 두 값이 벌어져 있으면 설정 문제가 아니라 계산 문제입니다.
'AI 개발 > 에이전트 코딩' 카테고리의 다른 글
| Xcode MCP 도구가 안 보일 때: mcpbridge 권한과 27.2 GetCodeCoverage (0) | 2026.10.23 |
|---|---|
| Codex 주간 한도가 갑자기 사라질 때: 서버가 보내는 계량값과 내 로그 대조법 (0) | 2026.10.21 |
| Claude Code 업데이트 후 구버전이 실행될 때: PATH·설치 방식·채널 점검 (0) | 2026.10.10 |
| Claude Code auto mode Bash 차단: 원인 3가지 구분과 대응 순서 (0) | 2026.10.04 |
| Codex VS Code 확장이 멈추고 메시지가 사라질 때: 캐시 삭제와 재시작 순서 (0) | 2026.10.02 |