> ## Content Index
> Fetch the complete content index at: https://blog.sorune.org/llms.txt
> Use this file to discover other available public pages before exploring further.

# AI 프롬프트를 77% 줄였는데 입력 비용은 왜 줄지 않았을까
- URL: https://blog.sorune.org/context-compaction-effective-input-cost/
- Published: 2026-09-11T22:37:21.000Z
- Updated: 2026-09-11T22:37:21.000Z
- Description: 실행 프롬프트와 handoff를 크게 줄인 뒤 실제 context 비용도 줄었는지 측정했다. 결과는 단순했다. 전송량을 줄이는 것과 모델이 다시 읽는 정보량을 줄이는 것은 다른 문제였다.
- Author: Sorune — Engineering, Photography & Lab Notes
- Tags: Lab, Context Engineering, AI-Native Engineering, Retrieval, Measurement, Agent Workflow

최근 AI에게 전달하는 작업 지시가 눈에 띄게 짧아졌다.

예전에는 프로젝트 상태, 이전 작업, 주의사항, 다음 단계까지 한 프롬프트에 길게 넣는 경우가 많았다. 프로젝트가 커지면서 이 방식은 점점 부담스러워졌고, 안정적인 정보는 Git과 프로젝트 문서로 옮기고 현재 작업에 필요한 delta만 전달하는 방향으로 바꿨다.

겉으로 보기에는 성공적이었다.

한 비교 표본에서 Human이 직접 전달하는 instruction payload는 약 **13,991 bytes에서 3,268 bytes로 줄었다.** 대략 76\~77% 감소다.

그런데 여기서 질문이 생겼다.

```text
프롬프트가 77% 짧아졌다면
AI가 실제로 읽는 input도 77% 줄었을까?

```

측정해보니 그렇게 단순하지 않았다.

이 글은 그 과정에서 `prompt size`, `context transport`, `retrieval cost`를 서로 다른 문제로 보게 된 기록이다.

> 이 글의 수치는 주로 파일 크기와 instruction payload의 UTF-8 byte 측정값이다. provider billing token이나 실제 cached-input token telemetry를 직접 측정한 결과가 아니다.

## 먼저 확실히 줄어든 것: Human prompt

현재 Workspace Ops 작업 중 하나였던 `OPS-UX-02`의 Human instruction을 측정했다.

```text
characters: 3,254
UTF-8 bytes: 3,268
lines: 177

```

비교 대상으로 과거 CharaWeave capability audit 지시를 같은 방식으로 봤다.

```text
characters: 13,697
UTF-8 bytes: 13,991
lines: 578

```

비율은 다음과 같았다.

| 항목          | 과거 표본  | compact 표본 | 변화     |
| ----------- | ------ | ---------- | ------ |
| Characters  | 13,697 | 3,254      | 약 -76% |
| UTF-8 bytes | 13,991 | 3,268      | 약 -77% |
| Lines       | 578    | 177        | 약 -69% |

Human이 직접 작성해서 전달하는 payload만 놓고 보면 명확한 개선이었다.

이전처럼 현재 상태 전체를 다시 설명하지 않고, 이미 저장된 상태를 가리키면서 이번 작업의 delta만 전달하기 시작했기 때문이다.

```text
FULL CONTEXT RECONSTRUCTION
→ POINTER / DELTA TRANSPORT

```

## Handoff도 실제로 작아졌다

비슷한 변화는 session/device handoff에서도 보였다.

초기 continuation 계열 두 표본은:

```text
9,935 B
10,833 B

average: 10,384 B

```

이후 compact handoff 10개는 평균 약:

```text
3,285 B

```

였다.

평균 기준으로 약 **68% 감소**다.

CharaWeave의 최근 handoff 10개도 평균 약 2,180 B 수준까지 내려가 있었다.

여기까지만 보면 context compaction은 잘 되고 있는 것처럼 보였다.

```text
Human prompt ↓
Handoff ↓
Repeated prose ↓

```

그런데 repository 쪽까지 보기 시작하면서 결과가 달라졌다.

## 첫 번째 반전: Git으로 옮긴 context도 결국 읽으면 input이다

프롬프트가 짧아진 이유 중 하나는 안정적인 규칙과 상태를 repository에 보관했기 때문이다.

예를 들어 측정 당시 주요 `AGENTS.md` 크기는 대략 다음과 같았다.

```text
workspace-ops/AGENTS.md  ≈ 16,275 B
PhotoGramPJ/AGENTS.md    ≈  6,169 B
charaweave/AGENTS.md     ≈  3,152 B

```

`OPS-UX-02`는 짧은 Human prompt 대신 repository의 `AGENTS.md`를 읽도록 요구했다.

따라서 아주 단순하게 둘만 합쳐보면:

```text
OPS-UX-02 Human prompt   3,268 B
workspace-ops AGENTS    16,275 B
--------------------------------
minimum                 19,543 B

```

과거 CharaWeave 표본도 똑같이 `prompt + AGENTS`만 계산하면:

```text
CW-PG prompt            13,991 B
charaweave AGENTS        3,152 B
--------------------------------
minimum                 17,143 B

```

