Medium
OpenAI Codex의 작동 원리
Codex CLI는 agent_loop + prompt caching + App Server(OpenAPI) 세 축으로 동작한다. 토큰 비용이 turn이 아니라 누적 컨텍스트 길이로 결정된다는 사실이 도구 설계의 방향을 뒤집는다.
핵심 요약
Codex CLI는 세 개의 독립된 레이어로 구성된다. (1) agent_loop 은 LLM 응답에서 tool_call 을 감지하면 툴을 실행하고 결과를 다음 프롬프트에 덧붙여 루프를 돌린다. 한 번의 사용자 질문이 수십 번의 LLM 호출로 확장될 수 있고, 각 호출의 비용은 누적 컨텍스트 길이에 비례한다. (2) Prompt Caching 은 OpenAI 측 서버 캐시로 프리픽스가 동일하면 입력 토큰을 재사용해 과금한다 — 즉 툴 결과를 뒤에 붙이는 순서 가 바뀌면 캐시가 깨진다. (3) App Server 는 OpenAPI 명세로 정의된 로컬 HTTP 서버로, CLI/IDE/Web 이 동일한 세션 상태를 공유하게 한다. 면접에서 이 세 축을 구분해 설명할 수 있으면 AI 도구 아키텍처 감각 을 보여줄 수 있다.
Codex를 'LLM이 호출하는 함수 집합' 이 아니라 '에이전트 루프가 관리하는 상태 기계' 로 본다. 프롬프트 → LLM 응답 → 툴 호출 → 결과 → 다음 프롬프트 로 순환하는 루프에서 캐시 적중률 과 컨텍스트 포화 가 실제 응답 속도와 비용을 좌우한다. 툴 하나하나보다 agent_loop 의 상태 전이 를 먼저 그려야 한다.
ChatGPT와 Cursor 같은 GUI 툴만 써온 개발자는 Codex CLI가 왜 빠르고 싼가 를 설명하지 못한다. 핵심은 세 가지다.
agent_loop: LLM이 툴을 호출한 뒤 결과를 받아 다시 같은 루프 로 들어가는 구조 —turn단위가 아니라 누적 컨텍스트 로 과금된다- Prompt Caching: 동일 프리픽스(system + 초반 대화)가 캐시 히트되면 토큰 비용이 최대 90% 절감
- App Server + OpenAPI 명세: CLI와 VSCode 확장이 동일한 서버를 공유해 세션 영속성 과 멀티 클라이언트 를 얻는다
이 구조를 이해하면 AI 코딩 도구를 '프롬프트 잘 쓰기' 가 아니라 '컨텍스트 설계' 로 바라보게 된다.
학습 포인트
면접 답변으로 연결할 학습 포인트입니다.
Agent loop = 재귀적 컨텍스트 누적
에이전트 루프는 단순한 '요청-응답'이 아니라 툴 호출이 끝날 때까지 같은 컨텍스트를 계속 쌓는 구조 다.
// pseudo-code for the agent loop
let messages = [systemPrompt, userTurn];
while (true) {
const resp = await llm.chat(messages);
messages.push(resp);
if (!resp.tool_calls) break; // LLM 이 답변을 마치면 종료
for (const call of resp.tool_calls) {
const out = await exec(call);
messages.push({ role: 'tool', content: out });
}
}
루프 한 바퀴가 늘어날 때마다 messages 길이가 커지고 다음 호출의 입력 토큰이 그만큼 늘어난다. 'turn 당 비용'이 아니라 누적 길이 × 루프 횟수 가 실제 과금이다.
'한 질문 = 한 번 LLM 호출'로 오해하는 것. 실제로는 툴 호출 1회마다 LLM 호출이 1회 더 발생 하며, 컨텍스트는 계속 불어난다.
Prompt caching 은 '순서' 가 전부
OpenAI Prompt Caching 은 프리픽스 매칭 이다. 요청의 앞부분이 직전 요청과 바이트 단위로 동일 할 때만 캐시 히트되고 최대 90% 저렴해진다.
| 순서 | 결과 |
|---|---|
[system, history, NEW_TOOL_RESULT] | 히트 — 앞부분 재사용 |
[system, NEW_TOOL_RESULT, history] | 미스 — 프리픽스가 달라짐 |
[system, history, TIMESTAMP, NEW] | 미스 — 가변 토큰으로 오염 |
도구 결과를 항상 끝에 append 하고, 시스템 프롬프트에 현재 시각 같은 가변 값을 넣지 않는 것이 캐시 적중률을 올리는 실전 규칙이다.
시스템 프롬프트 맨 앞에 세션 ID나 타임스탬프를 넣어 모든 요청이 캐시 미스 가 나게 만드는 것.
App Server 는 CLI-IDE 공유 경계
Codex는 CLI/VSCode 확장/Web UI 가 각자 LLM을 호출하는 구조가 아니라, 로컬 App Server 하나가 LLM 과 세션을 관리하고 클라이언트는 OpenAPI 로 정의된 HTTP 엔드포인트를 호출한다.
[CLI] ─┐
[VSCode] ─┼── HTTP/OpenAPI ──▶ [App Server] ──▶ [OpenAI API]
[Web] ─┘ │
└─ 세션/히스토리 저장
이 분리 덕분에 터미널에서 시작한 대화를 IDE에서 이어받거나, 세션을 로컬 파일로 직렬화해 재현할 수 있다. '왜 CLI 가 아니라 서버냐'가 아니라 '멀티 클라이언트 + 세션 영속성' 이 답이다.
Codex를 단순 CLI 래퍼로 오해하는 것. 실체는 로컬 HTTP 서버 + 얇은 클라이언트 아키텍처다.
읽는 순서
- 1이론
OpenAI Chat Completions 문서의
tool_calls섹션과 Prompt Caching 문서를 읽고, 입력 토큰 과금 구조 를 한 페이지로 정리하세요. - 2구현
20줄짜리
agent_loop을 직접 구현하세요 —messages배열, while 루프, 단일 툴(예:readFile) 만 써서 Codex 의 핵심 패턴을 재현합니다. - 3실무
실제 Codex CLI 세션을 하나 녹화하고(
--log-level debug), 프롬프트 캐시가 언제 히트/미스하는지 iteration 별 입력 토큰 수 를 그래프로 그려보세요. - 4설명
팀에 'AI 코딩 툴은 왜 갑자기 싸졌나'를 주제로 10분 발표를 준비하세요. 축: (1) agent loop, (2) prompt caching, (3) App Server. 각 축이 해결한 병목을 한 문단씩.
면접 연결 질문
[감점 답변] '한 번 질문하면 한 번 호출된다' 식. [좋은 답변] turn 은 사용자가 엔터를 누른 횟수이고, iteration 은 LLM↔툴 왕복 횟수다. 한 turn 안에서 파일 읽기/쓰기/명령 실행이 10회 일어나면 LLM 호출 11회 + 각 호출마다 누적 컨텍스트. 비용은 sum(context_len_i) 에 비례하므로 툴 결과가 클수록 다음 호출이 더 비싸진다.
[감점 답변] '시스템 프롬프트를 길게 쓴다' 수준. [좋은 답변] 세 규칙:
- 시스템 프롬프트는 고정 — 버전 관리 외 변경 금지
- 가변 값(시각/ID) 은 끝쪽으로 — 프리픽스를 오염시키지 말 것
- 툴 결과는 append 만 — 이전 메시지 수정 시 그 이후 전부 캐시 미스
구체적으로는 render(messages) 에서 앞부분을 불변으로 유지하는 코드 리뷰 기준을 둔다.
[감점 답변] '그냥 더 편해진다'. [좋은 답변] 네 가지 이점:
- 세션 영속성: 터미널을 닫아도 서버가 살아있으면 이어서 작업
- 멀티 클라이언트: CLI 와 IDE 확장이 같은 대화를 본다
- 프로세스 격리: LLM 호출/파일 접근 권한을 서버 한 곳에 집중해 감사
- OpenAPI 계약: 클라이언트를 언어 무관하게 자동 생성
트레이드오프: 로컬 포트 충돌, 인증, 업그레이드 시 프로토콜 호환성 관리 부담.
자기 점검
iteration 마다 비용이 동일하다고 생각하는 것. 실제로는 입력 토큰이 계속 늘어나므로 뒤로 갈수록 한 번이 비싸진다.
'캐시는 자동이라 신경 안 써도 된다'. 실제로는 프리픽스 설계 가 비용을 좌우한다.
'서버는 무조건 무겁다'는 편견. 로컬 HTTP 서버는 수백 MB 수준 리소스로도 충분한 경우가 많다.