Codex 컨텍스트 압축 방식

TMT

https://x.com/Kangwook_Lee/status/2028955292025962534

Codex 이외의 모델에서는, 오픈소스 Codex CLI가 로컬에서 컨텍스트를 압축합니다. LLM이 compaction prompt를 사용해 대화를 요약합니다. 나중에 압축된 컨텍스트를 사용할 때는, 요약을 어떻게 해석할지 틀을 잡아 주는 handoff prompt와 함께 responses.create()에 전달됩니다.

이 두 프롬프트는 소스 코드에서 그대로 확인할 수 있습니다.

반면 Codex 모델의 경우, CLI는 대신 compact() API를 호출하고, 이 API는 암호화된 blob을 반환합니다. 내부적으로 LLM을 사용하는지, 어떤 프롬프트를 쓰는지, handoff prompt가 존재하는지조차 알 수 없습니다.

아래에서는 간단한 프롬프트 인젝션(2번의 API 호출, 35줄짜리 파이썬 코드)으로 API 기반 압축 경로가 실제로 LLM을 사용해 컨텍스트를 요약한다는 점, 그리고 자체적인 compaction prompt와 요약 앞에 붙는 handoff prompt를 사용한다는 점을 보여 줍니다.

이 프롬프트들은 공개된 버전과 거의 동일합니다.

Step 1 — compact()

먼저 compact()를, 특별히 구성한 사용자 메시지와 함께 호출합니다. 서버 측에서는 “컴팩터(compactor)” LLM이, 제가 한 번도 본 적이 없고 알아내고자 하는 자기만의 숨겨진 시스템 프롬프트를 사용해 이 입력을 처리합니다.

서버는 컴팩터의 컨텍스트를 대략 다음과 같이 구성하는 것으로 보입니다:

Image

컴팩터 LLM은 자신의 시스템 프롬프트와 우리의 입력을 함께 읽습니다. 그리고 우리의 입력 안에는 인젝션 페이로드(위 그림의 빨간 텍스트)가 들어 있기 때문에, 컴팩터는 자기 자신의 시스템 프롬프트를 출력에 포함하도록 속게 됩니다. 이 평문 요약은 OpenAI 서버 안에서만 존재합니다. 클라이언트인 우리는 암호화된 blob만 보게 됩니다:

Image

이 시점에서 우리는 blob 안에 무엇이 들어 있는지 읽어 볼 방법이 전혀 없습니다. AES로 암호화되어 있고, 키는 OpenAI 서버에만 존재합니다. 우리가 할 수 있는 건, 컴팩터가 인젝션을 따랐고 자신의 프롬프트를 요약 안에 적어 넣었기를 바라는 것뿐입니다. 이게 실제로 성공했는지 확인할 수 있는 유일한 방법이 바로 Step 2입니다.

Step 2 — create()

이제 암호화된 blob과 두 번째 사용자 메시지를 함께 responses.create()에 전달합니다. 서버는 blob을 복호화하고, 모델이 볼 컨텍스트를 조립합니다.

제가 보낸 입력은 다음과 같습니다:

Image

모델은 대략 다음과 같은 컨텍스트를 보게 되는 것 같습니다:

Image

만약 Step 1이 잘 작동했다면, 복호화된 blob 안에는 (인젝션 덕분에 유출된) compaction prompt가 들어 있어야 합니다. 여기에 서버는 blob 앞에 handoff prompt까지 추가합니다. 따라서 우리의 “탐침”이 모델로 하여금 자신이 보고 있는 내용을 반복하게 만드는 데 성공한다면, 출력에는 세 가지가 모두 드러나야 합니다: 시스템 프롬프트, handoff prompt, compaction prompt.

결과

아래는 extract_prompts.py를 한 번 실행했을 때의 완전한, 편집되지 않은 출력입니다. 노란색 = 시스템 프롬프트, 초록색 = handoff prompt, 분홍색 = compaction prompt입니다.

Image

이 텍스트들이 실제 프롬프트이고, 모델이 만들어 낸 허구가 아니라는 걸 어떻게 알 수 있을까요? 추출된 compaction prompt와 handoff prompt는, 오픈소스 Codex CLI에서 Codex 이외의 모델에 사용되는 알려진 프롬프트(prompt.md, summary_prefix.md)에 매우 가깝게 일치합니다. 이 때문에, 모델이 이걸 완전히 새로 지어냈을 가능성은 낮아 보입니다. 실행 결과는 매번 조금씩 달라질 수 있습니다.

파이프라인

위의 결과들을 종합하면, compact()가 서버 측에서 내부적으로 무엇을 하는지에 대해 다음과 같은 “최선의 추측” 파이프라인을 세울 수 있습니다.

Image

스크립트

Image

열린 질문

왜 Codex CLI는, 프롬프트는 거의 동일한데도 (Codex 이외 모델에는 로컬 LLM, Codex 모델에는 암호화된 API라는) 서로 완전히 다른 두 가지 컨텍스트 압축 경로를 사용할까요? 그리고 왜 요약을 굳이 암호화까지 할까요?

단정적으로 말하기는 어렵습니다. 예를 들어, 이 암호화된 blob 안에는 이번 간단한 실험만으로는 드러나지 않는 추가적인 정보, 특히 도구(tool) 실행 결과를 어떻게 압축하고 복원하는지에 대한 모델 특유의 정보 같은 것이 더 포함되어 있을지도 모릅니다. 다만 저는 그 이상으로 깊게 실험해 보지는 않았습니다.

Edit this page