Human prompt는 훨씬 짧아졌는데, 이 단순 비교에서는 오히려 새 작업 쪽이 더 컸다.

물론 이 숫자를 곧바로 실제 model input이라고 부를 수는 없다. provider cache, tool 결과 전달 방식, 실제 read 범위가 다르기 때문이다.

하지만 한 가지는 명확했다.

```text
CONTEXT MOVED TO GIT
!=
CONTEXT COST ELIMINATED

```

정보를 프롬프트에서 파일로 옮겼다고 해서 그 정보가 공짜가 되는 것은 아니다.

agent가 매번 그 파일을 다시 읽는다면 비용의 위치만 바뀐 것이다.

## 두 번째 반전: 작은 handoff보다 큰 Always-Read set이 더 중요했다

CharaWeave workflow를 보면서 이 문제가 더 선명해졌다.

당시 workflow contract에는 future Story마다 다음 문서들을 `Always read`하도록 명시한 구간이 있었다.

```text
AGENTS.md
ORCA_GIT_WORKFLOW.md
ARCHITECTURE_BASELINE.md
PROJECT_EVOLUTION_MAP.md
DELIVERY_PLAN.md
1_0_READINESS_LEDGER.md

```

파일 크기를 합치면 약:

```text
134,673 B

```

였다.

약 131.5 KiB의 static context다.

Browser나 React 관련 Story라면 여기에 integration 문서가 추가되고, 현재 Story의 preceding work item과 handoff까지 읽도록 되어 있었다.

재미있는 점은 같은 시점 CharaWeave의 handoff 자체는 이미 평균 약 2 KB 수준으로 충분히 작아졌다는 것이다.

즉 큰 비용 후보는 더 이상 handoff가 아니었다.

```text
Handoff transport
= compact

Mandatory retrieval surface
= still large

```

여기서 처음 연구 질문이 바뀌었다.

## Transport Compaction과 Retrieval Compaction은 다르다

처음에는 이렇게 물었다.

```text
프롬프트가 얼마나 짧아졌는가?

```

측정 후에는 질문이 이렇게 바뀌었다.

```text
agent가 같은 작업을 하기 위해
stable context graph를 얼마나 다시 traverse하는가?

```

이 둘을 분리하기 위해 context compaction을 세 단계로 보기 시작했다.

### 1\. Transport Compaction

사람이나 이전 session이 다음 actor에게 직접 전달하는 양을 줄이는 것이다.

```text
Human prompt
handoff
resume delta

```

이 부분은 확실히 줄었다.

### 2\. Storage Separation

서로 성격이 다른 정보를 적절한 owner로 분리한다.

```text
stable governance → Git / AGENTS
current durable state → control state / checkpoint
history → history repository
current request → prompt delta

```

이것도 구조적으로는 상당히 개선됐다.

### 3\. Retrieval Compaction

실제 작업에서 필요한 것만 필요한 순간에 읽게 만드는 것이다.

```text
필요한 문서만
필요한 시점에
필요한 범위만

```

실제 input 효율과 가장 직접적으로 연결되는 부분은 이 세 번째 단계였다.

```text
TRANSPORT COMPACTION
!= RETRIEVAL COMPACTION

```

프롬프트를 아무리 짧게 만들어도 agent가 시작할 때마다 100 KB가 넘는 baseline을 다시 읽는다면 전체 비용은 생각만큼 줄지 않을 수 있다.

## 모든 reference를 Always Read로 취급해도 안 된다

여기서 반대 방향의 과대계산도 조심해야 했다.

PhotoGram `AGENTS.md`에는 여러 Workspace governance 문서가 required reference로 연결되어 있었다.

당시 그 문서들과 PhotoGram `AGENTS.md`의 파일 크기를 단순 합산하면 약:

```text
100,651 B

```

였다.

하지만 이것을:

```text
PhotoGram per-session input = 100,651 B

```

라고 부를 수는 없었다.

CharaWeave의 경우에는 workflow가 명시적으로 `Always read`를 요구했다. 반면 PhotoGram은 reference/authority surface를 선언한 것이지 모든 파일을 매 session마다 전부 읽는다는 증거는 아니었다.

실제 canary 기록에서도 targeted governance/history reread는 2회였고, manual handoff나 same-owner full context reconstruction은 없었다.

그래서 다음을 분리하게 됐다.

```text
DECLARED REFERENCE SURFACE
!=
PROVEN ACTUAL RETRIEVAL

```

파일이 존재한다는 이유만으로 input 비용에 전부 더하는 것도 잘못이고, prompt에 없다는 이유로 비용에서 빼는 것도 잘못이다.

결국 필요한 것은 실제 retrieval trace다.

## Context 비용은 문서 크기 하나로 설명되지 않는다

이 관찰을 바탕으로 context load를 개념적으로 다음처럼 보기 시작했다.

```text
Context Load Cost
≈ Σ(
    context size
  × actual read frequency
  × relevance
  × cache behavior
)

```

정확한 billing formula라는 뜻은 아니다.

