웹에서 읽기 → hojin12312.github.io/llm-field-notes — 반응형 + 다크/라이트 모드, 다이어그램 클릭 시 풀스크린 확대. 자매편 (일반 독자용 입문) → hojin12312.github.io/into-the-latent-space
같은 LLM(Large Language Model, 대형 언어 모델)이 한쪽에선 문장 한 줄을 만지작거리고, 다른 한쪽에선 수십 개의 파일을 가로지르며 코드를 수정하고 테스트를 돌리고 git 커밋까지 찍어요. 똑같은 모델인데 무엇이 그 격차를 만들까요. 모델 크기? 파라미터? 학습 데이터?
답은 의외로 단순해요. 모델 바깥의 코드 한 뭉치 — 도구를 호출하고 결과를 다시 모델에게 돌려주는 얇은 껍데기가 있느냐 없느냐의 차이예요. 이 껍데기를 하네스(harness) 라고 불러요. 본문이 풀어가는 첫 번째 이야기예요.
그리고 그 다음 이야기는 더 이상해요. 2026년 현재 가장 정교한 코딩 에이전트도 결국 메모리 대역폭 앞에서 무릎을 꿇어요. 더 똑똑한 알고리즘을 만들어도, 모델 가중치와 KV 캐시(Key-Value cache — 디코드 단계에서 이전 토큰의 K·V를 재사용하기 위해 잠시 들고 있는 단기 기억) 를 GPU 안으로 퍼 나르는 속도가 따라주지 않으면 토큰 1개를 더 뽑는 데 더 많은 밀리초가 걸려요. 지능의 진짜 병목은 소프트웨어가 아니라 하드웨어 쪽에 있어요. 본문이 결국 도착할 종착지예요.
왜 코딩 에이전트를 배워야 하는가? 업무 효율 향상은 기본이에요. 코딩 경력이 없어도, 시간이 없어도 — Claude Code나 Codex 같은 코딩 에이전트를 쓸 줄 알면 머릿속에 있던 것을 직접 만들어낼 수 있어요. 업무에서도, 개인 프로젝트에서도요.
코딩 에이전트는 음악을 작곡하거나, 그림을 그리거나, 회로를 설계하지는 못해요. 하지만 그 일을 해내는 AI 시스템을 만들어내는 도구예요. 음악 생성 모델, 이미지 합성 파이프라인, EDA 자동화 도구 — 이 모든 것이 코드 위에 올라가요. Anthropic의 Claude Code, OpenAI의 Codex(CLI) 같은 도구가 그 코드를 짜는 일을 맡아요. 본문은 특정 제품을 옹호하지 않고 에이전트 일반론을 다루되, 구체적 사례가 필요한 자리에서는 두 도구를 함께 인용해요.
이 문서는 소프트웨어 아키텍처 관점에서 에이전트를 해부하고, 지능의 진짜 병목이 어디인지 드러내요. Part I는 구조(뇌·몸·컨텍스트), Part II는 통제술(11개 원칙), Part III는 그 모든 최적화가 부딪히는 물리적 천장이에요.
Part I — LLM 에이전트의 해부학
Part II — 에이전트 통제술
Part III — 소프트웨어의 한계, 하드웨어의 가능성
심화 자료
- 파라미터 착시: KV 캐시의 진실
- 양자화와 KV 압축 — Unsloth Dynamic·TurboQuant
- 어텐션 변형 — SWA·GQA·MLA·RoPE/YaRN
- 추론 시스템·커널 최적화 — FlashAttention·PagedAttention·Continuous Batching·Prefix Caching
- 트랜스포머 추론의 두 단계: Prefill과 Decode
- 리즈닝 모델의 딜레마
- 안전한 AI는 더 약한 AI인가?
- 397B를 이긴 27B: 경량 모델이 대형 모델을 따라잡는 이유
- 최근 여섯 모델 — Gemma4·Qwen3.6·DeepSeek V4
- DFlash: 블록 확산 드래프터로 6배 빨라지는 투기적 디코딩
- LLM 구동의 주요 스펙: 메모리 용량과 대역폭
- 로컬 LLM 실행 생태계
- Claude Code 3대 설정 축
- Codex 사용 가이드
- 커밋(Commit)이란 무엇인가
- API 비용 최적화 — 캐싱·배치·모델 라우팅
- 에이전트 프레임워크 지형도 — LangChain·LangGraph·CrewAI·MS Agent·Claude Code·Codex
- RAG 아키텍처 — 검색 증강 생성의 실전 패턴
- LLM 평가 — 벤치마크·LLM-as-Judge·골든셋·에이전트 평가
- AI 기술 부채 — 빨라진 생성, 미뤄진 이해
- AI 와 일자리 — 합리적 공포와 합리적 회의
같은 모델이 왜 어떤 환경에선 문장 다듬기에 그치고, 어떤 환경에선 수백 줄짜리 코드를 자율적으로 고쳐내는가. 이 격차를 설명하는 단어는 단 하나, 하네스예요. Part I는 그 차이를 다섯 절에 걸쳐 분해해요.
ChatGPT에 질문하는 것과 코딩 에이전트(Claude Code, Codex 등)가 코드를 짜고 고치는 것은 체감이 완전히 달라요. 같은 LLM인데 왜 다를까요?
가장 단순한 LLM 사용은 이렇게 생겼어요.
[프롬프트] --> ( LLM ) --> [텍스트 응답]
정교한 두뇌지만 완전히 무력해요.
- 파일을 스스로 열어보지 못해요.
- 터미널 명령을 실행할 수 없어요.
- 이전 대화를 기억하지 못해요 (매번 컨텍스트를 다시 넣어야 해요).
- 웹을 검색할 수 없어요.
비유하자면 수술실에 누워 있는 환자와 같아요. 시각·청각·언어 능력은 멀쩡한데, 사지가 묶여 있죠. 누가 뭔가를 입에 가져다 대 주지 않으면, 본인은 한 발자국도 움직일 수 없어요.
Note
"그런데 제 ChatGPT는 저를 기억하던데요?" ChatGPT의 기억 기능은 LLM이 스스로 기억하는 게 아니에요. 대화가 끝날 때 하네스가 중요한 내용을 별도로 저장해 두었다가, 다음 대화를 시작할 때 프롬프트에 몰래 끼워 넣는 방식이에요. LLM 자체는 여전히 그 순간 입력된 컨텍스트만 봐요. 깜짝 사실: ChatGPT 본체는 사실상 매번 처음 만난 사람처럼 출발하고, 책상 위에 미리 올려둔 메모지를 슬쩍 본 다음 "아, 그 분이시죠" 하는 트릭이에요.
생각은 할 수 있지만, 아무것도 할 수 없어요. 그래서 진짜 "에이전트"가 되려면 몸이 필요해요.
에이전트(Agent) 는 LLM에 "몸"을 붙인 것이에요. 이 몸에 해당하는 것이 하네스(harness) 예요.
하네스(harness) 란: 원래는 말에 씌우는 마구(馬具). 소프트웨어 맥락에서는 LLM이 외부 세계와 상호작용할 수 있게 감싸주는 실행 환경 — 도구 호출 인터페이스, 반복 루프, 파일 I/O, 안전 장치가 한 덩어리로 묶여 있어요.
flowchart LR
User["사용자 입력(User Input)"]
subgraph Harness["하네스(Harness)"]
LLM["LLM"]
Tools["파일/셸/웹/DB(File/Shell/Web/DB)"]
LLM -->|"도구 호출(Tool Call)"| Tools
Tools -->|"도구 결과(Tool Result)"| LLM
end
User --> LLM
하네스가 제공하는 것:
- 도구 호출: LLM이 "파일 읽어줘", "이 명령 실행해줘"를 구조화된 형식으로 내놓으면, 하네스가 실행 후 결과를 돌려줌
- 반복 루프: "코드 짜기 → 실행 → 에러 → 수정"을 LLM이 스스로 반복할 수 있게 구동
- 상태 관리: 세션 동안의 파일 수정, 실행 기록 추적
- 안전 장치: 위험한 명령 차단, 사용자 승인 요청
이 메커니즘의 핵심을 한 문장으로 압축하면 — LLM은 텍스트만 출력해요. 파일을 직접 열거나 명령을 직접 실행하는 코드가 LLM 안에 있는 게 아니에요.
비유로 풀면 — LLM을 "주문서를 쓸 수 있는 관리자"로 생각해 보세요. 이 관리자는 직접 창고에 가지 않아요. "창고 3번 선반 A-4 박스 가져다줘"라고 적힌 메모를 써요. 창고 직원(하네스)이 그 메모를 읽고 실제로 가져와서 "A-4 박스 내용물: 나사 50개, 볼트 20개"라고 보고해요. 관리자는 그 보고를 읽고 다음 지시를 내려요.
비유에는 한계가 있어요. 실제 LLM이 "주문서를 쓰는" 행위는 사람의 의식적 결정과 달라요. 모델은 다음에 올 토큰을 확률 분포로 뽑을 뿐이고, 도구 호출 형식은 학습 과정에서 그 확률 분포에 굳어진 패턴이에요. 즉 "관리자가 의도적으로 주문서를 쓰는" 게 아니라, "주문서가 나올 자리에 주문서가 나오도록 훈련되어 있다"가 더 정확해요. 그렇긴 해도 외부에서 보는 흐름은 비유 그대로예요.
실제 도구 호출 루프는 이렇게 동작해요.
sequenceDiagram
participant LLM
participant Harness as 하네스(Harness)
LLM->>Harness: { "tool": "Read", "path": "src/main.py" }
Note over LLM: "src/main.py를 확인해야겠다"
Harness->>LLM: 파일 내용 (컨텍스트에 삽입)
Note over LLM: "17번째 줄에 버그. 수정이 필요하다"
LLM->>Harness: { "tool": "Edit", "file": "src/main.py", ... }
Harness->>LLM: 수정 완료 보고
Note over LLM: "수정 완료. 테스트를 돌려보자"
LLM->>Harness: { "tool": "Bash", "command": "pytest" }
Harness->>LLM: 테스트 결과
Note over LLM: "전부 통과. 완료."
LLM-->>LLM: 사용자에게 최종 응답
사용자는 최종 응답 한 줄만 봐요. 그 사이에 수십 번의 도구 호출 루프가 오갔을 수 있어요. 위 다이어그램에서 "Tool Call" 화살표가 내려가고 "Tool Result"가 올라오는 것이 이 루프예요.
어떤 도구를 붙이느냐에 따라 에이전트의 능력이 결정돼요. 파일 읽기·수정, 셸 명령 실행, 웹 검색, DB 조회 — 하네스에 등록된 것이라면 무엇이든 LLM이 주문서를 써서 호출할 수 있어요.
LLM은 뇌, 하네스는 몸. Claude Code, Codex, Cursor, Aider, Roo Code — 겉모습이 달라도 개념은 동일해요. 이 뼈대를 잡고 있으면 도구가 무엇이든 판단 기준이 흔들리지 않아요.
에이전트를 처음 마주할 때 가장 빠른 지름길은 — 그것을 자기 자신에 비춰 보는 것이에요. 어디가 닮았고 어디가 다른지 한 번에 잡아낼 수 있어요.
AI 에이전트의 구조를 이해하는 가장 빠른 방법은 인간과 대응시켜 보는 것이에요.
| 인간 | AI 에이전트 | 차이 |
|---|---|---|
| 뇌 (신경망) | LLM | 인간: 경험으로 실시간 재구성. AI: 학습 완료 후 가중치 동결 |
| 시냅스 (가소성) | 파라미터 | 인간: 평생 변화. AI: 학습 시 결정, 이후 고정 |
| 신체 (실행 인프라) | 하네스 (zsh, python3, 파일 시스템) |
인간: 유기적으로 진화, 물리 제약 있음. AI: 설계자가 임의로 교체·확장 가능 |
LLM은 인간 뇌와 비교할 때 분명히 열위인 부분이 있어요. 학습이 끝난 후 가중치가 굳기 때문에 새로운 경험을 흡수하지 못하고, 진짜 이해 없이 패턴을 흉내 내며, 맥락을 벗어나면 쉽게 환각(hallucination)을 일으켜요.
규모만 봐도 그래요. 현재 가장 큰 프론티어 모델들의 파라미터 수는 아래와 같아요.
| 모델 | 파라미터 수 | 비고 |
|---|---|---|
| Claude Opus 4.7 | 비공개 (수조 단위 추정) | Anthropic 공식 미공개 |
| GPT-5.4 | 비공개 | OpenAI 공식 미공개 |
| DeepSeek-V4-Pro | 1조 6,000억 (MoE, 490억 활성) | DeepSeek 2026-04-24 출시. 현재 공개된 오픈웨이트 중 최대. MoE(Mixture of Experts): 입력마다 전체 파라미터 중 일부만 활성화하는 구조 |
| Kimi K2.6 | 1조 (MoE, 320억 활성, 384 experts) | Moonshot AI 2026-04-20 출시 |
| GLM-5.1 | 7,440억 (MoE, 400억 활성) | Z.AI 공식 |
| Llama 3.1 405B | 4,050억 (dense) | Meta 공식. 공개 dense 모델 중 최대 |
| 인간 뇌 시냅스 | 약 100조~150조 | 신경과학계 측정치 (대뇌피질 기준) |
프론티어 모델 중 Anthropic·OpenAI는 공식 파라미터 수를 공개하지 않아요. "수조 단위"라는 표현은 업계 추정일 뿐 확정치가 아니에요. 공개된 오픈웨이트 중에서는 DeepSeek-V4-Pro(1.6T MoE)와 Kimi K2.6(1T MoE)가 가장 크고, dense 구조(모든 파라미터를 한꺼번에 활성화하는 방식)로는 Llama 3.1 405B가 여전히 최대예요.
단순 규모로는 최대 프론티어 모델도 인간 뇌 시냅스의 수십 분의 1 수준이에요.
그런데 왜 고수준 작업에서 인상적인 성능을 내는가: LLM이 학습하는 데이터의 질과 밀도 때문이에요. 인간은 수십 년에 걸쳐 자신이 직접 경험한 것만 배워요. LLM은 인류가 기록한 수천억 단어 — 책, 논문, 코드, 웹 문서 — 를 동시에 압축 학습해요. 시냅스 수는 더 적지만 인류 도서관 전체를 읽은 셈이에요. 더 작은 뇌에 더 많은 책을 욱여넣은 결과, 일부 영역에서는 사람을 능가해요.
AI 학습 단계를 인간에 빗대면:
| AI 학습 단계 | 인간의 대응 |
|---|---|
| Pre-training | 유아기~학창 시절: 세상의 모든 텍스트를 읽으며 언어·지식 구조를 내재화 |
| Fine-tuning | 전공 교육·직업 훈련: 특정 도메인에 맞게 행동 방식을 좁혀나감 |
| RLHF (Reinforcement Learning from Human Feedback) | 멘토·사수의 피드백: "이건 좋아, 저건 안 돼"를 반복하며 행동 교정 |
| 학습 완료 후 가중치 | 암묵지(implicit knowledge): 자전거 타는 법처럼 몸이 기억하지만 언어로 설명하기 어려운 것 |
파라미터에 저장된 것은 명시적 사실이 아니라 패턴과 확률 구조예요. 인간의 암묵지와 성격이 비슷해요.
컨텍스트 윈도우는 단기 기억인가: 맞아요.
| 인간 | LLM | |
|---|---|---|
| 단기 기억 | 작업 기억(Working Memory), ~7±2 청크 | 컨텍스트 윈도우 (~200K 토큰) |
| 장기 기억 | 수면 중 해마→대뇌피질 공고화 | 파라미터 (학습으로 고정된 가중치) |
결정적 차이: 인간은 단기 기억의 일부가 장기 기억으로 공고화돼요. LLM은 컨텍스트에서 일어난 일이 세션이 끝나면 소멸해요 — 파라미터에 아무것도 남지 않아요. 다음 세션의 LLM은 이전 대화를 전혀 몰라요.
이것이 시스템 프롬프트 파일(예: Claude Code의 CLAUDE.md, Codex의 AGENTS.md)이 존재하는 이유예요. 세션을 넘겨도 유지해야 할 지식을 파일에 적어두고 매 세션 컨텍스트에 주입하는 방식으로, 외부 메모가 장기 기억을 보조하듯 동작해요.
그런데 바로 이 "부족함"에서 도구로서의 가치가 생겨요.
가중치가 굳어 있다는 것은 동시에 일관성을 의미해요. 인간은 피로, 감정, 경험 편향에 따라 같은 입력에도 다른 판단을 내리지만, LLM은 동일한 입력에 대해 동일한 확률 분포로 응답해요. 연속해서 변화하는 환경에 적응하는 것보다 일관된 작업에서 일관된 품질의 결과물을 내놓는 것이 중요한 상황에서 이것은 강점이에요.
그리고 몸(하네스)은 인간의 신체와 달리 설계자가 완전히 통제해요. 규칙을 바꾸고 싶으면 시스템 프롬프트 파일 한 줄을 수정하면 돼요. 도구를 추가하고 싶으면 Tool 스펙을 붙이면 돼요. 인간에게 행동 지침을 바꾸도록 요청하는 것과는 차원이 다른 통제 가능성이에요.
요약하면 이래요.
| 인간 | AI 에이전트 | |
|---|---|---|
| 뇌의 유연성 | 높음 (평생 학습) | 낮음 (가중치 고정) |
| 뇌의 일관성 | 낮음 (감정·피로·편향) | 높음 (동일 입력 = 동일 분포) |
| 몸의 확장성 | 물리 제약 있음 | 소프트웨어로 무한 확장 |
| 몸의 통제 가능성 | 낮음 | 설계자가 완전 통제 |
AI 에이전트를 활용하는 핵심 전략은 AI가 인간보다 뛰어난 영역을 찾는 것이 아니에요. 인간이 직접 하기에 비효율적인 반복·정형 작업을 일관성 있게 수행할 수 있도록, 몸(하네스)을 잘 설계하는 것이에요.
모델이 "잘 답한다"와 "헛소리를 한다" 사이의 가장 큰 변수는 모델 크기가 아니에요. 그 순간 모델 앞에 어떤 글이 펼쳐져 있는가예요. 그 펼쳐진 책상이 컨텍스트 윈도우예요.
200K 토큰짜리 컨텍스트 윈도우는 균일한 공간이 아니에요. 레이어가 있어요.
비유를 하나 빌려 와볼게요. 컨텍스트 윈도우는 거대한 작업 책상이에요. 책상 한쪽에는 매뉴얼·도구 사용 설명서가 늘 깔려 있고(정적 레이어), 그 위에 작업 중에 꺼낸 부품과 도면이 쌓여 가요(동적 레이어). 책상이 다 차면 누군가가 정리해서 메모지로 압축해야 해요(Compaction).
flowchart TB
Ceiling["천장: 200K 토큰 한계(200K token limit)"]
subgraph Dynamic["동적 레이어(Dynamic layer)"]
direction TB
Compaction["압축 버퍼(Compaction Buffer)<br/>꽉 차면 핵심만 남기고 자동 요약"]
Remaining["남은 공간(Remaining Space)"]
History["대화 기록 / 도구 결과(Conversation History / Tool Results)<br/>채팅 로그, 파일 읽기, 셸 출력, 에러<br/>작업할수록 위로 쌓임"]
Compaction --- Remaining
Remaining --- History
end
Boundary["경계: 정적 / 동적(static / dynamic boundary)"]
subgraph Static["정적 레이어(Static layer)"]
direction TB
ClaudeMd["지침 파일(CLAUDE.md / AGENTS.md)<br/>전역 → 프로젝트 순"]
Skills["스킬 파일(Skills)<br/>/skill-name 입력 시 로드"]
ToolSpecs["도구 명세(Tool Specs)<br/>하네스 정의"]
SysPrompt["시스템 프롬프트(System Prompt)"]
ClaudeMd --- Skills
Skills --- ToolSpecs
ToolSpecs --- SysPrompt
end
Floor["바닥: 컨텍스트 시작(context start)"]
Ceiling --- Compaction
History --- Boundary
Boundary --- ClaudeMd
SysPrompt --- Floor
- 시스템 프롬프트 파일 (Claude Code:
CLAUDE.md전역 → 환경 → 프로젝트 / Codex:AGENTS.md전역 → 프로젝트 → 하위 폴더, 양쪽 다 순서대로 누적) - 호출된 스킬 파일 (
/skill-name입력 시 로드)
이 레이어는 세션 내내 메모리에 고정돼요. 길수록 모든 작업에 메모리를 잡아먹어요. 가구처럼 생각하면 돼요 — 책상에 깔려 있는 매트 자체가 두꺼우면, 그 위에 올릴 수 있는 도면 면적이 그만큼 줄어들어요.
- 현재 대화 히스토리
- 도구 실행 결과 (파일 읽기,
zsh셸 출력, 에러 로그) - 코드 실행 결과, 검색 결과
동적 레이어의 핵심 문제는 정제되지 않은 원본 그대로 쌓인다는 점이에요. 파일 하나를 열면 파일 전체가, 에러가 나면 스택 트레이스 전체가, 테스트를 돌리면 모든 반복 로그가 그대로 들어와요. 대규모 작업에서는 파일 탐색만으로도 컨텍스트를 가득 채울 수 있고, 의미 없는 로그로 가득 찬 컨텍스트는 LLM의 실효 집중력을 떨어뜨려요.
세 단계로 정리하면 흐름이 한눈에 보여요.
flowchart LR
subgraph Phase1["Phase 1 — 약 10% 사용(~10% used)"]
direction TB
D1["동적 레이어: 거의 비어 있음<br/>(dynamic layer thin)"]
S1["정적 레이어<br/>(static: CLAUDE.md, skills, tool spec)"]
D1 --- S1
end
subgraph Phase2["Phase 2 — 약 70% 사용(~70% used)"]
direction TB
D2["동적 레이어: 히스토리 누적<br/>도구 출력이 무거워짐<br/>attention 희석"]
S2["정적 레이어 (불변)<br/>(static, unchanged)"]
D2 --- S2
end
subgraph Phase3["Phase 3 — Compaction 직후(post-Compaction)"]
direction TB
D3["동적 레이어: 히스토리 → 요약본<br/>도구 로그 폐기<br/>새 흐름 이어감"]
S3["정적 레이어 (불변)<br/>(static, unchanged)"]
D3 --- S3
end
Phase1 --> Phase2 --> Phase3
핵심: 정적 레이어는 세 단계 내내 고정 비용이에요. 줄어드는 건 오직 동적 레이어뿐이고, Compaction이 손대는 곳도 동적 레이어예요. 그래서 시스템 프롬프트 파일 한 줄이 반복 비용에 매번 곱셈으로 들어가요.
여기에 깜짝 사실이 하나 더 있어요. 컨텍스트 윈도우가 200K라고 해서 모델이 그 200K 전체를 똑같이 잘 보는 건 아니에요. 트랜스포머의 self-attention(자기 주의) 메커니즘은 모든 토큰 쌍 사이의 가중치를 계산하는데, 토큰이 많아질수록 한 토큰에 분배되는 attention 가중치는 그만큼 얕아져요. 영어권 연구에서는 이를 "lost in the middle" — 양 끝(시작과 끝)의 정보는 잘 챙기지만 가운데가 흐려진다 — 이라고 불러요. 직관적으로 사람이 긴 회의록의 처음과 끝만 기억하는 현상과 닮았어요. 본문에서 "attention 분산" 으로 줄여 부르는 건 직관적 요약이고, 실제로는 위치 임베딩 방식(RoPE·YaRN 등) · 학습 데이터의 길이 분포 · 어텐션 변형(SWA·GQA·MLA 등) 이 복합적으로 작용해요. 자세한 메커니즘은 어텐션 변형 부록 에서 다뤄요.
비유에는 한계가 있어요. "책상" 비유는 컨텍스트의 양적 한계와 레이어 구조를 설명하지만, 실제 모델 안쪽에서 일어나는 일은 종이를 펴는 일이 아니라 모든 토큰 쌍 사이의 관계를 계산하는 일이에요. 책상이 두 배 넓어지면 종이가 두 배 들어가는 게 아니라, 처리해야 할 짝의 개수가 네 배로 늘어나요. Prefill 비용이 길이의 제곱에 비례하는 이유예요.
이 문제의 해법이 서브에이전트(Sub-agent) 위임이에요. 탐색·반복 실행·에러 테스트처럼 컨텍스트를 많이 소모하는 작업은 서브에이전트에게 맡기고, 메인 에이전트는 깔끔하게 요약된 보고만 받는 구조예요. 다음 섹션에서 바로 이어가요.
컨텍스트가 한도에 가까워지면 Compaction이 일어나요.
Compaction은 하네스가 LLM을 한 번 더 호출해 대화 히스토리 자체를 요약하게 시키는 과정이에요. 결과적으로 정적 레이어는 그대로 유지되고, 동적 레이어의 세부 내용만 요약본으로 대체돼요.
Compaction 후에는 원래 대화 히스토리가 사라져요. 오래된 작업을 다시 언급하면 LLM이 기억 못하는 이유예요.
실천 원칙: 시스템 프롬프트 파일은 짧게 유지하고, 작업은 세션 단위로 쪼개세요. 정적 레이어에 낭비되는 메모리를 최소화하는 것이 곧 지능의 실효 컨텍스트를 늘리는 일이에요.
컨텍스트 윈도우의 구조가 왜 이렇게 생겼는지, 그리고 트랜스포머의 Prefill/Decode 단계가 컨텍스트 길이에 어떤 비용을 매기는지는 트랜스포머 추론의 두 단계: Prefill과 Decode에서 다뤄요.
한 사람이 직접 모든 자료를 다 뒤지면 책상이 어지러워져요. 같은 일을 부하 직원에게 시키고 요약만 받으면, 책상은 깔끔한 채로 핵심 정보만 손에 쥘 수 있어요. 서브에이전트가 정확히 그 부하 직원이에요.
섹션 3에서 확인한 문제 — 동적 레이어는 정제 없이 쌓여요. 코드베이스를 탐색하면 파일 전체가, 테스트를 돌리면 반복 로그 전체가, 에러가 나면 스택 트레이스 전체가 메인 컨텍스트에 들어와요.
대규모 작업이라면 파일 탐색 수백 회, 테스트 수십 번 — 그것만으로 컨텍스트가 가득 차요. 관련 없는 정보로 오염된 컨텍스트는 LLM의 실효 집중력을 떨어뜨려요.
서브에이전트(Sub-agent) 는 메인 에이전트가 생성하는 독립 에이전트예요. 별도의 컨텍스트 윈도우에서 작업을 수행하고, 완료 후 요약된 결과만 메인에게 반환해요.
sequenceDiagram
participant Main as 메인 에이전트(Main Agent)
participant Sub as 서브에이전트(Sub-agent)<br/>독립 컨텍스트
Main->>Sub: "src/ 전체에서 API 파일 찾아줘"
Note over Sub: 파일 수백 개 탐색<br/>패턴 매칭 · 로그 처리
Sub->>Main: "routes/api.py, controllers/user.py"
Note over Main: 컨텍스트에 추가된 것:<br/>요약 두 줄
메인 컨텍스트에 들어오는 것은 요약뿐이에요. 서브에이전트가 내부에서 얼마나 많은 파일을 읽고 로그를 처리했든, 메인은 결과만 받아요.
같은 작업을 직접 처리할 때와 위임할 때, 메인 컨텍스트에 들어오는 토큰의 양이 얼마나 다른지 한눈에 보면 이래요.
flowchart LR
subgraph Direct["직접 수행(DIRECT — no sub-agent)"]
direction TB
DR1["메인이 file_001.py 읽기 [+800 tok]"]
DR2["메인이 file_002.py 읽기 [+650 tok]"]
DR3["메인이 file_003.py 읽기 [+1200 tok]"]
DR4["... 추가 47개 파일 ... [+30000 tok]"]
DR5["grep 출력 [+5000 tok]"]
DR6["메인 attention이 잡음에 희석"]
DR7["합계: +37K tokens 원본 바이트"]
DR1 --> DR2 --> DR3 --> DR4 --> DR5 --> DR6 --> DR7
end
subgraph Delegated["위임(DELEGATED)"]
direction TB
DG1["메인: "src/에서 API 파일 찾아줘""]
DG2["서브에이전트(독립 컨텍스트)<br/>파일 50개 읽기, grep, 스캔<br/>내부에서 30K+ 토큰 소모 후 종료"]
DG3["메인 수신: "routes/api.py,<br/>controllers/user.py" — 두 줄"]
DG1 --> DG2 --> DG3
end
같은 작업, 같은 결론. 다만 메인 컨텍스트에는 한쪽이 37,000 토큰을 부어 넣고, 다른 한쪽은 두 줄만 받아요. 메인이 이후 작업에서 쓸 수 있는 책상 면적이 차이가 나요.
| 직접 수행 | 서브에이전트 위임 | |
|---|---|---|
| 메인 컨텍스트 증가 | 파일 수백 개 내용 전부 | 요약 단락 하나 |
| 컨텍스트 오염 | 높음 | 없음 |
| LLM 집중력 | 떨어짐 | 유지됨 |
Claude Code에서 서브에이전트는 Task 도구(또는 문서상 Agent 도구로 지칭되기도 함)로 호출해요. 작업을 위임하고 결과를 즉시 받거나, 시간이 오래 걸리는 일은 백그라운드로 돌릴 수도 있어요.
Task({
description: "코드베이스 탐색",
subagent_type: "Explore", # 탐색에 특화된 서브에이전트 프리셋
prompt: "src/ 디렉토리에서 API 관련 파일을 탐색하고 "
"파일 경로와 핵심 역할만 요약해 반환해줘. 중간 로그 생략.",
run_in_background: false # true로 주면 비동기 백그라운드 실행
})서브에이전트에 맞는 작업:
- 코드베이스 탐색 (파일 수백 개 검색)
- 반복 테스트 및 에러 로그 분석
- 독립된 유틸리티 구현
- 보안 검토, 의존성 분석
핵심: 서브에이전트 프롬프트에 출력 형식을 명시하세요.
"탐색 후 파일 경로와 핵심 내용만 반환해줘. 중간 과정은 생략."
결과를 통째로 받으면 메인 컨텍스트가 똑같이 오염돼요. 요약 형식을 프롬프트에서 강제하는 것이 서브에이전트 활용의 핵심이에요.
Codex CLI 도 같은 위임 메커니즘을 갖고 있어요. 정의는 ~/.codex/config.toml 의 [agents] 테이블에 두고, 세션 안에서는 /agent 슬래시 커맨드로 활성 스레드를 전환해요. 별도 토글 없이 기본 활성이라 설정 파일에 에이전트만 등록하면 바로 써요. 큰 작업을 여러 갈래로 쪼개고 싶을 때는 spawn_agents_on_csv 같은 위임 도구로 분기해요.
# ~/.codex/config.toml
# 서브에이전트 1개 등록 (instructions 는 별도 파일로 분리)
[agents.explore]
description = "코드베이스 탐색 전용"
config_file = "./agents/explore.toml" # 본문은 별도 TOML 파일에
# 분기 한도 — [agents] 글로벌 테이블 직속
[agents]
max_threads = 4 # 동시 실행 스레드 수
max_depth = 2 # 재귀 분기 한도
job_max_runtime_seconds = 600 # 한 서브에이전트 작업 시간 한도./agents/explore.toml 같은 별도 파일에는 instructions 본문이 들어가요 — 예컨대 "src/ 디렉토리에서 요청한 파일을 탐색하고 파일 경로와 핵심 역할만 한 줄씩 요약해 반환해라. 중간 로그·grep 출력은 절대 본문에 넣지 마라" 같은 한 단락.
# 세션 안에서
/agent explore "src/ 에서 API 관련 파일만 골라줘"
호출 형식은 다르지만 자리는 정확히 같아요 — Claude Code 의 Task 도구가 함수 호출이라면 Codex 는 설정 파일 + 슬래시 커맨드의 짝이에요. 둘 다 별도 컨텍스트 윈도우에서 실행 → 요약만 메인으로 반환이라는 핵심 동작이 동일하고, 작업 시간 / 분기 한도를 잡는 토글이 있다는 점도 닮았어요. Codex 쪽 상세는 Codex 사용 가이드 §5 에서 다뤄요.
두 도구 공통의 핵심: 어느 쪽이든 서브에이전트 프롬프트에 출력 형식을 못박는 한 줄이 결과 품질을 결정해요. "탐색 후 파일 경로와 핵심 내용만 반환, 중간 과정 생략" — 이 한 줄이 빠지면 위임의 의미가 사라져요.
"더 큰 모델 = 더 나은 에이전트"는 틀린 공식이에요. 그리고 이 한 문장이, 2026년 현재 에이전트 설계의 가장 반직관적인 진실 중 하나예요.
| Big Brain + Weak Body | Sharp Brain + Strong Body | |
|---|---|---|
| 모델 크기 예 | GLM-5.1급 (744B MoE) | Gemma4:31b급 (30B dense) |
| 하네스 품질 | 기본 설정, 지침 빈약 | 정교한 지침 주입, 자동화된 오류 감지, 절차 안내 |
| 메모리 부담 | 동일 컨텍스트에서 수 배 더 큼 | 가볍고 빠름 |
| 반복 작업 정확도 | 지침을 간혹 무시 | 하네스가 강제, 일관성 높음 |
| 비용 | 높음 | 낮음 |
| 결과 | 느리고 비싸고 불안정 | 빠르고 저렴하고 일관적 |
표에서 보듯, 큰 모델은 KV 캐시가 더 무겁고 비용도 높지만 하네스가 빈약하면 일관성이 떨어져요. 작은 모델이라도 하네스가 잘 설계되어 있으면 반복 작업에서 더 안정적인 결과를 내요.
같은 컨텍스트를 채우면 GLM-5.1(744B MoE)의 단기 기억은 Gemma4 31B의 수 배예요. 메모리가 더 무겁고, 처리 속도도 느려요. 반면 Gemma4 31B에 완벽히 설계된 하네스는
- 반복 지침을 매 호출마다 빠짐없이 주입하고
- 오류를 즉시 감지해 루프를 끊거나 재시도하고
- 복잡한 절차를 단계별로 안내해요.
모델 업그레이드보다 하네스 정교화가 먼저예요.
비유를 하나 더 빌려 와볼게요. 두 변호사를 떠올려 보세요. 한쪽은 천재적인 머리를 가졌지만 사무실이 어지럽고 비서가 없어요. 다른 한쪽은 평범한 두뇌지만, 정돈된 사무실에 능숙한 비서와 검토 절차가 있어요. 의뢰인이 여러 건을 일관된 품질로 처리받고 싶다면 누구를 택할까요. 답은 거의 항상 후자예요. 에이전트도 마찬가지예요.
최근 경향은 이 비대칭을 더 뒤집고 있어요. 2026년의 경량 모델(Qwen3.6 27B, Gemma4 26B-A4B, Nemotron Cascade 2 등)이 1-2년 전 400B급 모델의 reasoning 수준을 따라잡고 있어요. 작은 모델 + 좋은 하네스 조합이 현실적인 선택지가 되고 있다는 뜻이에요. "397B를 이긴 27B"라는 부록 제목이 과장이 아니에요. 상세한 벤치마크와 원인 분석은 397B를 이긴 27B에서 다뤄요.
하네스의 확장은 여기서 끝나지 않아요. 외부망 환경에서는 웹 검색과 MCP 서버(Model Context Protocol — 외부 시스템을 에이전트의 도구로 연결하는 프로토콜)를 통해 GitHub, Slack, Linear, DB, 브라우저 등 어떤 외부 시스템이든 에이전트의 네이티브 도구로 편입할 수 있어요. 코드 작업 중에 이슈를 열고, 결과를 Slack에 보내고, DB를 직접 조회하는 일이 하나의 대화 흐름 안에서 이뤄져요. 폐쇄망 환경에서 웹 검색·MCP가 차단되는 게 아쉬운 이유가 여기 있어요. (Claude Code 기준 MCP 서버 상세는 Claude Code 3대 설정 축, Codex 기준은 Codex 사용 가이드)
서브에이전트는 코딩 에이전트가 내부에서 처리해주는 방식이에요. 여기서 한 단계 더 나아가면 에이전트를 오케스트레이터(orchestrator — 여러 에이전트 노드를 지휘하는 중앙 에이전트)로 삼아 여러 LLM 노드를 직접 설계하고 연결할 수 있어요.
각 노드는 독립된 시스템 프롬프트와 하네스를 가져요. 오케스트레이터가 입력을 중계하고, 조건에 따라 분기하거나 루프를 돌려요.
flowchart TD
Orch["오케스트레이터(Orchestrator)<br/>코딩 에이전트(Coding Agent)"]
Writer["작성자 LLM(Writer LLM)"]
Reviewer["검수자 LLM(Reviewer LLM)"]
Done["완료(done)"]
Orch --> Writer
Writer -->|"초안(draft)"| Reviewer
Reviewer -->|"수정 요청(revision)"| Writer
Reviewer -->|"통과(pass)"| Done
작성-검수 루프가 가장 직관적인 예예요.
- Writer LLM이 초안 작성 (시스템 프롬프트: "간결하고 명확하게")
- Reviewer LLM이 검토 후 피드백 반환 (시스템 프롬프트: "엄격히 비평, 통과 기준 명시")
- 피드백이 있으면 Writer가 수정 → 2번으로
- 기준 충족 시 루프 종료
Writer와 Reviewer를 분리하면 역할 간 충돌이 사라져요. 하나의 LLM이 작성과 비평을 동시에 맡으면 자기 결과물에 관대해지는 경향이 있어요. 역할을 나누면 Reviewer는 오직 비평에만 집중해요.
모델도 역할에 맞게 배분할 수 있어요. 비용이 높은 Opus는 검수에만 쓰고 Haiku로 초안을 쓰면 품질을 유지하면서 비용을 줄일 수 있어요.
이 패턴을 확장하면 이렇게 돼요.
| 구조 | 예시 |
|---|---|
| 작성 → 검수 → 루프 | 문서·코드 생성, 번역 품질 관리 |
| 분석 → 요약 → 검증 | 논문 리뷰, 데이터 분석 보고서 |
| 계획 → 실행 → 반성 | 리팩터링, 시스템 설계 반복 개선 |
| 전문가 패널 (병렬) | 여러 관점 동시 검토 후 합의 |
구현: Anthropic Python SDK(또는 OpenAI SDK)로 각 노드의 LLM 호출을 스크립트로 작성하고, 코딩 에이전트가 이를 오케스트레이션해요. 또는 Claude Code의 Task 도구·Codex의 위임 기능을 루프 구조로 연결하는 방법도 있어요.
각 노드의 시스템 프롬프트 설계가 파이프라인 전체 품질을 결정해요. 하네스 설계 원칙이 노드 단위로도 그대로 적용돼요.
Part I가 "에이전트는 어떻게 생겼는가"를 다뤘다면, Part II는 그것을 어떻게 길들이는가예요. 이론에서 실무로 옮겨가요.
앞서 본 구조(뇌·몸·컨텍스트·서브에이전트·하네스)를 실제 작업에서 어떻게 다루는지 — 11개 원칙으로 정리했어요.
이 섹션부터 이어지는 원칙들은 주간 70시간 이상 코딩 에이전트를 사용하면서 얻은 경험에서 나왔어요. 밥 먹을 때, 씻을 때, 자다 일어나서, 회사에서 하루종일, 이동 중에, 화장실에서까지 — 그렇게 몸으로 검증한 패턴들이에요.
세션이 길어질수록 관련 없는 컨텍스트가 뒤섞이고, Compaction이 중요한 내용을 날려요. 컨텍스트가 오염됐다 싶으면 새 세션을 여는 게 나아요.
/clear # 또는 새 세션 시작한 번 꼬인 컨텍스트는 수습하려 할수록 더 커져요. 얽힌 실타래를 풀려고 더 잡아당기면 매듭만 굵어져요. 일찍 리셋하는 게 빨라요.
컨텍스트 오염의 주요 원인 — 세션 내 중구난방 요청. 하나의 세션에서 "이것도 해줘, 저것도 해줘"를 섞으면, 서로 무관한 파일 읽기·실행 결과·대화 흐름이 전부 동적 레이어에 쌓여요. LLM 입장에서는 이 모든 정보를 고려하며 응답해야 하므로, 판단 품질이 점점 떨어져요. 트랜스포머 구조상 Attention이 컨텍스트 전체를 참조하기 때문에, 이는 "집중력 저하"에 그치지 않고 연산 비용과 세션 재개 지연으로도 이어져요. → 트랜스포머 추론의 두 단계: Prefill과 Decode
이 문제를 다루는 컨텍스트 관리용 슬래시 커맨드는 대부분의 코딩 에이전트가 제공해요. 아래는 Claude Code 사례예요.
/btw — 진행 중에 문득 떠오른 곁가지 질문을 처리할 때 써요. 메인 작업 흐름을 건드리지 않고 짧게 답변만 받을 수 있어요.
/branch — 현재까지의 컨텍스트를 공유하면서 다른 방향으로 탐색할 때 써요. 예를 들어, 같은 버그를 두 가지 접근 방식으로 각각 살펴보고 싶을 때 분기점에서 /branch를 치면 메인 컨텍스트를 오염시키지 않고 실험할 수 있어요.
컨텍스트 사용량 모니터링: 언제 리셋할지 직관으로 판단하면 너무 늦는 경우가 많아요. 에이전트 상태표시줄(statusline)을 설정하면 사용량을 수치로 실시간 확인할 수 있어요.
Claude Code 기준으로는 ~/.claude/settings.json에 statusLine 커맨드를 등록하면 돼요. 예시는 아래처럼 생겼어요.
{
"statusLine": {
"type": "command",
"command": "jq -r '\"CTX \\(.context.used_percentage)%\"'"
}
}위 예시는 개념 스케치예요. statusLine 커맨드가 stdin으로 받는 JSON 스키마(필드명)는 에이전트 버전마다 달라질 수 있으니, 정확한 필드는 공식 문서로 확인하고 적용하세요. 가장 안전한 방법은 자연어로 요청해 에이전트가 직접 스크립트를 작성하게 하는 거예요.
/statusline CTX 24K / 200K (12%) 형태로 보여줘
표시 예: CTX 12% → CTX 67% → CTX 89%
판단 기준:
- ~30% 이하: 여유
- 60% 이상: 작업 마무리 고려
- 80% 이상: Compaction 직전 — 새 세션 전환 적극 고려
(구체적인 Claude Code 설정 디테일은 Claude Code 3대 설정 축, Codex 쪽은 Codex 사용 가이드 참조.)
에이전트가 실행 중 로드하는 모든 것 — Python 패키지, 파일, 도구 출력 — 이 동적 레이어에 쌓여요. 불필요하게 큰 출력을 파이프로 다 집어넣거나, 거대한 종속성을 통째로 읽히는 건 메모리 낭비예요.
pip3의존성은 실제로 필요한 것만- 파일 읽기는 필요한 부분만 지정해서
- 셸 출력은 필요한 필드만
grep해서 넘기기
컨텍스트에 들어오는 정보량을 줄이는 것이 곧 LLM이 집중할 수 있는 유효 공간을 늘리는 일이에요.
큰 프로젝트일수록 설정을 먼저 다듬는 게 ROI가 압도적으로 높아요.
시스템 프롬프트 파일(Claude Code의 CLAUDE.md, Codex의 AGENTS.md)에 규칙 한 줄 추가로 해결되는 문제를 프롬프트에서 매번 설명하고 있다면, 수십 번의 반복 비용을 지불하고 있는 거예요. 에이전트와 일하기 전에 "이 에이전트를 어떻게 세팅할 것인가"에 시간을 써보세요.
언제 적용할까요: 같은 지시·정정·교정을 두 번 이상 반복하고 있다면, 그건 곧 메타 최적화 후보예요. 같은 설명을 매 세션마다 다시 적고 있다면 더 강한 신호예요. 시스템 프롬프트 파일 규칙 한 줄이 수십 번의 반복 지시를 대체해요. 초반에 설정에 투자하는 시간이 이후 작업 전체의 품질과 속도를 결정해요.
언제 안 할까요: 일회성 작업, 또는 실험 단계라 규칙이 자주 바뀔 게 뻔한 시점에 메타 최적화에 시간을 쏟는 건 낭비예요. 규칙은 안정된 다음에 박아요.
에러가 났을 때 시스템 프롬프트 파일에 "만약 X 에러가 나면 무시해"를 추가하고 싶은 유혹이 와요. 하지 말아요.
- 땜빵 규칙이 누적되면 LLM이 모순된 지침 사이에서 충돌을 일으켜요
- 최악의 경우 환각(hallucination)을 유발해요
- 근본 원인을 찾아 고치세요 — 지침은 얇을수록 좋아요
비유로 풀면 — 일정한 신호등을 가린 임시 표지판과 같아요. "이 표지판은 무시하세요"가 늘어날수록 운전자(LLM)는 매 교차로에서 결정을 머뭇거려요. 땜빵은 빚이에요. 두꺼운 지침은 LLM이 어떤 규칙을 따라야 할지 충돌을 일으켜요.
시스템 프롬프트 파일(Claude Code의 CLAUDE.md, Codex의 AGENTS.md)은 매 세션 컨텍스트에 통째로 올라가요. 파일이 길어질수록 관련 없는 작업에도 항상 무거운 정적 레이어를 얹게 돼요.
해법은 트리거(trigger) 예요. 모든 지식을 시스템 프롬프트 파일에 직접 쓰는 대신, "이 상황이 오면 이 파일을 읽어라"는 조건부 참조 지시만 남겨요. 실제 내용은 별도 파일에 두고 필요한 순간에만 로드돼요.
비유로 풀면 — 시스템 프롬프트 파일은 사전이 아니라 목차예요. 두꺼운 사전을 통째로 들고 다닐 필요 없이, "어떤 단어가 어느 페이지에 있는지"만 적어두면 돼요. 필요한 페이지는 그때 펼쳐요.
트리거 예시 (Claude Code의 CLAUDE.md 또는 Codex의 AGENTS.md 안에 작성):
## 트리거 참조
- API 엔드포인트 작업 시: 반드시 `docs/api-conventions.md`를 먼저 읽어라
- DB 스키마 변경 전: `docs/db-migration-checklist.md` 참조 필수
- 테스트 추가·수정 시: `docs/testing-guide.md` 확인이 방식이 동작하는 이유: LLM은 시스템 프롬프트 지침을 실제로 준수해요. "이 상황에서는 반드시 이걸 참조하라"는 문장은 해당 상황이 왔을 때 Read 도구 호출을 유발해요. 그 지식은 필요한 세션의 동적 레이어에만 들어오고, 무관한 세션에서는 전혀 로드되지 않아요.
슬림화 원칙:
- 시스템 프롬프트 파일에는 조건·트리거·파일 참조만 남기세요
- 절차나 규칙의 구체적 내용은 별도 파일(
api-conventions.md,testing-guide.md등)에 위임하세요 - 지식 파일도 짧고 집중적으로 — 불필요한 내용을 트리거 파일에 쏟아붓지 마세요
시스템 프롬프트 파일이 두꺼워질 것 같으면, 그 내용을 별도 파일로 빼고 트리거만 남기세요. 지침 파일이 얇을수록 LLM이 판단에 집중할 수 있는 실효 컨텍스트가 늘어나요.
원칙 1~5가 "환경 정돈"이었다면, 원칙 6~11은 그 환경 안에서 한 작업을 어떻게 시작·진행·마무리하느냐예요. 시작 단계의 판단이 결과 품질의 절반을 결정해요.
원칙 6~11의 큰 그림을 한눈에 보면, 새 작업을 받았을 때 어떤 길로 갈지 흐름도가 보여요.
flowchart TD
Start["새 작업 도착(New task arrives)"]
Q1{"요구사항이 명확한가?<br/>(Requirements clear?)"}
Plan["Plan Mode<br/>(Shift+Tab)"]
Clarified["요구사항 명확화<br/>(clarified)"]
Q2{"기계적·반복 작업인가?<br/>(Mechanical / repetitive?)"}
Script["스크립트로 처리<br/>(Bash/Python)"]
Direct["LLM 직접 수행<br/>(LLM does it direct)"]
Q3{"범위가 넓은가?<br/>(Wide scope?)"}
Split["요청을 쪼개기<br/>(Split request)"]
Single["한 번에 처리<br/>(Single shot)"]
Start --> Q1
Q1 -->|"아니오(NO)"| Plan
Q1 -->|"예(YES)"| Q2
Plan --> Clarified
Clarified --> Q2
Q2 -->|"예(YES)"| Script
Q2 -->|"아니오(NO)"| Direct
Direct --> Q3
Q3 -->|"예(YES)"| Split
Q3 -->|"아니오(NO)"| Single
흐름의 핵심: 명확하지 않으면 Plan Mode(원칙 8), 기계적이면 스크립트(원칙 9), 범위가 넓으면 쪼개기(원칙 11). 그리고 어느 분기든 끝에는 체크리스트(원칙 6) + CONTINUE.md(원칙 7) 가 따라와요.
연관된 작업이라도 한 세션에서 전부 처리하려 하면 컨텍스트가 부족해요. 대규모 작업을 시작할 때는 먼저 체크리스트를 만들고, 항목 하나씩 격파해 보세요.
## 리팩터링 체크리스트
- [x] auth 모듈 분리
- [ ] API 레이어 분리
- [ ] 테스트 커버리지 확인
- [ ] 문서 업데이트워크플로우:
- 세션 시작 시 작업 목록을
checklist.md에 정리 - 항목 하나를 완료하면 체크 표시 후 커밋 (커밋이란?)
- 필요하면 새 세션을 열고 다음 항목 진행
한 세션에서 모두 처리하면 컨텍스트가 무거워지고, Compaction이 앞에서 한 작업 내용을 날려요. 세션마다 항목 하나에 집중하면 각 세션이 가볍고 깨끗하게 유지돼요.
체크리스트 파일은 시스템 프롬프트 파일(CLAUDE.md/AGENTS.md)에 트리거로 연결해두면 다음 세션에서 자동으로 로드돼요.
## 트리거 참조
- 진행 중인 작업이 있으면: 반드시 `checklist.md`를 먼저 읽어라세션을 닫을 때 "문서 정리해줘"라고 하면 에이전트가 다음 세션용 인수인계 문서를 작성해요. 다음 세션에서 @CONTINUE.md 한 마디면 즉시 상황 브리핑과 다음 할 일을 받을 수 있어요.
비유로 풀면 — 교대 근무 일지예요. 야간조에서 주간조로 넘어갈 때, 어디까지 했고 무엇이 미해결이고 누구에게 무슨 알림이 와야 하는지를 한 장에 적어두면, 새 사람이 즉시 일을 이어갈 수 있어요. CONTINUE.md가 정확히 이 역할이에요.
그런데 세션을 새로 열지, 아니면 지금 세션을 이어갈지 판단이 서지 않을 때가 있어요. 이것도 에이전트에게 물어보면 돼요.
"지금 세션 정리하고 새로 시작하는 게 나을까, 아니면 여기서 계속하는 게 나을까?"
남은 컨텍스트 여유, 다음 작업과의 연관성, 현재 세션에서 파악한 정보의 재사용 가치를 에이전트가 종합해서 판단하고 권장해줘요.
시스템 프롬프트 파일 vs CONTINUE.md 역할 분리:
| 파일 | 내용 | 수명 |
|---|---|---|
CLAUDE.md / AGENTS.md |
영속적 프로젝트 구조·규칙·스타일 | 계속 누적 |
CONTINUE.md |
현재 작업 상태·미해결 이슈·다음 단계 | 매 세션 덮어씀 |
트리거와의 차이:
@CONTINUE.md직접 태그 → "이어하자"는 의도적 재개. 에이전트가 즉시 브리핑하고 다음 할 일을 제안해요.- 시스템 프롬프트 파일 트리거 → 태그를 까먹었을 때의 안전망. 두 가지를 함께 써도 충돌하지 않아요.
무엇을 어디에 쓸 것인가:
- CONTINUE.md: 지금 어디까지 했고, 미해결 이슈가 뭔지, 다음 세션에서 무엇부터 할지
- 시스템 프롬프트 파일: 반복되는 실수에서 얻은 교훈, 아키텍처 결정, 스타일 규칙 — 세션이 바뀌어도 유지해야 할 것
세션 단위 작업 상태를 시스템 프롬프트 파일에 쌓지 마세요. 파일이 두꺼워지고, Compaction 후에도 계속 정적 레이어를 차지해요.
설정 방법 — 전역 시스템 프롬프트 파일에 트리거 등록:
"문서 정리해줘" 한 마디로 CONTINUE.md가 자동 생성되는 건 전역 시스템 프롬프트 파일에 자연어 트리거를 등록해뒀기 때문이에요. Claude Code라면 ~/.claude/CLAUDE.md, Codex라면 글로벌 AGENTS.md에 아래처럼 작성해요.
## 세션 정리 트리거
사용자가 "문서 정리해", "세션 정리해", "다음 세션 지침 만들어" 등의 뉘앙스로 요청하면:
1. 프로젝트 루트의 시스템 프롬프트 파일에 이번 변경으로 생긴 영속적 정보를 반영한다
2. 프로젝트 루트의 `CONTINUE.md`에 현재 작업 상태·미해결 이슈·다음 단계를 기록한다
3. 작성 후 "CONTINUE.md 준비 완료, 새 세션에서 `@CONTINUE.md`로 이어가면 돼!" 안내전역 지침에 등록하면 모든 프로젝트 세션에 적용돼요. 특정 프로젝트에만 다르게 동작하게 하려면 해당 프로젝트의 시스템 프롬프트 파일에 덮어쓰면 돼요.
이것이 원칙 5의 트리거 패턴을 메타적으로 적용한 사례예요 — 에이전트 자체의 동작을 시스템 프롬프트 자연어 지침으로 확장하는 방식이에요.
작업을 시작할 때 요구사항이 완전히 명확한 경우는 드물어요. 일부 조건을 빠뜨리거나, 목표 자체가 모호하거나, 무엇이 필요한지 시작해봐야 알게 되는 경우가 많아요. 이 상태에서 바로 실행에 들어가면 엉뚱한 방향으로 구현이 진행되고, 수정 비용이 커져요.
Plan Mode는 에이전트가 파일을 읽거나 코드를 수정하지 않고, 구현 계획만 텍스트로 제안하는 모드예요. 실행 전에 방향을 조율하는 대화 공간이에요.
진입 방법(Claude Code 기준):
Shift+Tab # 입력창에서 토글
/plan # 슬래시 커맨드
Codex CLI 등 다른 에이전트도 비슷한 계획 모드·승인 단계를 제공해요(상세는 Codex 사용 가이드).
계획 모드에서 에이전트는 "어떤 파일을 어떻게 수정할지, 어떤 순서로 진행할지"를 먼저 제안해요. 이 단계에서
- 빠뜨린 조건을 발견할 수 있어요
- "이 부분은 이렇게 바꿔줘"로 방향을 수정할 수 있어요
- 에이전트가 잘못 이해한 부분을 실행 전에 잡을 수 있어요.
계획이 충분히 구체화되면 승인하고 실행해요. 계획 없이 바로 실행했을 때보다 결과물이 요구사항에 맞을 확률이 높고, 재작업이 줄어요.
복잡한 작업일수록, 요구사항이 모호할수록 계획 모드로 시작하세요. 충분히 상의하고 나서 실행하는 게 처음부터 다시 짜는 것보다 빨라요. 목수의 격언 그대로 — 두 번 재고 한 번 자른다.
계획 모드가 필요한지 판단이 서지 않으면, 에이전트에게 직접 물어보세요.
"이 작업, 바로 시작해도 될까 아니면 계획 모드로 먼저 정리하는 게 나을까?"
작업의 복잡도와 모호성을 에이전트 스스로 판단하고 권장해줘요.
같은 패턴의 작업을 LLM이 직접 반복 처리하면 두 가지 문제가 생겨요. 파일 하나를 읽을 때마다 내용 전체가 컨텍스트에 쌓이고, 중간에 오류가 나면 어디서 틀렸는지 추적하기 어려워요.
워크플로우를 바꿔보세요:
- "이 작업을 셸 스크립트(또는 파이썬 스크립트)로 짜줘"
- 스크립트가 의도한 대로 동작하는지 확인
- 실행 → 결과만 확인
LLM이 직접 100개 파일을 열어 수정하면 컨텍스트에 100번 쌓여요. 스크립트로 위임하면 최종 실행 결과 한 줄만 들어와요. 스크립트는 파일로 남으니 재사용과 수정도 쉬워요.
비용 관점에서 한 줄 비교:
| LLM 직접 처리 | 스크립트 위임 | |
|---|---|---|
| 컨텍스트 토큰 | 파일 100개 × 평균 500 tok = 50K+ | 스크립트 한 줄 결과 (~수십 tok) |
| 비용 | 매 회 LLM 호출 비용 | 스크립트 1회 작성 + 무료 실행 |
| 재현성 | 매번 다른 결과 가능 | 동일 입력 = 동일 출력 |
| 디버깅 | 어디서 틀렸는지 추적 어려움 | 스크립트 줄 번호로 즉시 추적 |
스크립트 방식이 유리한 작업:
- 파일 이름·디렉토리 일괄 정리
- CSV / JSON 데이터 일괄 변환·정제
- 코드베이스 전체 패턴 치환 (find & replace)
- 로그 분석, 반복 빌드·테스트 자동화
LLM이 직접 처리하는 게 나은 경우: 파일마다 내용을 이해하고 판단해야 하거나, 맥락에 따라 처리 방식이 달라지는 작업은 스크립트화하기 어려워요. 이런 작업은 서브에이전트 위임(섹션 4)을 고려해 보세요.
코딩 에이전트는 어느 정도 스스로 판단하기도 하지만, 명시적으로 "스크립트 먼저 짜줘"라고 요청하면 더 일관되게 동작해요.
함수를 모듈 단위로 작성하면 테스트가 필요해요. 그런데 "그럴듯한 가짜 입력"을 손으로 만드는 건 생각보다 시간이 걸려요. 실제 데이터가 없거나 민감 데이터라 직접 쓸 수 없는 경우는 더욱 그렇죠.
에이전트는 이 작업을 즉시 해줘요.
"이 함수에 대한 테스트 스크립트 짜줘. 정상 케이스 3개 + 엣지 케이스 2개."
"이 JSON 스키마에 맞는 샘플 데이터 100개 생성하는 스크립트 만들어줘."
"이 클래스 테스트할 가짜 입력 만들어줘."
테스트 데이터뿐 아니라 테스트 스크립트 자체도 뚝딱 만들어줘요. 코드 구조를 읽고 "어떤 입력이 의미 있는지"를 스스로 판단하기 때문에 가능한 일이에요.
효과적인 모듈 테스트 워크플로우:
- 함수 구현 완료
- "이 함수 테스트 스크립트 짜줘, 엣지 케이스 포함" 요청
- 스크립트 검토·실행
- 실패 케이스 발견 → 구현 수정
모듈화와 코딩 에이전트를 조합하면 테스트 데이터를 손으로 구성하는 시간 없이 테스트 루프를 빠르게 돌릴 수 있어요.
"문서 검토해줘"는 너무 넓어요. LLM은 범위가 모호한 요청일수록 모든 차원을 동시에 얕게 훑는 경향이 있어요.
같은 문서에 대한 요청을 목적별로 나누면 결과가 달라져요.
| 모호한 요청 | 구체적인 요청 |
|---|---|
| "문서 검토해줘" | "오탈자·문법 오류만 찾아줘" |
| "문체와 용어가 전체에서 통일됐는지 봐줘" | |
| "논리 흐름에 빠진 전제나 모순이 있는지 확인해줘" | |
| "섹션 순서가 자연스러운지, 재배치가 필요한 곳 있는지 봐줘" | |
| "읽기 어려운 문장 위주로 가독성 개선을 제안해줘" |
같은 문서를 다섯 번 보내도 매번 다른 결과가 나와요. 요청마다 LLM이 집중하는 차원이 다르기 때문이에요.
왜 차이가 나는가: 넓은 요청은 LLM이 "검토"의 범위를 스스로 정의해요. 그 결과 눈에 띄는 것만 집어내는 얕은 패스가 돼요. 좁은 요청은 평가 기준이 명확하므로 그 기준 하나에만 집중하는 깊은 패스가 돼요.
이는 문서 검토에만 국한되지 않아요. 코드 리뷰도 마찬가지예요.
- "코드 리뷰해줘" → 표면적 검토
- "보안 취약점만 확인해줘" / "성능 병목 찾아줘" / "에러 핸들링이 누락된 곳 봐줘" → 차원별 깊은 검토
요청을 정확하게 할수록 에이전트는 쓸모있어져요.
원칙 6부터 11까지 — 시스템 프롬프트 슬림화, 체크리스트 작성, 작업 분해, 스크립트화, 테스트 데이터 — 모두 직접 손으로 할 필요가 없어요. 에이전트에게 현재 상태를 보여주고 의견을 물어보세요.
"이 CLAUDE.md(또는 AGENTS.md) 너무 길어 보이는데 슬림화할 수 있을까?"
"이 작업 목록을 세션 단위로 쪼개서 체크리스트로 만들어줘."
"지금 시스템 프롬프트 파일에 트리거 구조를 도입하면 어떨까?"
LLM은 파일을 읽고 구조를 파악한 뒤 바로 제안하고 실행해요. 어떻게 나눌지 판단하는 것 자체가 LLM이 잘하는 일이에요. 하네스를 설계한 사람의 역할은 방향을 정하고 의견을 묻는 것 — 구체적인 파일 편집과 구조화는 에이전트에게 위임해 보세요.
전역 트리거로 워크플로우 전체를 자동화하세요:
원칙 6과 원칙 7을 매번 수동으로 요청할 필요 없이, 전역 시스템 프롬프트 파일에 트리거를 등록해두면 에이전트가 작업 흐름에서 자동으로 수행해요.
## 작업 트리거
사용자가 구체적인 작업(구현, 수정, 분석 등)을 요청하면:
1. 작업 시작 전 `checklist.md`를 생성한다:
- 수행할 작업 목록
- 각 항목의 완료 검증 기준 (어떻게 확인할지)
2. 작업 완료 후 각 검증 기준의 결과를 확인하고 출력한다
3. 다음을 판단하여 제안한다:
- 문서 정리(CONTINUE.md) 후 새 세션 시작이 적절한지
- 현재 세션에서 다음 작업을 계속하는 것이 나은지
- 판단이 어려우면 사용자에게 직접 묻는다이 트리거 하나로
- 작업 범위가 시작 전에 명확해져요 (체크리스트)
- 완료 기준이 사전에 합의돼요 (검증 항목)
- 세션 전환 판단을 에이전트가 능동적으로 제안해요.
"구체적인 작업" 요건을 명시하는 게 중요해요. 조건 없이 등록하면 짧은 질문이나 단순 조회에도 체크리스트가 생성되어 오히려 번거로워져요.
에이전트별 상세 설정 — Claude Code의
CLAUDE.md·Hooks·Skills 세 축은 Claude Code 3대 설정 축에서, Codex의AGENTS.md·승인 모드·MCP 설정은 Codex 사용 가이드에서 다뤄요.
지금까지의 모든 최적화 — 세션 분할, 시스템 프롬프트 슬림화, 서브에이전트 위임, 트리거 패턴 — 는 결국 같은 천장을 떠받치고 있어요. 그 천장이 무엇으로 만들어져 있는지가 마지막 이야기예요.
현재의 에이전트 운용은 KV 캐시를 쥐어짜며 버티는 방식이에요.
- 세션을 쪼개요 — KV 캐시가 쌓이지 않게
- 시스템 프롬프트 파일을 짧게 유지해요 — 정적 레이어가 무겁지 않게
- Compaction에 의존해요 — 터지기 전에 스스로 요약하도록
하지만 이 모든 최적화는 물리적 한계 위에서 이뤄져요. 아무리 잘 설계된 하네스도 대역폭보다 빠를 수 없고, 아무리 정교한 컨텍스트 관리도 메모리 용량보다 많은 정보를 담을 수 없어요.
에이전트의 자아가 깊어지는 것은 컨텍스트 윈도우가 넓어지는 것이에요. 256K가 1M이 되고 10M이 될 때마다, 에이전트가 한 번에 다룰 수 있는 작업의 반경이 넓어져요. 그 가능성을 여는 열쇠는 초대용량, 압도적 대역폭의 메모리에 있어요.
지능의 크기는 뇌(파라미터)가 아니라 단기 기억(KV 캐시)을 퍼 나르는 속도가 결정해요.
깜짝 사실 하나로 마무리하자면 — 현대 LLM 추론에서 GPU가 실제로 연산을 수행하는 시간보다, 모델 가중치와 KV 캐시를 메모리에서 GPU 코어로 옮겨오는 시간이 더 길어요. 즉 토큰 생성 속도의 진짜 한계는 "계산 능력"이 아니라 "데이터 운반 능력"이에요. 이것이 Apple Silicon의 통합 메모리(UMA), NVIDIA H100/B200의 HBM (High Bandwidth Memory — GPU 옆에 3D로 쌓아올린 고대역폭 메모리), AMD MI300X 같은 고대역폭 메모리 아키텍처가 LLM 시대에 그렇게 중요해진 이유예요. 상세한 메커니즘은 LLM 구동의 주요 스펙: 메모리 용량과 대역폭과 파라미터 착시: KV 캐시의 진실에서 다뤄요 (KV 캐시 절약 쪽 어텐션 변형·추론 시스템 커널은 부록 표에서 함께 살펴보세요).
이 거대한 컨텍스트의 바다를 감당할 준비가 되어 있나요?
| 문서 | 내용 |
|---|---|
| 파라미터 착시: KV 캐시의 진실 | KV 캐시 폭발 수치, 대역폭 병목, MoE·Hybrid Attention의 영향 |
| 양자화와 KV 압축 | Q4_K_M·Unsloth Dynamic·표준 KV 양자화·TurboQuant의 차이와 선택 기준 |
| 어텐션 변형 — SWA·GQA·MLA·RoPE/YaRN | SWA·sink·GQA·MQA·MLA·Decoupled RoPE·YaRN의 1차 출처 메커니즘 |
| 추론 시스템·커널 최적화 — FlashAttention·PagedAttention·Continuous Batching·Prefix Caching | FA-v1/v2/v3·PagedAttention·ORCA·SGLang RadixAttention의 1차 출처 수치 |
| 트랜스포머 추론의 두 단계: Prefill과 Decode | Prefill·Decode 구조, 세션 재개 비용, 컨텍스트 오염과의 연결 |
| 리즈닝 모델의 딜레마 | RLVR 학습, thinking 토큰 비용, 실무 사용 가이드 |
| 안전한 AI는 더 약한 AI인가? | Alignment tax, RLHF·CAI 메커니즘, over-refusal, alignment faking |
| 397B를 이긴 27B: 경량 모델이 대형 모델을 따라잡는 이유 | 2026년 벤치마크로 본 역전 현상, 원인 4축, 실무 시사점 |
| 최근 여섯 모델 | Gemma4 26B-A4B·Gemma4 31B·Qwen3.6 27B/35B-A3B·DeepSeek V4 Flash/Pro 구조 비교 |
| DFlash: 블록 확산 드래프터로 6배 빨라지는 투기적 디코딩 | 표준 spec decoding 복습, block diffusion drafter 동작, 추가 메모리(0.5–1B), 조건별 speedup, FP8 KV 비호환 |
| RAG 아키텍처 | 청킹·임베딩·하이브리드 검색·리랭킹·GraphRAG·Contextual Retrieval·MCP 통합 |
| LLM 평가 | 정량 벤치마크·LLM-as-Judge 편향·골든셋·A/B·에이전트 평가·평가 프레임워크 지형 |
| 문서 | 내용 |
|---|---|
| LLM 구동의 주요 스펙: 메모리 용량과 대역폭 | 대역폭 vs 용량, DRAM 한계, UMA 구조, Apple Silicon·NVIDIA·AMD 전 라인업 |
| 로컬 LLM 실행 생태계 | HuggingFace Hub·Ollama·LM Studio·OpenClaw 개념 소개와 비교 |
| 문서 | 내용 |
|---|---|
| Claude Code 3대 설정 축 | CLAUDE.md · Hooks · Skills 레퍼런스 |
| Codex 사용 가이드 | OpenAI Codex CLI — AGENTS.md · 승인 모드 · MCP 설정 |
| 커밋(Commit)이란 무엇인가 | 버전 관리 기초 — 세이브 포인트 비유, 로컬 커밋 vs 푸시 |
| API 비용 최적화 — 캐싱·배치·모델 라우팅 | 프롬프트 캐싱(read 90% 할인) · 배치 API(50%) · 컨텍스트 변곡점 · thinking 비용 · 7항목 체크리스트 |
| 에이전트 프레임워크 지형도 | LangChain·LangGraph·CrewAI·MS Agent·OpenAI Agents SDK·Claude Agent SDK·MCP 비교와 선택 기준 |
| 문서 | 내용 |
|---|---|
| AI 기술 부채 — 빨라진 생성, 미뤄진 이해 | 기술 부채의 두 갈래(ML 시스템 / AI 생성 코드), 이해·인지 부채, 사람들의 견해 |
| AI 와 일자리 — 합리적 공포와 합리적 회의 | 공포·회의 양측의 합당한 근거, 노동 총량의 오류와 제번스의 역설, 방사선과·ATM·코드 사례, 학계 주요 목소리 |
이 문서는 Claude Code(claude-sonnet-4-6)와 함께 작성했어요.