특히 `cache behavior`는 provider telemetry가 없으면 수치화하면 안 된다.

다만 최적화 방향을 생각하기에는 이 모델이 단순 prompt-size보다 유용했다.

예를 들어 50 KB짜리 문서라도 operation 전체에서 한 번만 읽고 이후에는 필요한 section만 가져온다면 비용 특성이 달라진다.

반대로 5 KB짜리 문서를 매 step마다 반복해서 읽으면 누적 비용은 커질 수 있다.

그래서 document size만 볼 게 아니라 다음을 같이 보게 됐다.

```text
SIZE
× READ FREQUENCY
× RELEVANCE
× CACHE BEHAVIOR

```

## 측정 항목도 다시 나눴다

처음에는 `prompt bytes` 하나면 충분하다고 생각했다.

지금은 적어도 다음 정도는 분리해야 한다고 본다.

```text
HUMAN PAYLOAD
= 사람이 이번 작업에 직접 전달한 instruction

FIXED GOVERNANCE COST
= 실제 mandatory / always-read stable context

DECLARED REFERENCE SURFACE
= 접근 가능해야 하지만 실제 read가 증명되지 않은 문서

DURABLE STATE COST
= checkpoint / operation / current control state

ROUTING COST
= handoff / continuation delta

TARGETED EVIDENCE COST
= 이번 step 때문에 실제로 읽은 evidence

REPEATED CONTEXT COST
= 같은 정보를 동일 operation에서 다시 읽은 양

FULL CONTEXT RECONSTRUCTION COUNT
= 전체 context를 다시 조립한 횟수

```

provider가 telemetry를 제공한다면 그때 별도로:

```text
input tokens
cached input tokens
output tokens
reasoning tokens, when exposed

```

을 기록하면 된다.

없는 telemetry를 추정해서 실제값처럼 다루지는 않는 편이 낫다.

## 그래서 77%는 무엇을 의미했는가

처음의 77%라는 수치는 틀리지 않았다.

다만 의미가 더 좁았다.

```text
Human-supplied instruction payload
= 약 76~77% 감소

```

이지:

```text
Total model input cost
= 77% 감소

```

가 아니었다.

당시 evidence를 다시 정리하면 이렇다.

```text
HUMAN PROMPT COMPACTION
= CLEAR PASS

HANDOFF / TRANSPORT COMPACTION
= CLEAR PASS

CONTEXT STORAGE SEPARATION
= CLEARLY IMPROVED

RETRIEVAL COMPACTION
= PROJECT-DEPENDENT / NOT YET COMPLETE

TOTAL EFFECTIVE INPUT COMPACTION
= PARTIALLY SUPPORTED, NOT YET TOKEN-PROVEN

```

이 구분을 하지 않았다면 "프롬프트를 77% 줄였더니 AI 비용도 77% 줄었다"는 훨씬 보기 좋은 결론을 쓸 수도 있었을 것이다.

하지만 현재 evidence가 말하는 것은 그보다 조금 더 복잡했다.

## Pointer가 항상 duplication보다 싸지는 않다

현재 내가 가장 중요하게 보는 결론은 이것이다.

```text
POINTER > DUPLICATION

```

이라는 원칙은 대체로 맞다.

같은 긴 context를 매번 prompt에 복제하는 것보다 canonical source를 가리키는 편이 관리와 provenance 측면에서도 좋다.

하지만 효율 측면에서는 조건이 하나 붙는다.

```text
POINTER TARGET을
매번 처음부터 끝까지 읽지 않아도 되어야 한다.

```

pointer를 만들고도 매 작업마다 target 전체를 다시 읽는다면 transport만 줄었을 뿐 retrieval은 줄지 않는다.

그래서 다음 최적화 대상은 더 짧은 prompt가 아니라 **더 좋은 retrieval policy**가 됐다.

```text
index first
→ identify relevant source
→ targeted read
→ expand only when necessary

```

정보를 없애는 것이 아니라, 필요한 순간까지 읽기를 지연시키는 방식이다.

## 다음 질문

이 연구는 아직 끝나지 않았다.

다음으로 확인하고 싶은 것은 byte 단위 관찰을 실제 execution trace와 provider telemetry에 연결하는 것이다.

- 실제 session이 읽은 file path와 byte 총량을 추적할 수 있는가?
- `Always read`를 `index → targeted read`로 바꿔도 correctness가 유지되는가?
- 같은 stable document를 operation 안에서 몇 번 다시 읽는가?
- provider cache가 이런 stable context를 실제로 얼마나 흡수하는가?
- byte 기반 context-load 추정치와 actual input token은 어느 정도 상관관계가 있는가?

처음에는 프롬프트를 짧게 만드는 문제라고 생각했다.

지금은 조금 다르게 본다.

**Context engineering의 핵심은 정보를 어디에 저장하느냐만이 아니라, 실제 작업에서 그 정보를 언제 얼마나 다시 읽게 하느냐에 있다.**

짧은 prompt는 좋은 시작이었다.

하지만 전체 input 비용을 줄이려면 transport 다음으로 retrieval을 설계해야 했다.